/* Copyright (C) 1995 Bjoern Beutel. */
/* Description. =============================================================*/
/* This module supports reading and parsing input. */
/* Includes. ================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <glib.h>
#include "basic.h"
#include "files.h"
#include "input.h"
/* Variables. ===============================================================*/
static text_t *text;
/* Functions. ===============================================================*/
void
parse_whitespace( string_t *input )
/* Read whitespace in *INPUT and update *INPUT. */
{
while (g_unichar_isspace( g_utf8_get_char( *input ) ))
*input = g_utf8_next_char( *input );
}
/*---------------------------------------------------------------------------*/
char_t *
parse_word( string_t *input )
/* If there is a word in *INPUT, parse it up to the next space
* and update *INPUT. Return the word. It must be freed after use.
* If there's no word, report an error. */
{
gunichar code;
clear_text( text );
if (**input == EOS)
complain( "Argument expected." );
if (**input == '\"')
{
/* A quoted word may contain spaces and quotes. */
(*input)++;
while (**input != '\"')
{
if (**input == EOS)
complain( "Missing closing '\"'." );
if ((*input)[0] == '\\' && (*input)[1] != EOS)
(*input)++;
add_char_to_text( text, *(*input)++ );
}
(*input)++;
}
else
{
while (**input != EOS)
{
code = g_utf8_get_char( *input );
if (g_unichar_isspace( code ))
break;
add_unichar_to_text( text, code );
*input = g_utf8_next_char( *input );
}
}
parse_whitespace( input );
return new_string( text->buffer, NULL );
}
/*---------------------------------------------------------------------------*/
char_t *
parse_absolute_path( string_t *input, string_t relative_to )
/* Parse the next file name in *INPUT and update *INPUT.
* Make the file name absolute (relative to RELATIVE_TO).
* If there is no file name, report an error. */
{
char_t * path;
char_t *abs_path;
path = parse_word( input );
abs_path = absolute_path( path, relative_to );
free_mem( &path );
return abs_path;
}
/*---------------------------------------------------------------------------*/
void
parse_end( string_t *input )
/* Test if there are no more arguments in *INPUT. */
{
if (**input != EOS)
complain( "Unexpected argument: \"%s\".", *input );
}
/*---------------------------------------------------------------------------*/
int_t
parse_int( string_t *input )
/* Parse the next integer number from *INPUT and update *INPUT.
* If there is no integer, an error is reported. */
{
int_t number;
string_t string;
string = parse_word( input );
if (sscanf( string, "%d", &number ) != 1)
complain( "Illegal integer value." );
free_mem( &string );
return number;
}
/*---------------------------------------------------------------------------*/
int_t
parse_cardinal( string_t *input )
/* Parse the next positive integer number from *INPUT and update *INPUT.
* If there is no integer, an error is reported. */
{
int_t number;
number = parse_int( input );
if (number < 1)
complain( "Number must be positive." );
return number;
}
/*---------------------------------------------------------------------------*/
double
parse_double( string_t *input )
/* Parse the next double from *INPUT and update *INPUT.
* If there is no double, an error is reported. */
{
double number;
string_t string;
string = parse_word( input );
if (sscanf( string, "%lf", &number ) != 1)
complain( "Illegal double value." );
free_mem( &string );
return number;
}
/*---------------------------------------------------------------------------*/
bool_t
parse_yes_no( string_t *input )
/* Parse next word in INPUT. It must be "yes" or "no" (or "on" or "off" for
* compatibility). Return TRUE iff next word is "yes" (or "on"). */
{
string_t argument;
bool_t return_value;
argument = parse_word( input );
if (strcmp_no_case( argument, "yes" ) == 0
|| strcmp_no_case( argument, "on" ) == 0)
{
return_value = TRUE;
}
else if (strcmp_no_case( argument, "no" ) == 0
|| strcmp_no_case( argument, "off" ) == 0)
{
return_value = FALSE;
}
else
complain( "\"yes\" or \"no\" expected, not \"%s\".", argument );
free_mem( &argument );
return return_value;
}
/*---------------------------------------------------------------------------*/
char_t *
read_line( FILE *stream )
/* Read user input from STREAM until eof or newline is met.
* Return the result string (without final EOL or EOF).
* The string must be freed after use.
* If EOF is initially met, return NULL. */
{
int_t c;
/* Read initial char to see if it's end of file. */
c = getc( stream );
if (c == EOF)
return NULL;
/* There is some real result, read it in and return it. */
clear_text( text );
while (c != '\n' && c != EOF)
{
ADD_CHAR_TO_TEXT( text, c );
c = getc( stream );
}
if (! g_utf8_validate( text->buffer, -1, NULL))
complain( "Illegal UTF-8 character." );
return new_string( text->buffer, NULL );
}
/*---------------------------------------------------------------------------*/
void
cut_comment( char_t *line )
/* Cut a "#"-comment in LINE if there is one.
* The char "#" is ignored if it occurs within a double-quoted string. */
{
while (*line != EOS)
{
if (*line == '#')
{
*line = EOS;
return;
}
if (*line == '\"')
{
/* Read over double-quoted string. */
line++;
while (*line != '\"')
{
if (*line == EOS)
return;
if (line[0] == '\\' && line[1] != EOS)
line += 2;
else
line++;
}
line++;
}
else
line++;
}
}
/*---------------------------------------------------------------------------*/
void
init_input( void )
/* Initialise this module. */
{
text = new_text();
}
/*---------------------------------------------------------------------------*/
void
terminate_input( void )
/* Terminate this module. */
{
free_text( &text );
}
/* End of file. =============================================================*/