/*==================================================================== * ------------------------ * | CVS File Information | * ------------------------ * * $RCSfile$ * * $Author$ * * $Date$ * * $Revision$ * Symbolic $Name$ * * $Id$ * $Source$ * *====================================================================*/ #ifndef lint static char const rcsid[] = "$Id$"; #endif #include #include #include #include #include #include #include #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 * --------- -------------- * 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 * --------- -------------- * 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 : * 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 * --------- --------------------------------------- * 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 : * 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 * --------- --------------------------------------- * 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); } /*****************************************************************************/