Files
cantera/tools/testtools/tok_input_util.cpp
2003-04-14 17:57:48 +00:00

1571 lines
56 KiB
C++

/*====================================================================
* ------------------------
* | CVS File Information |
* ------------------------
*
* $RCSfile$
*
* $Author$
*
* $Date$
*
* $Revision$
* Symbolic $Name$
*
* $Id$
* $Source$
*
*====================================================================*/
#ifndef lint
static char const rcsid[] =
"$Id$";
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "tok_input_util.h"
static char DEFAULT_STR[8] = "default";
static char DELIMITERS[8] = " \t\n\f\r\v"; /* Defn of white space in isspace()
- Used in tokenizing lines */
static char COM_CHAR = '!'; /* This is used as a comment character */
static char COM_CHAR2 = '#'; /* This is used as a 2nd comment character */
static char KEY_CHAR = '='; /* This is used to separate the key_string
from the rest of the line */
static int PrintInputFile = TRUE; /* Used to turn on and off the
printing of the input file */
/*************** R O U T I N E S I N T H E F I L E *******************
*
* NAME TYPE CALLED_BY
*--------------------------------------------------------------------
* get_next_keyLine BOOLEAN extern
* tok_to_int int extern
* str_to_int int extern, tok_to_int
* tok_to_double double extern
* str_to_double double extern,tok_to_double
* tok_to_boolean BOOLEAN extern
* str_to_boolean BOOLEAN extern,tok_to_boolean
* tok_to_string char * extern
*
*
* scan_for_int int extern
* scan_for_double double extern
* scan_for_string char * extern
* scan_for_boolean BOOLEAN extern
* scan_for_line int extern
* read_line int scan_for_line,
* get_next_keyLine
* interpret_int static BOOLEAN str_to_int + others
* interpret_boolean static BOOLEAN str_to_boolean
* interpret_double static BOOLEAN str_to_double
* strip int read_input_file,
* look_for,
* get_next_keyLine
* read_string static void scan_for_line
* stokenize int fillTokStruct
* outofbnds static BOOLEAN all
* strmatch BOOLEAN extern, toktokmatch
* strstrmatch BOOLEAN extern
* strtokmatch BOOLEAN extern
* toktokmatch BOOLEAN extern, strtokmatch
* strstrmatch
* fillTokStruct void extern, strtokmatch
* strstrmatch,
* get_next_keyLine
* copyTokStruct void extern
*
******************************************************************************/
/*
* Definitions of static functions:
*/
static BOOLEAN outofbnds(const double, const double, const double );
static BOOLEAN interpret_boolean(const char *, int *, const int);
static BOOLEAN interpret_int (const char *, int *, const int, const int,
const int);
static BOOLEAN interpret_double (const char *, double *, const double,
const double, const double);
/************ Member Functions for the TOKEN Structure ********************/
TOKEN::TOKEN(void) :
orig_str(0),
tok_str(0),
ntokes(0)
{
orig_str = copy_string("");
tok_str = copy_string("");
tok_ptr[0] = orig_str;
}
TOKEN::TOKEN(const char *str) :
orig_str(0),
tok_str(0),
ntokes(0)
{
if (str == NULL) {
orig_str = copy_string("");
tok_str = copy_string("");
tok_ptr[0] = orig_str;
ntokes = 0;
} else {
orig_str = copy_string(str);
tok_str = copy_string(str);
ntokes = stokenize(tok_str, DELIMITERS, tok_ptr, MAXTOKENS);
}
}
TOKEN::~TOKEN()
{
if (orig_str) free(orig_str);
orig_str = NULL;
if (tok_str) free(tok_str);
tok_str = NULL;
}
/**************************************************************************/
BOOLEAN get_next_keyLine(FILE *ifp, TOKEN *keyLineTok, TOKEN *keyArgTok)
/*
* This routine reads the input file to obtain the next line of
* uncommented
* data. The results are returned in two TOKEN structures. keyLineTok
* contains the key Line (everything before the first equals sign).
* keyArgTok contains everything after the equals sign.
* Note - Either keyLineTok or keyArgTok may be the null token
* (but not both)
*
* The definition of a token structure, given in .h file,
* is as follows:
*
* struct TOKEN {
* char orig_str[MAX_INPUT_STR_LN + 1];
* char tok_str[MAX_INPUT_STR_LN + 1];
* char *tok_ptr[MAXTOKENS];
* int ntokes;
* };
* mdp_allo.h
* orig_str Contains the original string, unmodified.
* tok_str Contains a modified version of the string,
* whose positions
* are pointed to by tok_ptr[i] values. It is usually not
* referenced directly.
* tok_ptr[i] Contains the i_th token of the original string. This
* is a stripped character string. 0 <=i <= i-1
* ntokes Number of tokens in the string.
*
*
* Comments are denoted by either '!' or '#'.
* Everything after the comment character on a
* line is stripped first. The comment character can occur
* anywhere in the line.
*
* Arguments to the keyLine are denoted by everything after a
* '=' character on the line.
*
* Example:
* ---------------------------------------------------------------
* ! Jack and Jill went up the hill to fetch a pale of water
* ! Jack by nimble, Jack be swift; Jack jump over the candle stick
*
* The meaning of life is = 36.243 24 136 Not even ! close
* -----------------------------------------------------------------
*
* Then, the routine would return (amongst other things):
* keyLineTok->orig_str = "The meaning of life is"
* keyArgTok->orig_str = "36.243 24 36 Not even"
* keyArgTok->ntokes = 5
* keyArgTok->tok_ptr[0] = "36.243"
* keyArgTok->tok_ptr[1] = "24"
* keyArgTok->tok_ptr[2] = "136"
* keyArgTok->tok_ptr[3] = "Not"
* keyArgTok->tok_ptr[4] = "Even"
*
* The function returns TRUE if there is a next line to process.
* It returns false if an EOF is encountered.
*/
{
int retn_value, i;
char save_input[MAX_INPUT_STR_LN + 1];
char *token_start = NULL;
/*
* Check the arguments to the routine. This routine needs to be
* supplied with valid pointers to files and spaces for storage
* of its output in the return tokens.
*/
if (ifp == NULL || keyLineTok == NULL || keyArgTok == NULL) {
fprintf(stderr, "get_next_keyLine ERROR, arguments are bad\n");
return(FALSE);
}
/*
* Read a chunk of text, either up to a newline from the file pointer,
* ifp. If an EOF occurs, return without changing the input structure
*/
do_it_again:
do {
if ((retn_value = read_string(ifp, save_input, '\n')) < 0) {
return(FALSE);
}
if (PrintInputFile) {
if (retn_value <=0) printf ("%s\n", save_input);
else printf ("%s", save_input);
}
for (i = 0; i < (int) strlen(save_input); i++) {
if (save_input[i] == COM_CHAR || save_input[i] == COM_CHAR2) {
save_input[i] = '\0';
break;
}
}
} while (strip(save_input) == 0);
/*
* Discover whether there are arguments in the line
* and then separate the line into two
*/
for (i = 0; i < (int) strlen(save_input); i++) {
if (save_input[i] == KEY_CHAR) {
save_input[i] = '\0';
token_start = save_input + i + 1;
break;
}
}
/*
* Strip the two strings of leading and trailing white space.
* If both strings are now the null string (because the line
* consisted of a single '=' character for example),
* go back and get a new line.
*/
i = strip(token_start);
if (!strip(save_input)) if (!i) goto do_it_again;
/*
* Now that we have two strings representing the Key String and
* associated arguments, process them into TOKEN structures.
* Note - if token_start still points to NULL, then fillTokStruct
* will fill keyArgTok with a "null token".
*/
fillTokStruct(keyLineTok, save_input);
fillTokStruct(keyArgTok, token_start);
return (TRUE);
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
int tok_to_int(const TOKEN *tokPtr, const int maxVal, const int minVal,
const int defaultVal, BOOLEAN *error)
/*
* Interprets the first string of a TOKEN structure as an int.
* Returns the interpreted value as the return value.
* AnErrors condition is created if more than one token is found
* in the struct TOKEN.
* Bounds checking is done on the value before returning. Value
* must be between the maxVal and minVal; it can equal the max or min
* value.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value (defined in <limits.h>
* --------- --------------
* INT_MAX, max, all INT_MAX
* INT_MIN INT_MIN
* N/A, Not Available INT_MIN
* default or "" defaultVal
*
* A default may be specified on the command line. The absence of a
* default may also be specified by setting devault_value to
* NO_DEFAULT_INT.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
if (tokPtr->ntokes == 0)
return(str_to_int(DEFAULT_STR, maxVal, minVal, defaultVal, error));
else if (tokPtr->ntokes > 1) {
(void) fprintf(stderr, "ERROR: tok_to_int, ntokes > 1: %s\n",
tokPtr->orig_str);
*error = TRUE;
}
return(str_to_int(tokPtr->tok_ptr[0], maxVal, minVal, defaultVal, error));
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
int str_to_int(const char *int_string, const int maxVal, const int minVal,
const int defaultVal, BOOLEAN *error)
/*
* Interprets a stripped character string as an integer.
* Bounds checking is done on the value before returning. Value
* must be between the max and min; it can equal the max or min value.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value (defined in <limits.h>
* --------- --------------
* INT_MAX, max, all INT_MAX
* INT_MIN INT_MIN
* N/A, Not Available INT_MIN
* default default_value
*
* A default may be specified on the command line. The absence of a
* default may also be specified by setting devault_value to
* NO_DEFAULT_INT.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
int retn_value, check = FALSE;
double LmaxVal, LminVal;
if (defaultVal == NO_DEFAULT_INT) check = TRUE;
if (interpret_int(int_string, &retn_value, maxVal, minVal, defaultVal)) {
if (check) {
if (retn_value == NO_DEFAULT_INT) {
(void) fprintf(stderr,
"ERROR: str_to_int: Default not allowed\n");
*error = TRUE;
}
}
if (maxVal < INT_MAX) LmaxVal = (double) maxVal + 0.01;
else LmaxVal = (double) maxVal;
if (minVal > INT_MIN) LminVal = (double) minVal - 0.01;
else LminVal = (double) minVal;
if (outofbnds((double) retn_value, LmaxVal, LminVal)) {
fprintf(stderr,
"ERROR: str_to_int outofbnds:\n\t\"%s\"\n",
int_string);
fprintf(stderr,"\tmax = %d, min = %d\n", maxVal, minVal);
*error = TRUE;
}
} else
*error = TRUE;
return (retn_value);
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
double tok_to_double(const TOKEN * tokPtr, const double maxVal,
const double minVal, const double defaultVal,
BOOLEAN *error)
/*
* Interprets the first string of a TOKEN structure as a double.
* Returns the interpreted value as the return value.
* Errors conditions are created if more than one token is found.
*
* Bounds checking is then done on the value before returning. Value
* must be between the max and min; it can equal the max or min.
*
* Useful values for bounds (specified in <limits.h>:
* DBL_MAX = largest legitimate value of a double ~ 2.0E-308
* -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
* DBL_EPSILON = smallest value of a double that can be added to one
* and produce a different number. ~ 2.0E-16
* DBL_MIN = smallest value of a double ~ 2.0E-308
* For example:
* If 0.0 is not a legitimate number for value, set min = DBL_MIN
* If value>=0.0 is legitimate, set min = 0.0
* if value<=100., set max = 100.
* If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
*
* Certain ascii strings are checked for first (case is insignificant):
*
* Token_String Retn_Value ( specified in <limits.h>
* --------- ---------------------------------------
* FLT_MAX, all FLT_MAX
* DBL_MAX, max DBL_MAX
* N/A -DBL_MAX
* default or "" default_value
* small, DBL_MIN DBL_MIN
* DBL_EPSILON DBL_EPSILON
*
* A default may be specified by either specifying the value as
* "default" or by the absense of any tokens in the TOKEN struct.
* The absence of a default may also be specified by setting the
* value of default_value to NO_DEFAULT_DOUBLE.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
if (tokPtr->ntokes == 0)
return(str_to_double(DEFAULT_STR, maxVal, minVal, defaultVal, error));
else if (tokPtr->ntokes > 1) {
(void) fprintf(stderr, "ERROR: tok_to_double, ntokes > 1: %s\n",
tokPtr->orig_str);
*error = TRUE;
}
return(str_to_double(tokPtr->tok_ptr[0], maxVal, minVal, defaultVal, error));
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
double str_to_double(const char *dbl_string, const double maxVal,
const double minVal, const double defaultVal,
BOOLEAN *error)
/*
* Interprets a stripped character string as a double. Returns the
* interpreted value as the return value.
*
* Bounds checking is then done on the value before returning. Value
* must be between the max and min; it can equal the max or min.
*
* Useful values for bounds (specified in <limits.h>:
* DBL_MAX = largest legitimate value of a double ~ 2.0E-308
* -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
* DBL_EPSILON = smallest value of a double that can be added to one
* and produce a different number. ~ 2.0E-16
* DBL_MIN = smallest value of a double ~ 2.0E-308
* For example:
* If 0.0 is not a legitimate number for value, set min = DBL_MIN
* If value>=0.0 is legitimate, set min = 0.0
* if value<=100., set max = 100.
* If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value ( specified in <limits.h>
* --------- ---------------------------------------
* FLT_MAX, all FLT_MAX
* DBL_MAX, max DBL_MAX
* N/A -DBL_MAX
* default default_value
* small, DBL_MIN DBL_MIN
* DBL_EPSILON DBL_EPSILON
*
* A default may be specified. The absence of a
* default may also be specified by setting the value of default_value
* to NO_DEFAULT_DOUBLE.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
double retn_value;
int check = FALSE;
if (defaultVal == NO_DEFAULT_DOUBLE) check = TRUE;
if (interpret_double(dbl_string, &retn_value, maxVal, minVal, defaultVal)) {
if (check)
if (retn_value == NO_DEFAULT_DOUBLE) {
(void) fprintf(stderr,
"ERROR: keyLine_double: Default not allowed\n");
*error = TRUE;
}
if (outofbnds(retn_value, maxVal, minVal)) {
(void) fprintf(stderr, "ERROR: keyLine_double outofbnds:\n\t\"%s\"\n",
dbl_string);
(void) fprintf(stderr,"\tmax = %e, min = %e\n", maxVal, minVal);
*error = TRUE;
}
} else
*error = TRUE;
return (retn_value);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
BOOLEAN tok_to_boolean(const TOKEN *tokPtr, const int default_value,
BOOLEAN *error)
/*
* Interprets the first string of a TOKEN structure as a BOOLEAN.
* (i.e., TRUE or FALSE). Returns the interpreted value as the
* return value.
* Errors conditions are created if more than one token is found.
*
* The following character strings are interpreted
* (case doesn't matter):
*
* TRUE = "YES", "TRUE", "T", "Y"
* FALSE = "NO, "FALSE", "N", "F"
* default_value = "DEFAULT" or ""
*
* A default may be specified on the command line. The absence of a
* default may also be specified by using the value of NO_DEFAULT_INT.
* If tokPtr contains no tokens, this routine will try to use the
* default value.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
if (tokPtr->ntokes == 0)
return(str_to_boolean(DEFAULT_STR, default_value, error));
else if (tokPtr->ntokes > 1) {
(void) fprintf(stderr, "ERROR: tok_to_boolean, ntokes > 1: %s\n",
tokPtr->orig_str);
*error = TRUE;
}
return(str_to_boolean(tokPtr->tok_ptr[0], default_value, error));
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
BOOLEAN str_to_boolean(const char *string, const int default_value,
BOOLEAN *error)
/*
* Interprets a stripped character string as a BOOLEAN value
* (i.e., TRUE or FALSE). It returns that value as the return value.
*
* The following character strings are interpreted
* (case doesn't matter):
*
* TRUE = "YES", "TRUE", "T", "Y"
* FALSE = "NO, "FALSE", "N", "F"
* default_value = "DEFAULT"
*
* A default may be specified on the command line. The absence of a
* default may also be specified by using the value of NO_DEFAULT_INT.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
int retn_value;
if (interpret_boolean(string, &retn_value, default_value)) {
if (retn_value == NO_DEFAULT_BOOLEAN) {
(void) fprintf(stderr,
"ERROR: keyLine_boolean: Default not allowed\n");
*error = TRUE;
}
} else
*error = TRUE;
return ((BOOLEAN) retn_value);
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
char *tok_to_string(const TOKEN *tokPtr, const int maxTok,
const int minTok, const char *defaultVal, BOOLEAN *error)
/*
* Interprets the arguments in a TOKEN structure as a string.
* It mallocs new space for the string, are returns the pointer to it.
* The number of tokens in the string is checked before returning.
* The value must be between the maxTok and minTok; it can equal the
* max or min value.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* default or "" defaultVal
*
* A default may be specified on the command line. The absence of a
* default may also be specified by setting devault_value to
* NO_DEFAULT_INT.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
char *str;
if (tokPtr->ntokes == 0)
str = str_to_string(DEFAULT_STR, defaultVal, error);
else
str = str_to_string(tokPtr->orig_str, defaultVal, error);
if (outofbnds((double) tokPtr->ntokes, (double) maxTok,
(double) minTok)) {
(void) fprintf(stderr, "ERROR: tok_to_String:\n\t\"%s\"\n",
tokPtr->orig_str);
(void) fprintf(stderr,"\tmaxTok = %d, minTok = %d\n", maxTok, minTok);
*error = TRUE;
}
return (str);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
char *str_to_string(const char *str, const char *defaultVal,
BOOLEAN *error)
/*
* Interprets the argument string as a string.
* It mallocs new space for the string, are returns the pointer to it.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* default defaultVal
*
* A default may be specified on the command line. The absence of a
* default may also be specified by setting devault_value to
* NO_DEFAULT_INT.
*
* If there is an error, *error is set to TRUE. *error isn't touched
* if there isn't an error.
*/
{
if (str == NULL) {
*error = TRUE;
(void) fprintf(stderr,"ERROR str_to_string: str is uninialized\n");
return(NULL);
}
if (strmatch(str, DEFAULT_STR)) {
if (strmatch(defaultVal, NO_DEFAULT_STR)) {
*error = TRUE;
(void) fprintf(stderr,"ERROR str_to_string: no default allowed\n");
return(copy_string(NO_DEFAULT_STR));
} else
return(copy_string(defaultVal));
}
return(copy_string(str));
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
int scan_for_int(FILE *ifp, const char *str, const int maxVal,
const int minVal)
/*
* Scans the file for a line matching string. Then, interprets
* everything after the equals sign as a single integer.
* Bounds checking is done on the value before returning. Value
* must be between the max and min; it can equal the max or min value.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* INT_MAX, max, all INT_MAX
* INT_MIN, default INT_MIN
* N/A, Not Available INT_MIN
*
* Because this is a fixed format input file routine, errors are
* handled by terminally exiting the program.
*/
{
int retn_value, defaultVal = INT_MIN;
char *tok_ptr[2];
char input[MAX_INPUT_STR_LN + 1];
if (scan_for_line(ifp, str, input, KEY_CHAR, PrintInputFile) < 0)
exit(-1);
if (stokenize(input, DELIMITERS, tok_ptr, 2) == 1) {
if (interpret_int(tok_ptr[0], &retn_value,
maxVal, minVal, defaultVal)) {
if (outofbnds((double) retn_value, (double) maxVal,
(double) minVal)) {
fprintf(stderr,
"ERROR: scan_for_int outofbnds:\n\t\"%s\"\n",str);
fprintf(stderr,"\tmax = %d, min = %d\n", maxVal, minVal);
exit(-1);
} else
return(retn_value);
}
}
fprintf(stderr, "ERROR while processing line, \"%s\"\n", str);
exit(-1); /*NOTREACHED*/
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
BOOLEAN scan_for_boolean(FILE *ifp, const char *string)
/*
* Scans the file for a line matching string. Then, interprets
* everything after the equals sign as a single boolean value
*
* Because this is a fixed format input file routine, errors are
* handled by terminally exiting the program.
*/
{
int ret_value;
char *tok_ptr[2];
char input[MAX_INPUT_STR_LN + 1];
if (scan_for_line(ifp, string, input, KEY_CHAR, PrintInputFile) < 0) exit(-1);
if (stokenize(input, DELIMITERS, tok_ptr, 2) == 1) {
if (interpret_boolean(tok_ptr[0], &ret_value, NO_DEFAULT_BOOLEAN)) {
if (ret_value == NO_DEFAULT_BOOLEAN) {
(void) fprintf(stderr, "scan_for_boolean: default not allowed\n");
exit (-1);
}
return((BOOLEAN) ret_value);
}
}
(void) fprintf(stderr, "scan_for_boolean: ERROR on line \"%s\"\n", string);
exit (-1); /*NOTREACHED*/
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
double scan_for_double(FILE *ifp, const char *string, const double maxVal,
const double minVal)
/*
* Scans the file for a line matching string. Then, interprets
* everything after the equals sign as a single floating point number.
* Bounds checking is then done on the value before returning. Value
* must be between the max and min; it can equal the max or min.
*
* Useful values for bounds:
* DBL_MAX = largest legitimate value of a double ~ 2.0E-308
* -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
* DBL_EPSILON = smallest value of a double that can be added to one
* and produce a different number. ~ 2.0E-16
* DBL_MIN = smallest value of a double ~ 2.0E-308
* For example:
* If 0.0 is not a legitimate number for value, set min = DBL_MIN
* If value>=0.0 is legitimate, set min = 0.0
* if value<=100., set max = 100.
* If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* FLT_MAX, all FLT_MAX
* DBL_MAX, max DBL_MAX
* N/A, default -DBL_MAX
* small, DBL_MIN DBL_MIN
* DBL_EPSILON DBL_EPSILON
*
* Because this is a fixed format input file routine, errors are
* handled by terminally exiting the program.
*/
{
double retn_value;
char *tok_ptr[2];
char input[MAX_INPUT_STR_LN + 1];
if (scan_for_line(ifp, string, input, KEY_CHAR, TRUE) < 0) exit(-1);
if (stokenize(input, DELIMITERS, tok_ptr, 2) > 0) {
if (interpret_double(tok_ptr[0], &retn_value, maxVal, minVal,
NO_DEFAULT_DOUBLE)) {
if (retn_value == NO_DEFAULT_DOUBLE) {
(void) fprintf(stderr,
"ERROR: scan_for_double has no default\n");
exit(-1);
}
if (outofbnds(retn_value, maxVal, minVal)) {
(void) fprintf(stderr,
"ERROR: scan_for_double outofbnds:\n \"%s = %e\"\n",
string, retn_value);
(void) fprintf(stderr,"\tmax = %e, min = %e\n", maxVal, minVal);
exit(-1);
} else
return(retn_value);
}
}
(void) fprintf(stderr, "ERROR scan_for_double: \"%s\"\n", string);
exit(-1); /*NOTREACHED*/
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
char *scan_for_string(FILE *ifp, const char *string, const int maxVal,
const int minVal)
/*
* Scans the file for a line matching string. Then, interprets
* everything after the equals sign as string to be returned.
* Storage for the resulting string is malloced, and the address
* of the string is returned.
* The string is returned stripped of leading and trailing white space,
* and of comments.
*
* Length checking is then done on the number of characters returned.
*
* Because this is a fixed format input file routine, errors are
* handled by terminally exiting the program.
*/
{
int len;
char input[MAX_INPUT_STR_LN + 1];
if (scan_for_line(ifp, string, input, KEY_CHAR, PrintInputFile) < 0)
exit(-1);
len = strlen(input);
if (outofbnds((double) len, (double) maxVal, (double) minVal)) {
(void) fprintf(stderr,
"ERROR: scan_for_string string length: \"%s = %s\"\n", string, input);
(void) fprintf(stderr, "\tlength max = %d, min = %d\n", maxVal, minVal);
exit(-1);
}
return (copy_string(input));
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
int scan_for_line(FILE *ifp, const char *str, char input[],
const char ch_term, const int print_flag)
/*
* Scan the input file (reading in strings according to
* 'read_string(ifp,)'
* specifications) until the character pattern in 'string' is matched.
* Returns all of the characters after the termination character in
* a null-character terminated string,
*
* Parameter list:
*
* ifp == pointer to file "input"
* string == contains string pattern to be matched.
* input == buffer array to hold characters that are read in.
* On output, it contains the return character string
* ch_term== Termination character. When scanning a line of input
* is read until either a newline, the 'ch' termination
* character is read, or the end-of-file is read.
*
* Output:
* This function returns the number of characters in the string
* input,
* excluding the null character. Error conditions are currently
* handled by returning with negative return values.
*/
{
int retn_value, i;
BOOLEAN found = FALSE;
char match_string[MAX_INPUT_STR_LN+1],
save_input[MAX_INPUT_STR_LN+1];
static const char *ename = "ERROR scan_for_line: ";
/*
* Error test the input match string
*/
if (strlen(str) > MAX_INPUT_STR_LN) {
fprintf(stderr,"%sMatch string is too long:\n\t%s\n",
ename, str);
return(-1);
}
/*
* Make it an error to have the comment indicator in a
* match string
*/
for (i = 0; i < (int) strlen(str); i++) {
if (str[i] == COM_CHAR || str[i] == COM_CHAR2) {
fprintf(stderr, "%s Comment in match string\n\t%s\n",
ename, str);
return(-1);
}
}
/*
* Strip the string of leading and trailing white space
*/
if ((retn_value = strip(strcpy(match_string, str))) <= 0) {
fprintf(stderr, "%sMatch string is white space: \"%s\"\n",
ename, str);
return(-1);
}
/*
* Start the search for the string
*/
do
{
/*
* Read a chunk of text, either up to a newline or to the
* character ch_term, from the file pointer, ifp.
*/
if ((retn_value = read_string(ifp, save_input, ch_term)) < 0) {
fprintf (stderr,
"%sEOF found in input file while searching for:\n", ename);
fprintf (stderr, "\t\"%s\"\n", match_string);
return(retn_value);
}
/*
* copy the string just read to the output string, and the
* strip it of leading and trailing white space, and comments.
* Then, compare the stripped input string with the stripped
* match_string
*/
strcpy(input, save_input);
if (strip(input) > 0)
found = strmatch(input, match_string);
/*
* If requested print the line, including comments, on standard output.
* Use the retn_value from read_string to test whether a \n needs to
* be written.
*/
if (print_flag) {
if (found) printf ("->\t");
if (retn_value == 0)
printf("%s\n", save_input);
else
printf("%s%c", save_input, ch_term);
}
/*
* Read and print the rest of the line, if we are in the middle of it.
*/
if (retn_value > 0) {
if ((retn_value = read_line(ifp, input, print_flag)) < 0) {
fprintf(stderr,
"ERROR, EOF found in input file while reading line:\n");
fprintf(stderr, "%s %c\n", str, ch_term);
return(retn_value);
}
}
else
input[0] = '\0';
} while (!found);
return (retn_value);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
int read_line(FILE *ifp, char input[], const int print_flag)
/*
* read_line:
*
* Reads a line of input. The line is
* printed to standard output, if print_flag is true.
* The line is returned in the character
* string pointed to by input. Leading and trailing white spaces are
* stripped from the line.
* The number of characters, excluding the null character, is
* returned, except when read_string encounters an error condition
* (negative return values). Then, the error condition is returned.
*/
{
int retn_value;
/*
* read the file up to the next new line, read_string will return
* a 0 for a success, and a negative value for failure
*/
retn_value = read_string(ifp, input, '\n');
/*
* Print out the line before stripping it of comments and white space
*/
if (print_flag) printf ("%s\n", input);
/*
* Strip the return line of comments and leading/trailing white space
* Use the function strip to return the number of characters remaining
*/
if (retn_value == 0) return (strip(input));
/*
* If an error condition occurred in read_string, return the error
* condition value instead of the character count
*/
(void) strip(input);
return (retn_value);
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
int read_string(FILE *ifp, char string[], const char ch)
/*
* This routine reads the standard input until encountering
* the end-of-file, a newline, the character 'ch' or until
* MAX_INPUT_STR_LN characters are read. The inputted characters
* are read into 'string'.
* If an EOF occurs, -1 is returned.
* If a line is longer than MAX_INPUT_STR_LN, a -2 is returned
* and an error message is written to standard error.
* string[] will be returned null-terminated with the
* first MAX_INPUT_STR_LN of the line.
* Upon successful completion with the read terminated by the
* character 'ch', the number of characters read plus 1 for the
* null character at the end of the string is returned. If the
* read is terminated by '\n', a 0 is returned, even if ch = '\n'
*
*
* Parameter list:
*
* ifp == pointer to file "input"
* string == On output, 'string' contains the characters read
* from the input stream. However, the termination character
* or the newline character is not included
* ch == Additional Termination character. That is, input function
* stops when 'ch' or '\n' is read.
*/
{
int i = 0, rtn_value, new_ch;
/*
* Read from the file, until termination conditions occur
* The order in the while statement is important.
*/
while( (i < MAX_INPUT_STR_LN )
&& ((new_ch = getc(ifp)) != ch )
&& ( new_ch != '\n')
&& ( new_ch != EOF )) string[i++] = new_ch;
/*
* Check for termination conditions
*/
if (new_ch == EOF) {
rtn_value = -1;
}
else if (i == MAX_INPUT_STR_LN) {
fprintf(stderr,
"read_string ERROR: Maxed line character count, %d,"
" before finding (%c)\n", MAX_INPUT_STR_LN, ch);
rtn_value = -2;
}
else if (new_ch == '\n')
rtn_value = 0;
else
rtn_value = i + 1;
/*
* Make sure the string is null terminated and return
*/
string[i] = '\0';
return (rtn_value);
}
/**************************************************************************/
static BOOLEAN interpret_boolean(const char *token, int *ret_value,
const int default_value)
/*
* This routine interprets a string token to be either true or false
* and then returns the appropriate answer as an int value in the
* variable ret_value. It is int because the default value may not
* be only 0 or 1
*/
{
/* lower_case (token); */
if (token[0] == '\0')
*ret_value = default_value;
else if (strlen(token) == 1) {
switch (token[0]) {
case 't':
case 'y':
*ret_value = TRUE; break;
case 'f':
case 'n':
*ret_value = FALSE; break;
default:
return (FALSE);
}
} else {
if (strmatch(token,"true") || strmatch(token,"yes"))
*ret_value = TRUE;
else if (strmatch(token,"false") || strmatch(token,"no"))
*ret_value = FALSE;
else if (strmatch(token,DEFAULT_STR) == 0) {
*ret_value = default_value;
} else {
return (FALSE);
}
}
return (TRUE);
}
/**************************************************************************/
static BOOLEAN interpret_int(const char *token, int *retn_value,
const int maxVal, const int minVal,
const int defaultVal)
/*
* This routine interprets a string token to be an integer
* and then returns the appropriate answer as an int value in the
* variable ret_value.
* Errors are indicated by returning FALSE. Success is indicated
* by returning TRUE.
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* INT_MAX, all INT_MAX
* INT_MIN INT_MIN
* max maxVal
* min minVal
* default defaultVal
* NULL string defaultVal
* N/A, Not_Available INT_MIN
*/
{
int retn;
/*
* Allow a few key ascii phrases in place of an actual int
*/
/* lower_case(token); */
if (token[0] == '\0')
*retn_value = defaultVal;
else if ((strmatch(token,"all")) || strmatch(token,"int_max") )
*retn_value = INT_MAX;
else if (strmatch(token,"int_min"))
*retn_value = INT_MIN;
else if (strmatch(token,"max"))
*retn_value = maxVal;
else if (strmatch(token,"min"))
*retn_value = minVal;
else if (strmatch(token,DEFAULT_STR))
*retn_value = defaultVal;
else if (strmatch(token,"n/a") || strmatch(token,"not_available"))
*retn_value = INT_MIN;
else {
if ((retn = sscanf(token, "%d", retn_value)) != 1) {
*retn_value = retn;
return (FALSE);
}
}
return (TRUE);
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
static BOOLEAN interpret_double(const char *token, double *retn_value,
const double maxVal, const double minVal,
const double defaultVal)
/*
* This routine interprets a string token to be a double
* and then returns the appropriate answer as a double value in the
* variable retn_value.
* The function itself returns TRUE if successful or FALSE if unsuccessful
*
*
* Certain ascii strings are checked for first (case is insignificant):
*
* String Retn_Value
* --------- --------------
* FLT_MAX, all FLT_MAX
* FLT_MIN FLT_MIN
* DBL_MAX DBL_MAX
* max maxVal
* min minVal
* default defaultVal
* NULL string defaultVal
* N/A -DBL_MAX
* small, DBL_MIN DBL_MIN
* DBL_EPSILON DBL_EPSILON
*
* DBL_MAX = largest legitimate value of a double ~ 2.0E-308
* -DBL_MAX = smallest legitimate value of a double ~ - 2.0E-308
* DBL_EPSILON = smallest value of a double that can be added to one
* and produce a different number. ~ 2.0E-16
* DBL_MIN = tiniest value of a double ~ 2.0E-308
*/
{
int retn;
float retn_float;
/*
* Allow a few key ascii phrases in place of an actual float
*/
/* lower_case(token); */
if (token[0] == '\0')
*retn_value = defaultVal;
else if ((strmatch(token,"all")) || strmatch(token,"flt_max"))
*retn_value = FLT_MAX;
else if (strmatch(token,"flt_min"))
*retn_value = FLT_MIN;
else if (strmatch(token,"dbl_max"))
*retn_value = DBL_MAX;
else if (strmatch(token,"max"))
*retn_value = maxVal;
else if (strmatch(token,"min"))
*retn_value = minVal;
else if (strmatch(token,"n/a"))
*retn_value = -DBL_MAX;
else if (strmatch(token, DEFAULT_STR))
*retn_value = defaultVal;
else if (strmatch(token,"small") || strmatch(token,"dbl_min"))
*retn_value = DBL_MIN;
else if (strmatch(token,"dbl_epsilon"))
*retn_value = DBL_EPSILON;
else {
if ((retn = sscanf(token, "%e", &retn_float)) != 1) {
*retn_value = (double) retn;
return (FALSE);
} else
*retn_value = (double) retn_float;
}
return(TRUE);
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
int strip(char str[])
/*
* This routine strips off blanks and tabs (only leading and trailing
* characters) in 'str'. On return, it returns the number of
* characters still included in the string (excluding the null character).
*
* Comments are excluded -> All instances of the comment character, '!',
* are replaced by '\0' thereby terminating
* the string
*
* Parameter list:
*
* str == On output 'str' contains the same characters as on
* input except the leading and trailing white space and
* comments have been removed.
*/
{
int i = 0, j = 0;
char ch;
/*
* Quick Returns
*/
if ((str == NULL) || (str[0] == '\0')) return (0);
/* Find first non-space character character */
while(((ch = str[i]) != '\0') && isspace(ch)) i++;
/*
* Move real part of str to the front by copying the string
* - Comments are handled here, by terminating the copy at the
* first comment indicator, and inserting the null character at
* that point.
*/
while ( (ch = str[j+i]) != '\0' &&
(ch != COM_CHAR) &&
(ch != COM_CHAR2) ) {
str[j] = ch;
j++;
}
str[j] = '\0';
j--;
/* Remove trailing white space by inserting a null character */
while( (j != -1 ) && isspace(str[j])) j--;
j++;
str[j] = '\0';
return (j);
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
void lower_case(char str[])
/*
* lower_case:
* Translates a string delimited by a NULL character
* to lower case. There is no error checking in this version.
* Relies on stlib function, tolower.
*/
{
int i;
for (i = 0; i < (int) strlen(str); i++) {
# if defined(_INCLUDE_XOPEN_SOURCE) && ! defined(__lint)
str[i] = _tolower((str[i]));
# else
str[i] = tolower(str[i]);
# endif
}
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
char *TokToStrng (const TOKEN *keyptr)
/*
* TokToStrng:
* Mallocs a new character string and copies
* the tokens character string to it, appending all tokens together
* into a single string separated by a single space character.
* It returns the pointer to the new string;
* The new string should be freed when no longer needed.
*/
{
int i;
if (!keyptr) return NULL;
if (!keyptr->orig_str) return NULL;
int iln = strlen(keyptr->orig_str) + 1 + keyptr->ntokes;
char *fstr = (char *) malloc(iln * sizeof(char));
char *const*str = &(keyptr->tok_ptr[0]);
for (i = 0, fstr[0]= '\0'; i < (keyptr->ntokes - 1); i++, str++) {
(void) strcat(strcat(fstr, *str), " ");
}
return(strcat(fstr, *str));
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
int stokenize(char *string, const char *delimiters, char *tok_ptr[],
const int max_tokens)
/*
* stokenize
*
* This function will break up a string into its respective "tokens".
* It returns the number of tokens found. See the strtok(3) man page.
*
* input
* ----------
* string - String to be tokenized. Note, that the string is
* changed by this procedure. Null characters are
* put between each symbol.
* delimiters - String containing a list of delimiters.
* The example below covers 'white space'
* e.g., char *delimiters = " \t\n";
* max_tokens - Maximum number of tokens to be found
*
* output
* -----------
* tok_ptr - Vector of pointers to strings, that contain the input
* string's tokens
*/
{
int i = 0;
if (string == NULL) {
tok_ptr[0] = NULL;
return 0;
}
if (strlen(string) == 0) {
tok_ptr[0] = string;
return 0;
}
if ( (tok_ptr[0] = strtok(string, delimiters)) != NULL) {
do {
if ( (++i) == max_tokens) break;
} while ( (tok_ptr[i] = strtok(NULL, delimiters)) != NULL);
}
return (i);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
static BOOLEAN outofbnds(const double value, const double maxVal,
const double minVal)
/*
* This routine checks the bounds of a single double value.
* If it is inside or on the bounds, it returns false.
* If it is outside the bounds, it returns true.
*/
{
if ((value <= maxVal) && (value >= minVal)) return (FALSE);
return(TRUE);
}
/******************************************************************************
*
* strmatch():
*
* This routine checks whether one string is the same as another.
* Upper case is transformed into lower case before the comparison is done.
* Thus, case doesn't matter in the comparison. However, white space
* does matter in this comparison.
* If they are, it returns true
* If they aren't, it returns false
*/
BOOLEAN strmatch(const char *s1, const char *s2)
{
while (*s1 != '\0') {
# if defined (_INCLUDE_XOPEN_SOURCE) && ! defined(__lint)
if (_tolower((*s1++)) != _tolower((*s2++))) return (FALSE);
# else
if (tolower(*s1) != tolower(*s2)) return (FALSE);
s1++; s2++;
# endif
}
if (*s2 != '\0') return (FALSE);
return (TRUE);
}
/*****************************************************************************
*
* strstrmatch():
*
* This routine checks whether two strings are the same modulo differences
* in their white space
*/
BOOLEAN strstrmatch(const char *s1, const char*s2)
{
struct TOKEN tmpKeyStruct1, tmpKeyStruct2;
fillTokStruct(&tmpKeyStruct1, s1);
fillTokStruct(&tmpKeyStruct2, s2);
return (toktokmatch(&tmpKeyStruct2, &tmpKeyStruct1));
}
/*******************************************************************************
*
* strtokmatch():
*
* This routine checks whether a string matches the string contained in
* the tokens of a keyLineStr.
* White space and case are ignored.
* If they are, it returns true
* If they aren't, it returns false
*/
BOOLEAN strtokmatch(const TOKEN *keyptr, const char*s2)
{
struct TOKEN tmpKeyStruct;
fillTokStruct(&tmpKeyStruct, s2);
return (toktokmatch(keyptr, &tmpKeyStruct));
}
/**************************************************************************
*
* toktokmatch()
*
* This routine checks whether two TOKEN structures contain the
* same data up to differences in white space.
* Case is ignored as well, as strmatch is called.
*/
BOOLEAN toktokmatch(const TOKEN *keyptr1, const TOKEN *keyptr2)
{
int i = keyptr1->ntokes;
if (i != keyptr2->ntokes) return FALSE;
while (i > 0) {
i--;
if (!strmatch(keyptr1->tok_ptr[i], keyptr2->tok_ptr[i])) return FALSE;
}
return TRUE;
}
/**************************************************************************/
/*
* fillTokStruct()
*
* Fill in a keyLineStruct with a string. Use the defn of white space
* at the start of the file to tokenize the string, storring it in the
* TOKEN structure.
*/
void fillTokStruct(TOKEN *keyptr1, const char *s2)
{
if (keyptr1 == NULL) return;
if (keyptr1->orig_str) free(keyptr1->orig_str);
if (keyptr1->tok_str) free(keyptr1->tok_str);
if (s2 == NULL) {
keyptr1->orig_str = copy_string("");
keyptr1->tok_str = copy_string("");
keyptr1->ntokes = 0;
keyptr1->tok_ptr[0] = keyptr1->orig_str;
return;
}
keyptr1->orig_str = copy_string(s2);
keyptr1->tok_str = copy_string(s2);
keyptr1->ntokes = stokenize(keyptr1->tok_str, DELIMITERS, keyptr1->tok_ptr,
MAXTOKENS);
}
/******************************************************************************
*
* copyTokStruct():
*
* Copies the information stored in keyptr2 into keyptr1
*/
void copyTokStruct(TOKEN *keyptr1, const TOKEN *keyptr2)
{
if (keyptr1 == NULL) return;
if (keyptr2 == NULL) return;
if (keyptr1->orig_str) free(keyptr1->orig_str);
if (keyptr1->tok_str) free(keyptr1->tok_str);
if (keyptr2->orig_str == NULL) {
keyptr1->orig_str = copy_string("");
keyptr1->tok_str = copy_string("");
keyptr1->ntokes = 0;
keyptr1->tok_ptr[0] = keyptr1->orig_str;
return;
}
keyptr1->orig_str = copy_string(keyptr2->orig_str);
keyptr1->tok_str = copy_string(keyptr2->orig_str);
keyptr1->ntokes = stokenize(keyptr1->tok_str, DELIMITERS, keyptr1->tok_ptr,
MAXTOKENS);
}
/******************************************************************************
*
* in_char_list():
*
* Finds a match of one string against a list of strings. Returns
* the position that the first match occurred.
* If no match occurred, returns -1.
* The comparisons ignore differences in white space.
*/
int in_char_list(const char * const str1, const char ** const list,
int num_list)
{
int i;
for (i = 0; i < num_list; i++) if (strstrmatch(str1, list[i])) return(i);
return (-1);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
char *copy_string(const char *string)
/*
* copy_string:
* Mallocs a new character string and copies the old string to it
*
* NOTE: Memory leak may result if the calling program doesn't free
* the malloced space
*/
{
char *new_string;
new_string = (char *) malloc(strlen(string)+1);
if (new_string == NULL) {
(void) fprintf(stderr, "copy_string ERROR: malloc returned NULL");
} else {
(void) strcpy(new_string, string);
}
return (new_string);
}
/******************************************************************************
*
* strip_item_from_token ():
*
* Change the token by taking eliminating the iword'th token from the token
* structure and reformulating the token expression
*/
void strip_item_from_token(int iword, TOKEN *tok)
{
if (!tok) return;
if (iword < 0 || iword > tok->ntokes) return;
int ioffset = tok->tok_ptr[iword] - tok->tok_str;
int ilength = strlen(tok->tok_ptr[iword]);
int i = ioffset;
int j = ioffset + ilength;
if (j <= (int) strlen(tok->orig_str)) {
while(tok->orig_str[j] != '\0') {
tok->orig_str[i] = tok->orig_str[j];
i++;
j++;
}
tok->orig_str[i] = '\0';
}
strcpy(tok->tok_str, tok->orig_str);
tok->ntokes = stokenize(tok->tok_str, DELIMITERS, tok->tok_ptr,
MAXTOKENS);
}
/*****************************************************************************/