/*
 *----------------------------------------------------------------------
 *
 * PROGRAM	: gksmc
 *
 * FILE		: AEutils.c
 *
 * CONTENTS	: Utility routines to read from an Annex E format metafile,
 *		  such as integers, reals, strings etc.
 *
 * GLOBALS USED : int_field_width, real_field_width, real_rep,
 *
 * DATE		: 26th April 1988
 *
 *----------------------------------------------------------------------
 */
#include <stdio.h>
#include "defns.h"

extern int int_field_width;
extern int real_field_width;
extern int real_rep;


/*
 *-------------------------------------------------------------------------
 * read_string:
 *	Reads a specified number of characters from the input file and
 * stores them in the string given. All reading from the input file is
 * done via this routine, to allow characters such as newline to be
 * handled consistently. Eg newline can be ignored in an Annexe E metafile.
 * Reading from the metafile can be done this way since the number of
 * characters to be read for each type of data is known beforehand - the
 * field widths are contained in the metafile header.
 *-------------------------------------------------------------------------
 */
read_string(infile, string, length)
	FILE   *infile;
	char   *string;
	int     length;
{
	int     i = 0,
	        ch;

	while (i < length && (ch = getc(infile)) != EOF)
		if (ch != '\n')
			string[i++] = ch;
	if (ch == EOF)
		write_error(DEFAULT);
	string[i] = '\0';
}


/*
 *-------------------------------------------------------------------------
 * read_string_int:
 *	Calls read_string to read in a string of the specified length,
 * then stores the integer value the string represents in the integer
 * variable referenced.
 *-------------------------------------------------------------------------
 */
read_string_int(infile, int_var_ptr, width)
	FILE   *infile;
	int    *int_var_ptr;
	int     width;
{
	char   *num;

	if (width == DEFAULT)
		width = int_field_width;
	num = (char *) calloc(width + 1, sizeof(char));
	read_string(infile, num, width);
	if (!legal_int_string(num))
		write_error(23);
	*int_var_ptr = atoi(num);
	cfree(num);
}


/*
 *-------------------------------------------------------------------------
 * legal_int_string:
 *	Takes a string pointer and returns 1 (TRUE) if the string
 * referenced represents a legal integer, 0 (FALSE) if not.
 *-------------------------------------------------------------------------
 */
legal_int_string(str)
	char   *str;
{
	int     i = 0,
	        legal = TRUE;

	while (str[i] == ' ')	/* read off any leading spaces */
		i++;
	if (str[i] == '-' || str[i] == '+')	/* single unary operator ok */
		i++;
	while (str[i] != '\0' && legal)
	{	/* should only be digits left */
		if (str[i] < '0' || str[i] > '9')
			legal = FALSE;
		i++;
	}
	return (legal);
}


/*
 *-------------------------------------------------------------------------
 * read_string_real:
 *	The real number representation (reals as integer or real values)
 * is checked. If integer format then read_string_int is called, otherwise
 * a string is read in and interpreted as a floating point number, the
 * value stored in the double float variable referenced.
 *-------------------------------------------------------------------------
 */
read_string_real(infile, real_var_ptr, width)
	FILE   *infile;
	double *real_var_ptr;
	int     width;
{
	char   *num;
	double  atof();
	int     int_var;

	if (real_rep == REAL_AS_INT)
	{
		read_string_int(infile, &int_var, DEFAULT);
		*real_var_ptr = (double) int_var;
	}
	else
	{
		if (width == DEFAULT)
			width = real_field_width;
		num = (char *) calloc(width + 1, sizeof(char));
		read_string(infile, num, width);
		if (!legal_real_string(num))
			write_error(24);
		*real_var_ptr = atof(num);
		cfree(num);
	}
}


/*
 *-------------------------------------------------------------------------
 * legal_real_string:
 *	Takes a string pointer and returns 1 (TRUE) if the string
 * referenced represents a legal real, 0 (FALSE) if not.
 *-------------------------------------------------------------------------
 */
legal_real_string(str)
	char   *str;
{
	int     i = 0,
	        legal = TRUE;

	while (str[i] == ' ')	/* read off any leading spaces */
		i++;
	if (str[i] == '-' || str[i] == '+')	/* single unary operator ok */
		i++;
	while (str[i] != '\0' && str[i] != '.' && legal)
	{	/* digits before . */
		if (str[i] < '0' || str[i] > '9')
			legal = FALSE;
		i++;
	}
	if (str[i] == '.')	/* single decimal point ok */
		i++;
	while (str[i] != '\0' && str[i] != '.' && legal)
	{	/* digits after . */
		if (str[i] < '0' || str[i] > '9')
			legal = FALSE;
		i++;
	}
	return (legal);
}


/*
 *-------------------------------------------------------------------------
 * read_point:
 *	Reads in an x value then a y value and stores them in the Point
 * structure referenced.
 *-------------------------------------------------------------------------
 */
read_point(infile, point)
	FILE   *infile;
	Point  *point;
{
	read_string_real(infile, &point->x, DEFAULT);
	read_string_real(infile, &point->y, DEFAULT);
}


/*
 *-------------------------------------------------------------------------
 * read_int_list:
 *	Uses read_string_int to read in the specified number of integer
 * values and stores them in the list given
 *-------------------------------------------------------------------------
 */
read_int_list(infile, list, num_ints)
	FILE   *infile;
	int    *list,
	        num_ints;
{
	while (num_ints--)
		read_string_int(infile, list++, DEFAULT);
}


/*
 *-------------------------------------------------------------------------
 * read_real_list:
 *	Uses read_string_real to read in the specified number of real
 * values and stores them in the list given
 *-------------------------------------------------------------------------
 */
read_real_list(infile, list, num_reals)
	FILE   *infile;
	double *list;
	int     num_reals;
{
	while (num_reals--)
		read_string_real(infile, list++, DEFAULT);
}


/*
 *-------------------------------------------------------------------------
 * read_point_list:
 *	Uses read_point to read in the specified number of points and
 * stores them in the list given
 *-------------------------------------------------------------------------
 */
read_point_list(infile, pt_list, num_pts)
	FILE   *infile;
	Point  *pt_list;
	int     num_pts;
{
	while (num_pts--)
		read_point(infile, pt_list++);
}
