Cantera  2.0
tok_input_util.cpp
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5 #include <float.h>
6 #include <limits.h>
7 #include <ctype.h>
8 
9 #include "tok_input_util.h"
10 
11 static char DEFAULT_STR[8] = "default";
12 static char DELIMITERS[8] = " \t\n\f\r\v"; /* Defn of white space in isspace()
13  - Used in tokenizing lines */
14 static char COM_CHAR = '!'; /* This is used as a comment character */
15 static char COM_CHAR2 = '#'; /* This is used as a 2nd comment character */
16 static char KEY_CHAR = '='; /* This is used to separate the key_string
17  from the rest of the line */
18 static int PrintInputFile = true; /* Used to turn on and off the
19  printing of the input file */
20 
21 /*************** R O U T I N E S I N T H E F I L E *******************
22 *
23 * NAME TYPE CALLED_BY
24 *--------------------------------------------------------------------
25 * get_next_keyLine bool extern
26 * tok_to_int int extern
27 * str_to_int int extern, tok_to_int
28 * tok_to_double double extern
29 * str_to_double double extern,tok_to_double
30 * tok_to_boolean bool extern
31 * str_to_boolean bool extern,tok_to_boolean
32 * tok_to_string char * extern
33 *
34 * scan_for_int int extern
35 * scan_for_double double extern
36 * scan_for_string char * extern
37 * scan_for_boolean bool extern
38 * scan_for_line int extern
39 * read_line int scan_for_line,
40 * get_next_keyLine
41 * interpret_int static bool str_to_int + others
42 * interpret_boolean static bool str_to_boolean
43 * interpret_double static bool str_to_double
44 * strip int read_input_file,
45 * look_for,
46 * get_next_keyLine
47 * read_string static void scan_for_line
48 * stokenize int fillTokStruct
49 * outofbnds static bool all
50 * strmatch bool extern, toktokmatch
51 * strstrmatch bool extern
52 * strtokmatch bool extern
53 * toktokmatch bool extern, strtokmatch
54 * strstrmatch
55 * fillTokStruct void extern, strtokmatch
56 * strstrmatch,
57 * get_next_keyLine
58 * copyTokStruct void extern
59 *
60 ******************************************************************************/
61 /*
62 * Definitions of static functions:
63 */
64 
65 static bool outofbnds(const double, const double, const double);
66 static bool interpret_boolean(const char*, int*, const int);
67 static bool interpret_int(const char*, int*, const int, const int,
68  const int);
69 static bool interpret_double(const char*, double*, const double,
70  const double, const double);
71 
72 
73 /************ Member Functions for the TOKEN Structure ********************/
74 
75 TOKEN::TOKEN(void) :
76  orig_str(0),
77  tok_str(0),
78  ntokes(0)
79 {
80  orig_str = copy_string("");
81  tok_str = copy_string("");
82  tok_ptr[0] = orig_str;
83 }
84 
85 
86 TOKEN::TOKEN(const char* str) :
87  orig_str(0),
88  tok_str(0),
89  ntokes(0)
90 {
91  if (str == NULL) {
92  orig_str = copy_string("");
93  tok_str = copy_string("");
94  tok_ptr[0] = orig_str;
95  ntokes = 0;
96  } else {
97  orig_str = copy_string(str);
98  tok_str = copy_string(str);
99  ntokes = stokenize(tok_str, DELIMITERS, tok_ptr, MAXTOKENS);
100  }
101 }
102 
103 TOKEN::~TOKEN()
104 {
105  if (orig_str) {
106  free(orig_str);
107  }
108  orig_str = NULL;
109  if (tok_str) {
110  free(tok_str);
111  }
112  tok_str = NULL;
113 }
114 
115 /**************************************************************************/
116 
117 bool get_next_keyLine(FILE* ifp, TOKEN* keyLineTok, TOKEN* keyArgTok)
118 /*
119  * This routine reads the input file to obtain the next line of
120  * uncommented
121  * data. The results are returned in two TOKEN structures. keyLineTok
122  * contains the key Line (everything before the first equals sign).
123  * keyArgTok contains everything after the equals sign.
124  * Note - Either keyLineTok or keyArgTok may be the null token
125  * (but not both)
126  *
127  * The definition of a token structure, given in .h file,
128  * is as follows:
129  *
130  * struct TOKEN {
131  * char orig_str[MAX_INPUT_STR_LN + 1];
132  * char tok_str[MAX_INPUT_STR_LN + 1];
133  * char *tok_ptr[MAXTOKENS];
134  * int ntokes;
135  * };
136  * mdp_allo.h
137  * orig_str Contains the original string, unmodified.
138  * tok_str Contains a modified version of the string,
139  * whose positions
140  * are pointed to by tok_ptr[i] values. It is usually not
141  * referenced directly.
142  * tok_ptr[i] Contains the i_th token of the original string. This
143  * is a stripped character string. 0 <=i <= i-1
144  * ntokes Number of tokens in the string.
145  *
146  *
147  * Comments are denoted by either '!' or '#'.
148  * Everything after the comment character on a
149  * line is stripped first. The comment character can occur
150  * anywhere in the line.
151  *
152  * Arguments to the keyLine are denoted by everything after a
153  * '=' character on the line.
154  *
155  * Example:
156  * ---------------------------------------------------------------
157  * ! Jack and Jill went up the hill to fetch a pale of water
158  * ! Jack by nimble, Jack be swift; Jack jump over the candle stick
159  *
160  * The meaning of life is = 36.243 24 136 Not even ! close
161  * -----------------------------------------------------------------
162  *
163  * Then, the routine would return (amongst other things):
164  * keyLineTok->orig_str = "The meaning of life is"
165  * keyArgTok->orig_str = "36.243 24 36 Not even"
166  * keyArgTok->ntokes = 5
167  * keyArgTok->tok_ptr[0] = "36.243"
168  * keyArgTok->tok_ptr[1] = "24"
169  * keyArgTok->tok_ptr[2] = "136"
170  * keyArgTok->tok_ptr[3] = "Not"
171  * keyArgTok->tok_ptr[4] = "Even"
172  *
173  * The function returns true if there is a next line to process.
174  * It returns false if an EOF is encountered.
175  */
176 {
177  int retn_value, i;
178  char save_input[MAX_INPUT_STR_LN + 1];
179  char* token_start = NULL;
180 
181  /*
182  * Check the arguments to the routine. This routine needs to be
183  * supplied with valid pointers to files and spaces for storage
184  * of its output in the return tokens.
185  */
186  if (ifp == NULL || keyLineTok == NULL || keyArgTok == NULL) {
187  fprintf(stderr, "get_next_keyLine ERROR, arguments are bad\n");
188  return(false);
189  }
190 
191  /*
192  * Read a chunk of text, either up to a newline from the file pointer,
193  * ifp. If an EOF occurs, return without changing the input structure
194  */
195 do_it_again:
196  do {
197  if ((retn_value = read_string(ifp, save_input, '\n')) < 0) {
198  return(false);
199  }
200  if (PrintInputFile) {
201  if (retn_value <=0) {
202  printf("%s\n", save_input);
203  } else {
204  printf("%s", save_input);
205  }
206  }
207  for (i = 0; i < (int) strlen(save_input); i++) {
208  if (save_input[i] == COM_CHAR || save_input[i] == COM_CHAR2) {
209  save_input[i] = '\0';
210  break;
211  }
212  }
213  } while (strip(save_input) == 0);
214 
215  /*
216  * Discover whether there are arguments in the line
217  * and then separate the line into two
218  */
219 
220  for (i = 0; i < (int) strlen(save_input); i++) {
221  if (save_input[i] == KEY_CHAR) {
222  save_input[i] = '\0';
223  token_start = save_input + i + 1;
224  break;
225  }
226  }
227 
228  /*
229  * Strip the two strings of leading and trailing white space.
230  * If both strings are now the null string (because the line
231  * consisted of a single '=' character for example),
232  * go back and get a new line.
233  */
234 
235  i = strip(token_start);
236  if (!strip(save_input)) if (!i) {
237  goto do_it_again;
238  }
239 
240  /*
241  * Now that we have two strings representing the Key String and
242  * associated arguments, process them into TOKEN structures.
243  * Note - if token_start still points to NULL, then fillTokStruct
244  * will fill keyArgTok with a "null token".
245  */
246 
247  fillTokStruct(keyLineTok, save_input);
248  fillTokStruct(keyArgTok, token_start);
249  return (true);
250 }
251 /**************************************************************************/
252 /**************************************************************************/
253 /**************************************************************************/
254 
255 int tok_to_int(const TOKEN* tokPtr, const int maxVal, const int minVal,
256  const int defaultVal, bool* error)
257 /*
258  * Interprets the first string of a TOKEN structure as an int.
259  * Returns the interpreted value as the return value.
260  * AnErrors condition is created if more than one token is found
261  * in the struct TOKEN.
262  * Bounds checking is done on the value before returning. Value
263  * must be between the maxVal and minVal; it can equal the max or min
264  * value.
265  *
266  * Certain ascii strings are checked for first (case is insignificant):
267  *
268  * String Retn_Value (defined in <limits.h>
269  * --------- --------------
270  * INT_MAX, max, all INT_MAX
271  * INT_MIN INT_MIN
272  * N/A, Not Available INT_MIN
273  * default or "" defaultVal
274  *
275  * A default may be specified on the command line. The absence of a
276  * default may also be specified by setting default_value to
277  * NO_DEFAULT_INT.
278  *
279  * If there is an error, *error is set to true. *error isn't touched
280  * if there isn't an error.
281  */
282 {
283  if (tokPtr->ntokes == 0) {
284  return(str_to_int(DEFAULT_STR, maxVal, minVal, defaultVal, error));
285  } else if (tokPtr->ntokes > 1) {
286  (void) fprintf(stderr, "ERROR: tok_to_int, ntokes > 1: %s\n",
287  tokPtr->orig_str);
288  *error = true;
289  }
290  return(str_to_int(tokPtr->tok_ptr[0], maxVal, minVal, defaultVal, error));
291 }
292 /**************************************************************************/
293 /**************************************************************************/
294 /**************************************************************************/
295 
296 int str_to_int(const char* int_string, const int maxVal, const int minVal,
297  const int defaultVal, bool* error)
298 /*
299  * Interprets a stripped character string as an integer.
300  * Bounds checking is done on the value before returning. Value
301  * must be between the max and min; it can equal the max or min value.
302  *
303  * Certain ascii strings are checked for first (case is insignificant):
304  *
305  * String Retn_Value (defined in <limits.h>
306  * --------- --------------
307  * INT_MAX, max, all INT_MAX
308  * INT_MIN INT_MIN
309  * N/A, Not Available INT_MIN
310  * default default_value
311  *
312  * A default may be specified on the command line. The absence of a
313  * default may also be specified by setting default_value to
314  * NO_DEFAULT_INT.
315  *
316  * If there is an error, *error is set to true. *error isn't touched
317  * if there isn't an error.
318  */
319 {
320  int retn_value, check = false;
321  double LmaxVal, LminVal;
322  if (defaultVal == NO_DEFAULT_INT) {
323  check = true;
324  }
325  if (interpret_int(int_string, &retn_value, maxVal, minVal, defaultVal)) {
326  if (check) {
327  if (retn_value == NO_DEFAULT_INT) {
328  (void) fprintf(stderr,
329  "ERROR: str_to_int: Default not allowed\n");
330  *error = true;
331  }
332  }
333  if (maxVal < INT_MAX) {
334  LmaxVal = (double) maxVal + 0.01;
335  } else {
336  LmaxVal = (double) maxVal;
337  }
338  if (minVal > INT_MIN) {
339  LminVal = (double) minVal - 0.01;
340  } else {
341  LminVal = (double) minVal;
342  }
343  if (outofbnds((double) retn_value, LmaxVal, LminVal)) {
344  fprintf(stderr,
345  "ERROR: str_to_int outofbnds:\n\t\"%s\"\n",
346  int_string);
347  fprintf(stderr,"\tmax = %d, min = %d\n", maxVal, minVal);
348  *error = true;
349  }
350  } else {
351  *error = true;
352  }
353  return (retn_value);
354 }
355 /**************************************************************************/
356 /**************************************************************************/
357 /**************************************************************************/
358 
359 double tok_to_double(const TOKEN* tokPtr, const double maxVal,
360  const double minVal, const double defaultVal,
361  bool* error)
362 /*
363  * Interprets the first string of a TOKEN structure as a double.
364  * Returns the interpreted value as the return value.
365  * Errors conditions are created if more than one token is found.
366  *
367  * Bounds checking is then done on the value before returning. Value
368  * must be between the max and min; it can equal the max or min.
369  *
370  * Useful values for bounds (specified in <limits.h>:
371  * DBL_MAX = largest legitimate value of a double ~ 2.0E-308
372  * -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
373  * DBL_EPSILON = smallest value of a double that can be added to one
374  * and produce a different number. ~ 2.0E-16
375  * DBL_MIN = smallest value of a double ~ 2.0E-308
376  * For example:
377  * If 0.0 is not a legitimate number for value, set min = DBL_MIN
378  * If value>=0.0 is legitimate, set min = 0.0
379  * if value<=100., set max = 100.
380  * If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
381  *
382  * Certain ascii strings are checked for first (case is insignificant):
383  *
384  * Token_String Retn_Value ( specified in <limits.h>
385  * --------- ---------------------------------------
386  * FLT_MAX, all FLT_MAX
387  * DBL_MAX, max DBL_MAX
388  * N/A -DBL_MAX
389  * default or "" default_value
390  * small, DBL_MIN DBL_MIN
391  * DBL_EPSILON DBL_EPSILON
392  *
393  * A default may be specified by either specifying the value as
394  * "default" or by the absense of any tokens in the TOKEN struct.
395  * The absence of a default may also be specified by setting the
396  * value of default_value to NO_DEFAULT_DOUBLE.
397  *
398  * If there is an error, *error is set to true. *error isn't touched
399  * if there isn't an error.
400  */
401 {
402  if (tokPtr->ntokes == 0) {
403  return(str_to_double(DEFAULT_STR, maxVal, minVal, defaultVal, error));
404  } else if (tokPtr->ntokes > 1) {
405  (void) fprintf(stderr, "ERROR: tok_to_double, ntokes > 1: %s\n",
406  tokPtr->orig_str);
407  *error = true;
408  }
409  return(str_to_double(tokPtr->tok_ptr[0], maxVal, minVal, defaultVal, error));
410 }
411 /**************************************************************************/
412 /**************************************************************************/
413 /**************************************************************************/
414 
415 double str_to_double(const char* dbl_string, const double maxVal,
416  const double minVal, const double defaultVal,
417  bool* error)
418 /*
419  * Interprets a stripped character string as a double. Returns the
420  * interpreted value as the return value.
421  *
422  * Bounds checking is then done on the value before returning. Value
423  * must be between the max and min; it can equal the max or min.
424  *
425  * Useful values for bounds (specified in <limits.h>:
426  * DBL_MAX = largest legitimate value of a double ~ 2.0E-308
427  * -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
428  * DBL_EPSILON = smallest value of a double that can be added to one
429  * and produce a different number. ~ 2.0E-16
430  * DBL_MIN = smallest value of a double ~ 2.0E-308
431  * For example:
432  * If 0.0 is not a legitimate number for value, set min = DBL_MIN
433  * If value>=0.0 is legitimate, set min = 0.0
434  * if value<=100., set max = 100.
435  * If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
436  *
437  * Certain ascii strings are checked for first (case is insignificant):
438  *
439  * String Retn_Value ( specified in <limits.h>
440  * --------- ---------------------------------------
441  * FLT_MAX, all FLT_MAX
442  * DBL_MAX, max DBL_MAX
443  * N/A -DBL_MAX
444  * default default_value
445  * small, DBL_MIN DBL_MIN
446  * DBL_EPSILON DBL_EPSILON
447  *
448  * A default may be specified. The absence of a
449  * default may also be specified by setting the value of default_value
450  * to NO_DEFAULT_DOUBLE.
451  *
452  * If there is an error, *error is set to true. *error isn't touched
453  * if there isn't an error.
454  */
455 {
456  double retn_value;
457  int check = false;
458  if (defaultVal == NO_DEFAULT_DOUBLE) {
459  check = true;
460  }
461  if (interpret_double(dbl_string, &retn_value, maxVal, minVal, defaultVal)) {
462  if (check)
463  if (retn_value == NO_DEFAULT_DOUBLE) {
464  (void) fprintf(stderr,
465  "ERROR: keyLine_double: Default not allowed\n");
466  *error = true;
467  }
468  if (outofbnds(retn_value, maxVal, minVal)) {
469  (void) fprintf(stderr, "ERROR: keyLine_double outofbnds:\n\t\"%s\"\n",
470  dbl_string);
471  (void) fprintf(stderr,"\tmax = %e, min = %e\n", maxVal, minVal);
472  *error = true;
473  }
474  } else {
475  *error = true;
476  }
477  return (retn_value);
478 }
479 /*****************************************************************************/
480 /*****************************************************************************/
481 /*****************************************************************************/
482 
483 bool tok_to_boolean(const TOKEN* tokPtr, const int default_value,
484  bool* error)
485 /*
486 * Interprets the first string of a TOKEN structure as a bool.
487 * (i.e., true or false). Returns the interpreted value as the
488 * return value.
489 * Errors conditions are created if more than one token is found.
490 *
491 * The following character strings are interpreted
492 * (case doesn't matter):
493 *
494 * true = "YES", "true", "T", "Y"
495 * false = "NO, "false", "N", "F"
496 * default_value = "DEFAULT" or ""
497 *
498 * A default may be specified on the command line. The absence of a
499 * default may also be specified by using the value of NO_DEFAULT_INT.
500 * If tokPtr contains no tokens, this routine will try to use the
501 * default value.
502 *
503 * If there is an error, *error is set to true. *error isn't touched
504 * if there isn't an error.
505 */
506 {
507  if (tokPtr->ntokes == 0) {
508  return(str_to_boolean(DEFAULT_STR, default_value, error));
509  } else if (tokPtr->ntokes > 1) {
510  (void) fprintf(stderr, "ERROR: tok_to_boolean, ntokes > 1: %s\n",
511  tokPtr->orig_str);
512  *error = true;
513  }
514  return(str_to_boolean(tokPtr->tok_ptr[0], default_value, error));
515 }
516 /******************************************************************************/
517 /******************************************************************************/
518 /******************************************************************************/
519 
520 bool str_to_boolean(const char* string, const int default_value,
521  bool* error)
522 /*
523 * Interprets a stripped character string as a bool value
524 * (i.e., true or false). It returns that value as the return value.
525 *
526 * The following character strings are interpreted
527 * (case doesn't matter):
528 *
529 * true = "YES", "true", "T", "Y"
530 * false = "NO, "false", "N", "F"
531 * default_value = "DEFAULT"
532 *
533 * A default may be specified on the command line. The absence of a
534 * default may also be specified by using the value of NO_DEFAULT_INT.
535 *
536 * If there is an error, *error is set to true. *error isn't touched
537 * if there isn't an error.
538 */
539 {
540  int retn_value;
541  if (interpret_boolean(string, &retn_value, default_value)) {
542  if (retn_value == NO_DEFAULT_BOOLEAN) {
543  (void) fprintf(stderr,
544  "ERROR: keyLine_boolean: Default not allowed\n");
545  *error = true;
546  }
547  } else {
548  *error = true;
549  }
550  return (retn_value != 0);
551 }
552 /**************************************************************************/
553 /**************************************************************************/
554 /**************************************************************************/
555 
556 char* tok_to_string(const TOKEN* tokPtr, const int maxTok,
557  const int minTok, const char* defaultVal, bool* error)
558 /*
559  * Interprets the arguments in a TOKEN structure as a string.
560  * It mallocs new space for the string, are returns the pointer to it.
561  * The number of tokens in the string is checked before returning.
562  * The value must be between the maxTok and minTok; it can equal the
563  * max or min value.
564  *
565  * Certain ascii strings are checked for first (case is insignificant):
566  *
567  * String Retn_Value
568  * --------- --------------
569  * default or "" defaultVal
570  *
571  * A default may be specified on the command line. The absence of a
572  * default may also be specified by setting default_value to
573  * NO_DEFAULT_INT.
574  *
575  * If there is an error, *error is set to true. *error isn't touched
576  * if there isn't an error.
577  */
578 {
579  char* str;
580  if (tokPtr->ntokes == 0) {
581  str = str_to_string(DEFAULT_STR, defaultVal, error);
582  } else {
583  str = str_to_string(tokPtr->orig_str, defaultVal, error);
584  }
585  if (outofbnds((double) tokPtr->ntokes, (double) maxTok,
586  (double) minTok)) {
587  (void) fprintf(stderr, "ERROR: tok_to_String:\n\t\"%s\"\n",
588  tokPtr->orig_str);
589  (void) fprintf(stderr,"\tmaxTok = %d, minTok = %d\n", maxTok, minTok);
590  *error = true;
591  }
592  return (str);
593 }
594 /*****************************************************************************/
595 /*****************************************************************************/
596 /*****************************************************************************/
597 
598 char* str_to_string(const char* str, const char* defaultVal,
599  bool* error)
600 /*
601  * Interprets the argument string as a string.
602  * It mallocs new space for the string, are returns the pointer to it.
603  *
604  * Certain ascii strings are checked for first (case is insignificant):
605  *
606  * String Retn_Value
607  * --------- --------------
608  * default defaultVal
609  *
610  * A default may be specified on the command line. The absence of a
611  * default may also be specified by setting default_value to
612  * NO_DEFAULT_INT.
613  *
614  * If there is an error, *error is set to true. *error isn't touched
615  * if there isn't an error.
616  */
617 {
618  if (str == NULL) {
619  *error = true;
620  (void) fprintf(stderr,"ERROR str_to_string: str is uninialized\n");
621  return(NULL);
622  }
623  if (strmatch(str, DEFAULT_STR)) {
624  if (strmatch(defaultVal, NO_DEFAULT_STR)) {
625  *error = true;
626  (void) fprintf(stderr,"ERROR str_to_string: no default allowed\n");
627  return(copy_string(NO_DEFAULT_STR));
628  } else {
629  return(copy_string(defaultVal));
630  }
631  }
632  return(copy_string(str));
633 }
634 /**************************************************************************/
635 /**************************************************************************/
636 /**************************************************************************/
637 
638 int scan_for_int(FILE* ifp, const char* str, const int maxVal,
639  const int minVal)
640 /*
641  * Scans the file for a line matching string. Then, interprets
642  * everything after the equals sign as a single integer.
643  * Bounds checking is done on the value before returning. Value
644  * must be between the max and min; it can equal the max or min value.
645  *
646  * Certain ascii strings are checked for first (case is insignificant):
647  *
648  * String Retn_Value
649  * --------- --------------
650  * INT_MAX, max, all INT_MAX
651  * INT_MIN, default INT_MIN
652  * N/A, Not Available INT_MIN
653  *
654  * Because this is a fixed format input file routine, errors are
655  * handled by terminally exiting the program.
656  */
657 {
658  int retn_value, defaultVal = INT_MIN;
659  char* tok_ptr[2];
660  char input[MAX_INPUT_STR_LN + 1];
661  if (scan_for_line(ifp, str, input, KEY_CHAR, PrintInputFile) < 0) {
662  exit(-1);
663  }
664  if (stokenize(input, DELIMITERS, tok_ptr, 2) == 1) {
665  if (interpret_int(tok_ptr[0], &retn_value,
666  maxVal, minVal, defaultVal)) {
667  if (outofbnds((double) retn_value, (double) maxVal,
668  (double) minVal)) {
669  fprintf(stderr,
670  "ERROR: scan_for_int outofbnds:\n\t\"%s\"\n",str);
671  fprintf(stderr,"\tmax = %d, min = %d\n", maxVal, minVal);
672  exit(-1);
673  } else {
674  return(retn_value);
675  }
676  }
677  }
678  fprintf(stderr, "ERROR while processing line, \"%s\"\n", str);
679  exit(-1); /*NOTREACHED*/
680 }
681 /**************************************************************************/
682 /**************************************************************************/
683 /**************************************************************************/
684 
685 bool scan_for_boolean(FILE* ifp, const char* string)
686 /*
687  * Scans the file for a line matching string. Then, interprets
688  * everything after the equals sign as a single boolean value
689  *
690  * Because this is a fixed format input file routine, errors are
691  * handled by terminally exiting the program.
692  */
693 {
694  int ret_value;
695  char* tok_ptr[2];
696  char input[MAX_INPUT_STR_LN + 1];
697  if (scan_for_line(ifp, string, input, KEY_CHAR, PrintInputFile) < 0) {
698  exit(-1);
699  }
700  if (stokenize(input, DELIMITERS, tok_ptr, 2) == 1) {
701  if (interpret_boolean(tok_ptr[0], &ret_value, NO_DEFAULT_BOOLEAN)) {
702  if (ret_value == NO_DEFAULT_BOOLEAN) {
703  (void) fprintf(stderr, "scan_for_boolean: default not allowed\n");
704  exit(-1);
705  }
706  return (ret_value != 0);
707  }
708  }
709  (void) fprintf(stderr, "scan_for_boolean: ERROR on line \"%s\"\n", string);
710  exit(-1); /*NOTREACHED*/
711 }
712 /******************************************************************************/
713 /******************************************************************************/
714 /******************************************************************************/
715 
716 double scan_for_double(FILE* ifp, const char* string, const double maxVal,
717  const double minVal)
718 /*
719  * Scans the file for a line matching string. Then, interprets
720  * everything after the equals sign as a single floating point number.
721  * Bounds checking is then done on the value before returning. Value
722  * must be between the max and min; it can equal the max or min.
723  *
724  * Useful values for bounds:
725  * DBL_MAX = largest legitimate value of a double ~ 2.0E-308
726  * -DBL_MAX = smallest legitimate value of a double ~ 2.0E-308
727  * DBL_EPSILON = smallest value of a double that can be added to one
728  * and produce a different number. ~ 2.0E-16
729  * DBL_MIN = smallest value of a double ~ 2.0E-308
730  * For example:
731  * If 0.0 is not a legitimate number for value, set min = DBL_MIN
732  * If value>=0.0 is legitimate, set min = 0.0
733  * if value<=100., set max = 100.
734  * If no range checking is required, set max = DBL_MAX, min = -DBL_MAX
735  *
736  * Certain ascii strings are checked for first (case is insignificant):
737  *
738  * String Retn_Value
739  * --------- --------------
740  * FLT_MAX, all FLT_MAX
741  * DBL_MAX, max DBL_MAX
742  * N/A, default -DBL_MAX
743  * small, DBL_MIN DBL_MIN
744  * DBL_EPSILON DBL_EPSILON
745  *
746  * Because this is a fixed format input file routine, errors are
747  * handled by terminally exiting the program.
748  */
749 {
750  double retn_value;
751  char* tok_ptr[2];
752  char input[MAX_INPUT_STR_LN + 1];
753  if (scan_for_line(ifp, string, input, KEY_CHAR, true) < 0) {
754  exit(-1);
755  }
756  if (stokenize(input, DELIMITERS, tok_ptr, 2) > 0) {
757  if (interpret_double(tok_ptr[0], &retn_value, maxVal, minVal,
758  NO_DEFAULT_DOUBLE)) {
759  if (retn_value == NO_DEFAULT_DOUBLE) {
760  (void) fprintf(stderr,
761  "ERROR: scan_for_double has no default\n");
762  exit(-1);
763  }
764  if (outofbnds(retn_value, maxVal, minVal)) {
765  (void) fprintf(stderr,
766  "ERROR: scan_for_double outofbnds:\n \"%s = %e\"\n",
767  string, retn_value);
768  (void) fprintf(stderr,"\tmax = %e, min = %e\n", maxVal, minVal);
769  exit(-1);
770  } else {
771  return(retn_value);
772  }
773  }
774  }
775  (void) fprintf(stderr, "ERROR scan_for_double: \"%s\"\n", string);
776  exit(-1); /*NOTREACHED*/
777 }
778 /******************************************************************************/
779 /******************************************************************************/
780 /******************************************************************************/
781 
782 char* scan_for_string(FILE* ifp, const char* string, const int maxVal,
783  const int minVal)
784 /*
785  * Scans the file for a line matching string. Then, interprets
786  * everything after the equals sign as string to be returned.
787  * Storage for the resulting string is malloced, and the address
788  * of the string is returned.
789  * The string is returned stripped of leading and trailing white space,
790  * and of comments.
791  *
792  * Length checking is then done on the number of characters returned.
793  *
794  * Because this is a fixed format input file routine, errors are
795  * handled by terminally exiting the program.
796  */
797 {
798  size_t len;
799  char input[MAX_INPUT_STR_LN + 1];
800  if (scan_for_line(ifp, string, input, KEY_CHAR, PrintInputFile) < 0) {
801  exit(-1);
802  }
803  len = strlen(input);
804  if (outofbnds((double) len, (double) maxVal, (double) minVal)) {
805  (void) fprintf(stderr,
806  "ERROR: scan_for_string string length: \"%s = %s\"\n", string, input);
807  (void) fprintf(stderr, "\tlength max = %d, min = %d\n", maxVal, minVal);
808  exit(-1);
809  }
810  return (copy_string(input));
811 }
812 /**************************************************************************/
813 /**************************************************************************/
814 /**************************************************************************/
815 
816 int scan_for_line(FILE* ifp, const char* str, char input[],
817  const char ch_term, const int print_flag)
818 /*
819 * Scan the input file (reading in strings according to * 'read_string(ifp,)'
820 * specifications) until the character pattern in 'string' is matched.
821 * Returns all of the characters after the termination character in
822 * a null-character terminated string,
823 *
824 * Parameter list:
825 *
826 * ifp == pointer to file "input"
827 * string == contains string pattern to be matched.
828 * input == buffer array to hold characters that are read in.
829 * On output, it contains the return character string
830 * ch_term== Termination character. When scanning a line of input
831 * is read until either a newline, the 'ch' termination
832 * character is read, or the end-of-file is read.
833 *
834 * Output:
835 * This function returns the number of characters in the string input,
836 * excluding the null character. Error conditions are currently
837 * handled by returning with negative return values.
838 */
839 {
840  int retn_value, i;
841  bool found = false;
842  char match_string[MAX_INPUT_STR_LN+1],
843  save_input[MAX_INPUT_STR_LN+1];
844  static const char* ename = "ERROR scan_for_line: ";
845 
846  /*
847  * Error test the input match string
848  */
849 
850  if (strlen(str) > MAX_INPUT_STR_LN) {
851  fprintf(stderr,"%sMatch string is too long:\n\t%s\n",
852  ename, str);
853  return(-1);
854  }
855 
856  /*
857  * Make it an error to have the comment indicator in a
858  * match string
859  */
860 
861  for (i = 0; i < (int) strlen(str); i++) {
862  if (str[i] == COM_CHAR || str[i] == COM_CHAR2) {
863  fprintf(stderr, "%s Comment in match string\n\t%s\n",
864  ename, str);
865  return(-1);
866  }
867  }
868 
869  /*
870  * Strip the string of leading and trailing white space
871  */
872 
873  if ((retn_value = strip(strcpy(match_string, str))) <= 0) {
874  fprintf(stderr, "%sMatch string is white space: \"%s\"\n",
875  ename, str);
876  return(-1);
877  }
878 
879  /*
880  * Start the search for the string
881  */
882 
883  do {
884  /*
885  * Read a chunk of text, either up to a newline or to the
886  * character ch_term, from the file pointer, ifp.
887  */
888 
889  if ((retn_value = read_string(ifp, save_input, ch_term)) < 0) {
890  fprintf(stderr,
891  "%sEOF found in input file while searching for:\n", ename);
892  fprintf(stderr, "\t\"%s\"\n", match_string);
893  return(retn_value);
894  }
895 
896  /*
897  * copy the string just read to the output string, and the
898  * strip it of leading and trailing white space, and comments.
899  * Then, compare the stripped input string with the stripped
900  * match_string
901  */
902 
903  strcpy(input, save_input);
904  if (strip(input) > 0) {
905  found = strmatch(input, match_string);
906  }
907 
908  /*
909  * If requested print the line, including comments, on standard output.
910  * Use the retn_value from read_string to test whether a \n needs to
911  * be written.
912  */
913 
914  if (print_flag) {
915  if (found) {
916  printf("->\t");
917  }
918  if (retn_value == 0) {
919  printf("%s\n", save_input);
920  } else {
921  printf("%s%c", save_input, ch_term);
922  }
923  }
924 
925  /*
926  * Read and print the rest of the line, if we are in the middle of it.
927  */
928 
929  if (retn_value > 0) {
930  if ((retn_value = read_line(ifp, input, print_flag)) < 0) {
931  fprintf(stderr,
932  "ERROR, EOF found in input file while reading line:\n");
933  fprintf(stderr, "%s %c\n", str, ch_term);
934  return(retn_value);
935  }
936  } else {
937  input[0] = '\0';
938  }
939  } while (!found);
940  return (retn_value);
941 }
942 /*****************************************************************************/
943 /*****************************************************************************/
944 /*****************************************************************************/
945 
946 int read_line(FILE* ifp, char input[], const int print_flag)
947 
948 /*
949 * read_line:
950 *
951 * Reads a line of input. The line is
952 * printed to standard output, if print_flag is true.
953 * The line is returned in the character
954 * string pointed to by input. Leading and trailing white spaces are
955 * stripped from the line.
956 * The number of characters, excluding the null character, is
957 * returned, except when read_string encounters an error condition
958 * (negative return values). Then, the error condition is returned.
959 */
960 {
961  int retn_value;
962 
963  /*
964  * read the file up to the next new line, read_string will return
965  * a 0 for a success, and a negative value for failure
966  */
967 
968  retn_value = read_string(ifp, input, '\n');
969 
970  /*
971  * Print out the line before stripping it of comments and white space
972  */
973 
974  if (print_flag) {
975  printf("%s\n", input);
976  }
977 
978  /*
979  * Strip the return line of comments and leading/trailing white space
980  * Use the function strip to return the number of characters remaining
981  */
982 
983  if (retn_value == 0) {
984  return (strip(input));
985  }
986 
987  /*
988  * If an error condition occurred in read_string, return the error
989  * condition value instead of the character count
990  */
991 
992  (void) strip(input);
993  return (retn_value);
994 }
995 /**************************************************************************/
996 /**************************************************************************/
997 /**************************************************************************/
998 
999 int read_string(FILE* ifp, char string[], const char ch)
1000 /*
1001  * This routine reads the standard input until encountering
1002  * the end-of-file, a newline, the character 'ch' or until
1003  * MAX_INPUT_STR_LN characters are read. The inputted characters
1004  * are read into 'string'.
1005  * If an EOF occurs, -1 is returned.
1006  * If a line is longer than MAX_INPUT_STR_LN, a -2 is returned
1007  * and an error message is written to standard error.
1008  * string[] will be returned null-terminated with the
1009  * first MAX_INPUT_STR_LN of the line.
1010  * Upon successful completion with the read terminated by the
1011  * character 'ch', the number of characters read plus 1 for the
1012  * null character at the end of the string is returned. If the
1013  * read is terminated by '\n', a 0 is returned, even if ch = '\n'
1014  *
1015  *
1016  * Parameter list:
1017  *
1018  * ifp == pointer to file "input"
1019  * string == On output, 'string' contains the characters read
1020  * from the input stream. However, the termination character
1021  * or the newline character is not included
1022  * ch == Additional Termination character. That is, input function
1023  * stops when 'ch' or '\n' is read.
1024  */
1025 {
1026  int i = 0, rtn_value, new_ch;
1027 
1028  /*
1029  * Read from the file, until termination conditions occur
1030  * The order in the while statement is important.
1031  */
1032  while ((i < MAX_INPUT_STR_LN)
1033  && ((new_ch = getc(ifp)) != ch)
1034  && (new_ch != '\n')
1035  && (new_ch != EOF)) {
1036  string[i++] = new_ch;
1037  }
1038 
1039  /*
1040  * Check for termination conditions
1041  */
1042  if (new_ch == EOF) {
1043  rtn_value = -1;
1044  } else if (i == MAX_INPUT_STR_LN) {
1045  fprintf(stderr,
1046  "read_string ERROR: Maxed line character count, %d,"
1047  " before finding (%c)\n", MAX_INPUT_STR_LN, ch);
1048  rtn_value = -2;
1049  } else if (new_ch == '\n') {
1050  rtn_value = 0;
1051  } else {
1052  rtn_value = i + 1;
1053  }
1054 
1055  /*
1056  * Make sure the string is null terminated and return
1057  */
1058  string[i] = '\0';
1059  return (rtn_value);
1060 }
1061 /**************************************************************************/
1062 
1063 static bool interpret_boolean(const char* token, int* ret_value,
1064  const int default_value)
1065 /*
1066 * This routine interprets a string token to be either true or false
1067 * and then returns the appropriate answer as an int value in the
1068 * variable ret_value. It is int because the default value may not
1069 * be only 0 or 1
1070 */
1071 {
1072  /* lower_case (token); */
1073  if (token[0] == '\0') {
1074  *ret_value = default_value;
1075  } else if (strlen(token) == 1) {
1076  switch (token[0]) {
1077  case 't':
1078  case 'y':
1079  *ret_value = true;
1080  break;
1081  case 'f':
1082  case 'n':
1083  *ret_value = false;
1084  break;
1085  default:
1086  return (false);
1087  }
1088  } else {
1089  if (strmatch(token,"true") || strmatch(token,"yes")) {
1090  *ret_value = true;
1091  } else if (strmatch(token,"false") || strmatch(token,"no")) {
1092  *ret_value = false;
1093  } else if (strmatch(token,DEFAULT_STR) == 0) {
1094  *ret_value = default_value;
1095  } else {
1096  return (false);
1097  }
1098  }
1099  return (true);
1100 }
1101 /**************************************************************************/
1102 
1103 static bool interpret_int(const char* token, int* retn_value,
1104  const int maxVal, const int minVal,
1105  const int defaultVal)
1106 /*
1107 * This routine interprets a string token to be an integer
1108 * and then returns the appropriate answer as an int value in the
1109 * variable ret_value.
1110 * Errors are indicated by returning false. Success is indicated
1111 * by returning true.
1112 *
1113 * Certain ascii strings are checked for first (case is insignificant):
1114 *
1115 * String Retn_Value
1116 * --------- --------------
1117 * INT_MAX, all INT_MAX
1118 * INT_MIN INT_MIN
1119 * max maxVal
1120 * min minVal
1121 * default defaultVal
1122 * NULL string defaultVal
1123 * N/A, Not_Available INT_MIN
1124 */
1125 {
1126  int retn;
1127 
1128  /*
1129  * Allow a few key ascii phrases in place of an actual int
1130  */
1131 
1132  /* lower_case(token); */
1133  if (token[0] == '\0') {
1134  *retn_value = defaultVal;
1135  } else if ((strmatch(token,"all")) || strmatch(token,"int_max")) {
1136  *retn_value = INT_MAX;
1137  } else if (strmatch(token,"int_min")) {
1138  *retn_value = INT_MIN;
1139  } else if (strmatch(token,"max")) {
1140  *retn_value = maxVal;
1141  } else if (strmatch(token,"min")) {
1142  *retn_value = minVal;
1143  } else if (strmatch(token,DEFAULT_STR)) {
1144  *retn_value = defaultVal;
1145  } else if (strmatch(token,"n/a") || strmatch(token,"not_available")) {
1146  *retn_value = INT_MIN;
1147  } else {
1148  if ((retn = sscanf(token, "%d", retn_value)) != 1) {
1149  *retn_value = retn;
1150  return (false);
1151  }
1152  }
1153  return (true);
1154 }
1155 /******************************************************************************/
1156 /******************************************************************************/
1157 /******************************************************************************/
1158 
1159 static bool interpret_double(const char* token, double* retn_value,
1160  const double maxVal, const double minVal,
1161  const double defaultVal)
1162 /*
1163 * This routine interprets a string token to be a double
1164 * and then returns the appropriate answer as a double value in the
1165 * variable retn_value.
1166 * The function itself returns true if successful or false if unsuccessful
1167 *
1168 *
1169 * Certain ascii strings are checked for first (case is insignificant):
1170 *
1171 * String Retn_Value
1172 * --------- --------------
1173 * FLT_MAX, all FLT_MAX
1174 * FLT_MIN FLT_MIN
1175 * DBL_MAX DBL_MAX
1176 * max maxVal
1177 * min minVal
1178 * default defaultVal
1179 * NULL string defaultVal
1180 * N/A -DBL_MAX
1181 * small, DBL_MIN DBL_MIN
1182 * DBL_EPSILON DBL_EPSILON
1183 *
1184 * DBL_MAX = largest legitimate value of a double ~ 2.0E-308
1185 * -DBL_MAX = smallest legitimate value of a double ~ - 2.0E-308
1186 * DBL_EPSILON = smallest value of a double that can be added to one
1187 * and produce a different number. ~ 2.0E-16
1188 * DBL_MIN = tiniest value of a double ~ 2.0E-308
1189 */
1190 {
1191  int retn;
1192  float retn_float;
1193 
1194  /*
1195  * Allow a few key ascii phrases in place of an actual float
1196  */
1197 
1198  /* lower_case(token); */
1199  if (token[0] == '\0') {
1200  *retn_value = defaultVal;
1201  } else if ((strmatch(token,"all")) || strmatch(token,"flt_max")) {
1202  *retn_value = FLT_MAX;
1203  } else if (strmatch(token,"flt_min")) {
1204  *retn_value = FLT_MIN;
1205  } else if (strmatch(token,"dbl_max")) {
1206  *retn_value = DBL_MAX;
1207  } else if (strmatch(token,"max")) {
1208  *retn_value = maxVal;
1209  } else if (strmatch(token,"min")) {
1210  *retn_value = minVal;
1211  } else if (strmatch(token,"n/a")) {
1212  *retn_value = -DBL_MAX;
1213  } else if (strmatch(token, DEFAULT_STR)) {
1214  *retn_value = defaultVal;
1215  } else if (strmatch(token,"small") || strmatch(token,"dbl_min")) {
1216  *retn_value = DBL_MIN;
1217  } else if (strmatch(token,"dbl_epsilon")) {
1218  *retn_value = DBL_EPSILON;
1219  } else {
1220  if ((retn = sscanf(token, "%e", &retn_float)) != 1) {
1221  *retn_value = (double) retn;
1222  return (false);
1223  } else {
1224  *retn_value = (double) retn_float;
1225  }
1226  }
1227  return(true);
1228 }
1229 /******************************************************************************/
1230 /******************************************************************************/
1231 /******************************************************************************/
1232 
1233 int strip(char str[])
1234 /*
1235 * This routine strips off blanks and tabs (only leading and trailing
1236 * characters) in 'str'. On return, it returns the number of
1237 * characters still included in the string (excluding the null character).
1238 *
1239 * Comments are excluded -> All instances of the comment character, '!',
1240 * are replaced by '\0' thereby terminating
1241 * the string
1242 *
1243 * Parameter list:
1244 *
1245 * str == On output 'str' contains the same characters as on
1246 * input except the leading and trailing white space and
1247 * comments have been removed.
1248 */
1249 {
1250  int i = 0, j = 0;
1251  char ch;
1252 
1253  /*
1254  * Quick Returns
1255  */
1256 
1257  if ((str == NULL) || (str[0] == '\0')) {
1258  return (0);
1259  }
1260 
1261  /* Find first non-space character character */
1262 
1263  while (((ch = str[i]) != '\0') && isspace(ch)) {
1264  i++;
1265  }
1266 
1267  /*
1268  * Move real part of str to the front by copying the string
1269  * - Comments are handled here, by terminating the copy at the
1270  * first comment indicator, and inserting the null character at
1271  * that point.
1272  */
1273 
1274  while ((ch = str[j+i]) != '\0' &&
1275  (ch != COM_CHAR) &&
1276  (ch != COM_CHAR2)) {
1277  str[j] = ch;
1278  j++;
1279  }
1280  str[j] = '\0';
1281  j--;
1282 
1283  /* Remove trailing white space by inserting a null character */
1284 
1285  while ((j != -1) && isspace(str[j])) {
1286  j--;
1287  }
1288  j++;
1289  str[j] = '\0';
1290  return (j);
1291 }
1292 /**************************************************************************/
1293 /**************************************************************************/
1294 /**************************************************************************/
1295 
1296 void lower_case(char str[])
1297 /*
1298 * lower_case:
1299 * Translates a string delimited by a NULL character
1300 * to lower case. There is no error checking in this version.
1301 * Relies on stlib function, tolower.
1302 */
1303 {
1304  int i;
1305  for (i = 0; i < (int) strlen(str); i++) {
1306 # if defined(_INCLUDE_XOPEN_SOURCE) && ! defined(__lint)
1307  str[i] = _tolower((str[i]));
1308 # else
1309  str[i] = tolower(str[i]);
1310 # endif
1311  }
1312 }
1313 /******************************************************************************/
1314 /******************************************************************************/
1315 /******************************************************************************/
1316 
1317 char* TokToStrng(const TOKEN* keyptr)
1318 /*
1319 * TokToStrng:
1320 * Mallocs a new character string and copies
1321 * the tokens character string to it, appending all tokens together
1322 * into a single string separated by a single space character.
1323 * It returns the pointer to the new string;
1324 * The new string should be freed when no longer needed.
1325 */
1326 {
1327  int i;
1328  if (!keyptr) {
1329  return NULL;
1330  }
1331  if (!keyptr->orig_str) {
1332  return NULL;
1333  }
1334  size_t iln = strlen(keyptr->orig_str) + 1 + keyptr->ntokes;
1335  char* fstr = (char*) malloc(iln * sizeof(char));
1336 
1337  char* const* str = &(keyptr->tok_ptr[0]);
1338  for (i = 0, fstr[0]= '\0'; i < (keyptr->ntokes - 1); i++, str++) {
1339  (void) strcat(strcat(fstr, *str), " ");
1340  }
1341  return(strcat(fstr, *str));
1342 }
1343 /******************************************************************************/
1344 /******************************************************************************/
1345 /******************************************************************************/
1346 
1347 int stokenize(char* string, const char* delimiters, char* tok_ptr[],
1348  const int max_tokens)
1349 /*
1350  * stokenize
1351  *
1352  * This function will break up a string into its respective "tokens".
1353  * It returns the number of tokens found. See the strtok(3) man page.
1354  *
1355  * input
1356  * ----------
1357  * string - String to be tokenized. Note, that the string is
1358  * changed by this procedure. Null characters are
1359  * put between each symbol.
1360  * delimiters - String containing a list of delimiters.
1361  * The example below covers 'white space'
1362  * e.g., char *delimiters = " \t\n";
1363  * max_tokens - Maximum number of tokens to be found
1364  *
1365  * output
1366  * -----------
1367  * tok_ptr - Vector of pointers to strings, that contain the input
1368  * string's tokens
1369  */
1370 {
1371  int i = 0;
1372  if (string == NULL) {
1373  tok_ptr[0] = NULL;
1374  return 0;
1375  }
1376  if (strlen(string) == 0) {
1377  tok_ptr[0] = string;
1378  return 0;
1379  }
1380  if ((tok_ptr[0] = strtok(string, delimiters)) != NULL) {
1381  do {
1382  if ((++i) == max_tokens) {
1383  break;
1384  }
1385  } while ((tok_ptr[i] = strtok(NULL, delimiters)) != NULL);
1386  }
1387  return (i);
1388 }
1389 /*****************************************************************************/
1390 /*****************************************************************************/
1391 /*****************************************************************************/
1392 
1393 static bool outofbnds(const double value, const double maxVal,
1394  const double minVal)
1395 /*
1396  * This routine checks the bounds of a single double value.
1397  * If it is inside or on the bounds, it returns false.
1398  * If it is outside the bounds, it returns true.
1399  */
1400 {
1401  if ((value <= maxVal) && (value >= minVal)) {
1402  return (false);
1403  }
1404  return(true);
1405 }
1406 /******************************************************************************
1407  *
1408  * strmatch():
1409  *
1410  * This routine checks whether one string is the same as another.
1411  * Upper case is transformed into lower case before the comparison is done.
1412  * Thus, case doesn't matter in the comparison. However, white space
1413  * does matter in this comparison.
1414  * If they are, it returns true
1415  * If they aren't, it returns false
1416  */
1417 bool strmatch(const char* s1, const char* s2)
1418 {
1419  while (*s1 != '\0') {
1420 # if defined (_INCLUDE_XOPEN_SOURCE) && ! defined(__lint)
1421  if (_tolower((*s1++)) != _tolower((*s2++))) {
1422  return (false);
1423  }
1424 # else
1425  if (tolower(*s1) != tolower(*s2)) {
1426  return (false);
1427  }
1428  s1++;
1429  s2++;
1430 # endif
1431  }
1432  if (*s2 != '\0') {
1433  return (false);
1434  }
1435  return (true);
1436 }
1437 
1438 /*****************************************************************************
1439  *
1440  * strstrmatch():
1441  *
1442  * This routine checks whether two strings are the same modulo differences
1443  * in their white space
1444  */
1445 bool strstrmatch(const char* s1, const char* s2)
1446 {
1447  struct TOKEN tmpKeyStruct1, tmpKeyStruct2;
1448  fillTokStruct(&tmpKeyStruct1, s1);
1449  fillTokStruct(&tmpKeyStruct2, s2);
1450  return (toktokmatch(&tmpKeyStruct2, &tmpKeyStruct1));
1451 }
1452 
1453 /*******************************************************************************
1454  *
1455  * strtokmatch():
1456  *
1457  * This routine checks whether a string matches the string contained in
1458  * the tokens of a keyLineStr.
1459  * White space and case are ignored.
1460  * If they are, it returns true
1461  * If they aren't, it returns false
1462  */
1463 bool strtokmatch(const TOKEN* keyptr, const char* s2)
1464 {
1465  struct TOKEN tmpKeyStruct;
1466  fillTokStruct(&tmpKeyStruct, s2);
1467  return (toktokmatch(keyptr, &tmpKeyStruct));
1468 }
1469 
1470 /**************************************************************************
1471  *
1472  * toktokmatch()
1473  *
1474  * This routine checks whether two TOKEN structures contain the
1475  * same data up to differences in white space.
1476  * Case is ignored as well, as strmatch is called.
1477  */
1478 bool toktokmatch(const TOKEN* keyptr1, const TOKEN* keyptr2)
1479 {
1480  int i = keyptr1->ntokes;
1481  if (i != keyptr2->ntokes) {
1482  return false;
1483  }
1484  while (i > 0) {
1485  i--;
1486  if (!strmatch(keyptr1->tok_ptr[i], keyptr2->tok_ptr[i])) {
1487  return false;
1488  }
1489  }
1490  return true;
1491 }
1492 
1493 /**************************************************************************/
1494 /*
1495  * fillTokStruct()
1496  *
1497  * Fill in a keyLineStruct with a string. Use the defn of white space
1498  * at the start of the file to tokenize the string, storing it in the
1499  * TOKEN structure.
1500  */
1501 void fillTokStruct(TOKEN* keyptr1, const char* s2)
1502 {
1503  if (keyptr1 == NULL) {
1504  return;
1505  }
1506  if (keyptr1->orig_str) {
1507  free(keyptr1->orig_str);
1508  }
1509  if (keyptr1->tok_str) {
1510  free(keyptr1->tok_str);
1511  }
1512  if (s2 == NULL) {
1513  keyptr1->orig_str = copy_string("");
1514  keyptr1->tok_str = copy_string("");
1515  keyptr1->ntokes = 0;
1516  keyptr1->tok_ptr[0] = keyptr1->orig_str;
1517  return;
1518  }
1519  keyptr1->orig_str = copy_string(s2);
1520  keyptr1->tok_str = copy_string(s2);
1521  keyptr1->ntokes = stokenize(keyptr1->tok_str, DELIMITERS, keyptr1->tok_ptr,
1522  MAXTOKENS);
1523 }
1524 
1525 /******************************************************************************
1526  *
1527  * copyTokStruct():
1528  *
1529  * Copies the information stored in keyptr2 into keyptr1
1530  */
1531 void copyTokStruct(TOKEN* keyptr1, const TOKEN* keyptr2)
1532 {
1533  if (keyptr1 == NULL) {
1534  return;
1535  }
1536  if (keyptr2 == NULL) {
1537  return;
1538  }
1539  if (keyptr1->orig_str) {
1540  free(keyptr1->orig_str);
1541  }
1542  if (keyptr1->tok_str) {
1543  free(keyptr1->tok_str);
1544  }
1545  if (keyptr2->orig_str == NULL) {
1546  keyptr1->orig_str = copy_string("");
1547  keyptr1->tok_str = copy_string("");
1548  keyptr1->ntokes = 0;
1549  keyptr1->tok_ptr[0] = keyptr1->orig_str;
1550  return;
1551  }
1552  keyptr1->orig_str = copy_string(keyptr2->orig_str);
1553  keyptr1->tok_str = copy_string(keyptr2->orig_str);
1554  keyptr1->ntokes = stokenize(keyptr1->tok_str, DELIMITERS, keyptr1->tok_ptr,
1555  MAXTOKENS);
1556 }
1557 
1558 /******************************************************************************
1559  *
1560  * in_char_list():
1561  *
1562  * Finds a match of one string against a list of strings. Returns
1563  * the position that the first match occurred.
1564  * If no match occurred, returns -1.
1565  * The comparisons ignore differences in white space.
1566  */
1567 int in_char_list(const char* const str1, const char** const list,
1568  int num_list)
1569 {
1570  int i;
1571  for (i = 0; i < num_list; i++) if (strstrmatch(str1, list[i])) {
1572  return(i);
1573  }
1574  return (-1);
1575 }
1576 /*****************************************************************************/
1577 /*****************************************************************************/
1578 /*****************************************************************************/
1579 
1580 char* copy_string(const char* string)
1581 /*
1582 * copy_string:
1583 * Mallocs a new character string and copies the old string to it
1584 *
1585 * NOTE: Memory leak may result if the calling program doesn't free
1586 * the malloced space
1587 */
1588 {
1589  char* new_string;
1590  new_string = (char*) malloc(strlen(string)+1);
1591  if (new_string == NULL) {
1592  (void) fprintf(stderr, "copy_string ERROR: malloc returned NULL");
1593  } else {
1594  (void) strcpy(new_string, string);
1595  }
1596  return (new_string);
1597 }
1598 
1599 /******************************************************************************
1600  *
1601  * strip_item_from_token ():
1602  *
1603  * Change the token by taking eliminating the iword'th token from the token
1604  * structure and reformulating the token expression
1605  */
1606 void strip_item_from_token(int iword, TOKEN* tok)
1607 {
1608  if (!tok) {
1609  return;
1610  }
1611  if (iword < 0 || iword > tok->ntokes) {
1612  return;
1613  }
1614 #ifdef _MSC_VER
1615  __w64 size_t ioffset = tok->tok_ptr[iword] - tok->tok_str;
1616 #else
1617  size_t ioffset = tok->tok_ptr[iword] - tok->tok_str;
1618 #endif
1619  size_t ilength = strlen(tok->tok_ptr[iword]);
1620 #ifdef _MSC_VER
1621  __w64 size_t i = ioffset;
1622  __w64 size_t j = ioffset + ilength;
1623 #else
1624  size_t i = ioffset;
1625  size_t j = ioffset + ilength;
1626 #endif
1627  if (j <= strlen(tok->orig_str)) {
1628  while (tok->orig_str[j] != '\0') {
1629  tok->orig_str[i] = tok->orig_str[j];
1630  i++;
1631  j++;
1632  }
1633  tok->orig_str[i] = '\0';
1634  }
1635  strcpy(tok->tok_str, tok->orig_str);
1636  tok->ntokes = stokenize(tok->tok_str, DELIMITERS, tok->tok_ptr,
1637  MAXTOKENS);
1638 }
1639 
1640 /*****************************************************************************/