/*************************************************************** OPTION.C This is a set of routines for processing a list of program options read from a control file. The first option in the list should be the terminator for that set of options; that is, when it's name is encountered, a final routine will be executed and the processing of that list will end. Fri 11-18-1988 1) Modified so that each word read by execute_options and execute_one_option is echoed to the screen. This should make it much easier to figure out what is wrong when the program fails in reading a control file. -- see note of 2/25/91 below 2) Added function "list_options()", to be used when an error is found. It prints to the screen a list of the available options. Eric Firing University of Hawaii Mon 02-25-91 JR Modified so execute_options() and execute_one_option() echo only any invalid option encountered, and then call list_options() to list valid options. */ #include #include /* strcmp() */ #include "ioserv.h" /* OPTION_TYPE, report_msg(), check_error() */ int get_option_index(OPTION_TYPE *list, char *word) { int i; for (i=0; list[i].name; i++) if (!strcmp( list[i].name, word)) return(i); /* match */ return(-1); /* no match */ } /* get_option_index */ int echo = 0; int execute_options(FILE *fp, OPTION_TYPE *list, int echo_flag) { char word[80]; int index = 0; int end = 0; int match = 0; /* count of the number of words matched */ echo = echo_flag; if (echo == 1) report_msg("% OPTIONS:\n% ======="); while (!end) { if (fscanf(fp, " %79s", word) != 1) return(-1); /* scanf error exit */ index = get_option_index(list, word); if (index < 0) { report_msg("\n% ERROR: Unrecognized option => "); report_msg(word); list_options(list); return(0); /* error exit: word not found */ } if (index == 0) { end = 1; if (echo == 1) report_msg("\n% =======\n"); } else { if (echo == 1) { report_msg("\n% "); report_msg(word); } if (list[index].function != NULL) (*(list[index].function))(fp, list[index].argument, list[index].code); } match++; } return(match); /* normal exit */ } /* execute_options */ int execute_one_option(FILE *fp, OPTION_TYPE *list) { char word[80]; int index = 0; if (fscanf(fp, " %79s", word) != 1) return(-1); /* scanf error exit */ index = get_option_index(list, word); if (index < 0) { report_msg("\n ERROR: Unrecognized option => "); report_msg(word); list_options(list); return(0); /* error exit: word not found */ } if (list[index].function != NULL) (*(list[index].function))(fp, list[index].argument, list[index].code); return(1); /* normal exit */ } /* execute_one_option */ char *get_option_name(OPTION_TYPE *list, int number) { int i; for (i=0; list[i].name; i++) if ( list[i].code == number ) return (list[i].name); return(NULL); } /* get_option_name() */ void list_options(OPTION_TYPE *list) { int i; report_msg("\n Valid options are:\n "); for (i=0; list[i].name; i++) { report_msg(list[i].name); report_msg("\n "); } } /* list_options() */ /*************************************************************** The following functions are likely to be useful in option processing. function: skip_to() This allows flexible nested commenting out of blocks of a control file. For example: skip_to next1 do_this do_that next1 in the control file will cause the commands do_this and do_that to be skipped, provided skip_to() is mapped to "skip_to" in the option structure. function: logical_or() This is used for building up a flag in which each option sets one or more bits. The option code is an integer with the appropriate bits set for that option. The logical_or operation then makes sure that these bits are also set in the argument, without disturbing any other bits. function: set_code() This is used when the option code completely determines the value of a flag word. ****************************************************************/ int skip_to(FILE *fp, char *arg, int code) { char word[80], next_word[80]; if (fscanf(fp, " %79s", word) != 1) return(-1); /* scanf error exit */ while (1) { if (fscanf(fp, " %79s", next_word) != 1) return(-1); if (strcmp(word, next_word) == 0) return(0); } } int logical_or(FILE *fp, char *arg, int code) { *((int *)arg) |= code; return(0); } int set_code(FILE *fp, char *arg, int code) { *((int *)arg) = code; return(0); } /*----------------------------------------------------------------- The following sets bit n (counting from 0) in a long word, or, if n>32, it resets bit n-100. */ int set_long_bit(FILE *fp, char *arg, int code) { long bit_mask; int off = 0; if (code >31) /* turn off a bit */ { code -= 100; off = 1; } bit_mask = 1; bit_mask <<= code; if (off) *((long *)arg) &= ~bit_mask; else *((long *)arg) |= bit_mask; return(0); } /* The following is for getting simple options, that is, numbers or strings, without translations. */ static NAME_LIST_ENTRY_TYPE op_format_list[] = { {" %c" , TYPE_CHAR}, {" %ld" , TYPE_LONG}, {" %f" , TYPE_FLOAT}, {" %lf" , TYPE_DOUBLE}, {PATH_FMT, TYPE_STRING}, /* from dbext.h via misc.h via ioserv.h */ {" %d" , TYPE_INT}, {NULL , 0} }; int op_get_param(FILE *fp, char *arg, int code) { /* If code is TYPE_STRING, then arg should be a FILE_NAME_TYPE or other char buffer of size PATHBUFSIZE. */ FILE_NAME_TYPE buf; /* not necessarily a file name... */ check_error( (fscanf(fp, get_name(op_format_list, code), arg) != 1), "op_get_param"); if (echo) { switch (code) { case TYPE_INT: sprintf(buf, " %d", *((int *) arg)); break; case TYPE_LONG: sprintf(buf, " %ld", *((long *) arg)); break; case TYPE_FLOAT: sprintf(buf, " %f", *((float *) arg)); break; case TYPE_DOUBLE: sprintf(buf, " %f", *((double *) arg)); break; case TYPE_CHAR: sprintf(buf, " %c", *arg); break; case TYPE_STRING: sprintf(buf, PATH_FMT, arg); break; } report_msg(buf); } return(1); }