/*------------------------------------------------------------------*\ | These are the things the user can specify: | | 1. Modern sample characteristics | | 2. How to combine or transform the modern sample data | | 3. Environmental data for the modern sample sites | | 4. Fossil sample characteristics | | 5. How to combine or transform the fossil sample data | | 6. Meta data for the fossil sample sites | | 7. Sample distance measure | | 8. How many modern analogs to report for each fossil sample | | 9. What modern sample meta data to include in the report | | 10. Where to put the results | | | | Peter N. Schweitzer (U.S. Geological Survey, Reston, VA 22092) | \*------------------------------------------------------------------*/ #include #include #include #include #include "analog.h" #ifdef THINK_C extern FILE *Mac_fopen (char *name, char *mode); #define FOPEN Mac_fopen #else #define FOPEN fopen #endif #ifndef HAVE_STRICMP int stricmp (char *s, char *t) { int d = 0; if (!*s && !*t) return (0); do { d = toupper(*s++) - toupper (*t++); } while (*s && !d); return (d); } #endif enum word_code { Wbasis, Wsample, Wdata, Wtransform, Wmeta, Wdistance, Wreport, Wname, Wclosest, Wverbose, WLBrace, WRBrace, WColon, WIdentifier, WNULL }; struct word { char *name; enum word_code code; }; static int word_list_count = 0; static struct word word_list[] = { {"basis", Wbasis }, {"sample", Wsample }, {"data", Wdata }, {"transform", Wtransform }, {"meta", Wmeta }, {"distance", Wdistance }, {"report", Wreport }, {"name", Wname }, {"closest", Wclosest }, {"verbose", Wverbose }, {NULL, WNULL } }; static int compare_words (const void *e1, const void *e2) { struct word *w1, *w2; w1 = (struct word *) e1; w2 = (struct word *) e2; return (stricmp (w1->name,w2->name)); } struct token { enum word_code code; char string[MAX_NAME_LENGTH]; int line_number; }; static struct token *token = NULL; static int token_count = 0; static void find_tokens (char *job_file) { int n; FILE *in; char line [MAX_CONFIG_LINE_LEN]; int line_count = 0; char *s; struct word w,*match; char string[MAX_NAME_LENGTH]; char *b, *e; int token_limit = 0; if (job_file) in = FOPEN (job_file,"r"); else { in = stdin; job_file = "stdin"; } if (in) { if (!word_list_count) { for (word_list_count=0; word_list[word_list_count].name; word_list_count++); qsort (word_list,word_list_count,sizeof(struct word),compare_words); } if (!(token = (struct token *) malloc (GRANULARITY * sizeof (struct token)))) { sprintf (message,"Error: could not allocate space for token array"); error_exit (message); } token_count = 0; token_limit = GRANULARITY; while (fgets (line,MAX_CONFIG_LINE_LEN,in)) { line_count++; if (s = strrchr (line,'\n')) *s = 0; if (s = strrchr (line,'\r')) *s = 0; s = line; while (*s && isspace (*s)) s++; /*------------------------------------------------------*\ | Read the tokens and put in the array token. | \*------------------------------------------------------*/ while (*s && *s != '#') { while (*s && isspace (*s)) s++; #ifdef DEBUG printf ("line_count %d token_count %d s = \"%s\"\n",line_count,token_count,s); #endif if (*s) switch (*s) { case '{': #ifdef DEBUG printf ("found left brace in line %d\n",line_count); #endif token[token_count].code = WLBrace; strcpy (token[token_count].string,"{"); token[token_count].line_number = line_count; token_count++; s++; break; case '}': #ifdef DEBUG printf ("found right brace in line %d\n",line_count); #endif token[token_count].code = WRBrace; strcpy (token[token_count].string,"}"); token[token_count].line_number = line_count; token_count++; s++; break; case ':': #ifdef DEBUG printf ("found colon in line %d\n",line_count); #endif token[token_count].code = WColon; strcpy (token[token_count].string,":"); token[token_count].line_number = line_count; token_count++; s++; break; default: b = s; if (e = strpbrk (s," \t{#:}")) { memcpy (string,b,e-b); string[e-b] = 0; } else strcpy (string,b); if (*string) { #ifdef DEBUG printf ("found word \"%s\" in line %d\n",string,line_count); #endif w.name = string; if (match = (struct word *) bsearch (&w,word_list,word_list_count,sizeof(struct word),compare_words)) { #ifdef DEBUG printf (" (this word is in the list)\n"); #endif token[token_count].code = match->code; strcpy (token[token_count].string,string); token[token_count].line_number = line_count; } else { #ifdef DEBUG printf (" (this word is not in the list)\n"); #endif token[token_count].code = WIdentifier; strcpy (token[token_count].string,string); token[token_count].line_number = line_count; } token_count++; } if (e) s = e; else s = b + strlen(b); break; } if (token_count >= token_limit) { #ifdef DEBUG printf ("trying to enlarge token from %d by %d\n",token_limit,GRANULARITY); #endif if (!(token = realloc (token,(token_limit + GRANULARITY)*sizeof(struct token)))) { sprintf (message,"Error: could not enlarge token array to %d elements",token_limit + GRANULARITY); error_exit (message); } token_limit += GRANULARITY; #ifdef DEBUG printf ("token_limit = %d\n",token_limit); #endif } } } fclose (in); } else { sprintf (message,"Error: could not open run description file %s",job_file); error_exit (message); } } static struct data_base *new_data_base (void) { struct data_base *p = NULL; if (p = (struct data_base *) malloc (sizeof (struct data_base))) { p->next = NULL; p->count = 0; p->limit = 0; p->sample = NULL; *p->raw.filespec = 0; *p->raw.format = 0; p->raw.count = 0; p->raw.name = NULL; *p->rule.filespec = 0; p->rule.count = 0; p->rule.name = NULL; p->data.count = 0; p->data.name = NULL; *p->meta.filespec = 0; *p->meta.format = 0; p->meta.count = 0; p->meta.name = 0; } else { sprintf (message,"Error: could not allocate space for modern data base"); error_exit (message); } return (p); } static int increment (int i) { i++; if (i >= token_count) { sprintf (message,"Error: unexpected end of run description file"); error_exit (message); } return (i); } void parse_run_configuration (char *job_file) { int i; struct data_base *p; int number; char *s; find_tokens (job_file); i = 0; while (i < token_count) { switch (token[i].code) { /*----------------------------------------------------------*\ | basis { | | data file_name: format_description | | transform file_name | | meta file_name: format_description | | } | \*----------------------------------------------------------*/ case Wbasis: i = increment (i); if (token[i].code == WLBrace) { i = increment (i); if (modern) { for (p=modern; p->next; p=p->next); p->next = new_data_base(); p = p->next; } else p = modern = new_data_base(); while (token[i].code != WRBrace) { switch (token[i].code) { /*------------------------------------------*\ | data file_name: format_description | \*------------------------------------------*/ case Wdata: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->raw.filespec,token[i].string); i = increment (i); /*----------------------------------*\ | Colon indicates the presence of | | the optional format description. | \*----------------------------------*/ if (token[i].code == WColon) { i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->raw.format,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected format description, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } } } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | transform file_name | \*------------------------------------------*/ case Wtransform: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->rule.filespec,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | meta file_name: format_description | \*------------------------------------------*/ case Wmeta: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->meta.filespec,token[i].string); i = increment (i); /*----------------------------------*\ | Colon indicates the presence of | | the optional format description. | \*----------------------------------*/ if (token[i].code == WColon) { i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->meta.format,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected format description, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } } } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | } | \*------------------------------------------*/ case WRBrace: break; /*------------------------------------------*\ | Anything else is an error | \*------------------------------------------*/ default: sprintf (message,"Error: unexpected \"%s\" in line %d of %s",token[i].string,token[i].line_number,job_file); error_exit (message); break; } } } else { sprintf (message,"Error: expected '{', got \"%s\" on line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } if (token[i].code == WRBrace) i++; break; /*----------------------------------------------------------*\ | sample { | | data file_name: format_description | | transform file_name | | meta file_name: format_description | | } | \*----------------------------------------------------------*/ case Wsample: i = increment (i); if (token[i].code == WLBrace) { i = increment (i); if (fossil) { for (p=fossil; p->next; p=p->next); p->next = new_data_base(); p = p->next; } else p = fossil = new_data_base(); while (token[i].code != WRBrace) { switch (token[i].code) { /*------------------------------------------*\ | data file_name: format_description | \*------------------------------------------*/ case Wdata: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->raw.filespec,token[i].string); i = increment (i); /*----------------------------------*\ | Colon indicates the presence of | | the optional format description. | \*----------------------------------*/ if (token[i].code == WColon) { i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->raw.format,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected format description, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } } } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | transform file_name | \*------------------------------------------*/ case Wtransform: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->rule.filespec,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | meta file_name: format_description | \*------------------------------------------*/ case Wmeta: i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->meta.filespec,token[i].string); i = increment (i); /*----------------------------------*\ | Colon indicates the presence of | | the optional format description. | \*----------------------------------*/ if (token[i].code == WColon) { i = increment (i); if (token[i].code == WIdentifier) { strcpy (p->meta.format,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected format description, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } } } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | } | \*------------------------------------------*/ case WRBrace: break; /*------------------------------------------*\ | Anything else is an error | \*------------------------------------------*/ default: sprintf (message,"Error: unexpected \"%s\" in line %d of %s",token[i].string,token[i].line_number,job_file); error_exit (message); break; } } } else { sprintf (message,"Error: expected '{', got \"%s\" on line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } if (token[i].code == WRBrace) i++; break; /*----------------------------------------------------------*\ | distance distance_measure | \*----------------------------------------------------------*/ case Wdistance: i = increment (i); if (token[i].code == WIdentifier) { strcpy (distance_measure_name,token[i].string); i++; } else { sprintf (message,"Error: expected distance measure, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*----------------------------------------------------------*\ | verbose | \*----------------------------------------------------------*/ case Wverbose: verbose = 1; i++; break; /*----------------------------------------------------------*\ | report { | | name file_name: format_description | | closest number | | meta variable_name | | } | \*----------------------------------------------------------*/ case Wreport: i = increment (i); if (token[i].code == WLBrace) { i = increment (i); while (token[i].code != WRBrace) { switch (token[i].code) { /*------------------------------------------*\ | name file_name: format_description | \*------------------------------------------*/ case Wname: i = increment (i); if (token[i].code == WIdentifier) { strcpy (report.filespec,token[i].string); i = increment (i); /*----------------------------------*\ | Colon indicates the presence of | | the optional format description. | \*----------------------------------*/ if (token[i].code == WColon) { i = increment (i); if (token[i].code == WIdentifier) { strcpy (report.format,token[i].string); i = increment (i); } else { sprintf (message,"Error: expected format description, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } } } else { sprintf (message,"Error: expected file name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | closest | \*------------------------------------------*/ case Wclosest: i = increment (i); if (token[i].code == WIdentifier) { s = NULL; number = strtol (token[i].string,&s,0); if (s == token[i].string) { sprintf (message,"Error: expected number, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } else report.closest = number; i = increment (i); } else { sprintf (message,"Error: expected number, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | meta variable_name or "all" | \*------------------------------------------*/ case Wmeta: i = increment (i); if (token[i].code == WIdentifier) { if (!report.name) if (report.name = (char **) malloc (GRANULARITY * sizeof (char *))) report.limit = GRANULARITY; else { sprintf (message,"Error: could not allocate space for output meta data names"); error_exit (message); } if (s = (char *) malloc (1 + strlen (token[i].string))) { strcpy (s,token[i].string); i = increment (i); report.name[report.count] = s; /*------------------------------*\ | User must substitute '_' for | | ' ' in variable names given | | in the run configuration. | \*------------------------------*/ while (*s) { if (*s == '_') *s = ' '; s++; } report.count++; if (report.count == report.limit) if (report.name = (char **) realloc (report.name,(report.limit + GRANULARITY) * sizeof (char *))) report.limit += GRANULARITY; else { sprintf (message,"Error: could not enlarge space for output meta data names"); error_exit (message); } } } else { sprintf (message,"Error: expected meta data variable name, got \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } break; /*------------------------------------------*\ | } | \*------------------------------------------*/ case WRBrace: break; /*------------------------------------------*\ | Anything else is an error | \*------------------------------------------*/ default: sprintf (message,"Error: unexpected \"%s\" in line %d of %s",token[i].string,token[i].line_number,job_file); error_exit (message); break; } } } else { sprintf (message,"Error: expected '{', got \"%s\" on line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); } if (token[i].code == WRBrace) i++; break; default: sprintf (message,"Error: unexpected \"%s\" in line %d of %s", token[i].string, token[i].line_number, job_file ); error_exit (message); break; } } if (token) free (token); } /*----------------------------------------------------------------------*\ \*----------------------------------------------------------------------*/