/* next_string() reads the header file and returns the next NON-COMMENT */ /* string in the file, or NULL if end-of-file is reached */ /* *f is the file pointer for the header file */ char *next_string(f) FILE *f; { int num_fields; /* number of fields read & assigned by fscanf() */ static char instring[256]; /* buffer for fscanf() */ /* WARNING: While INSTRING is declared as a local variable, its */ /* actual scope is more global. INSTRING is declared STATIC */ /* because it is accessed by other functions via the STRING */ /* pointer. The contents of INSTRING must remain valid beyond */ /* the life of the next_string() call. */ char *string; /* pointer to INSTRING */ num_fields=fscanf(f,"%s",instring); string=instring; /* throw away the comments */ if(!strncmp("/*", string, 2)) { do { num_fields=fscanf(f,"%s",string); } while( strncmp("*/",&string[strlen(string)-2],2) && (num_fields != EOF)); /* get the next string after the close of the comment */ /* to return. Make sure that the next string is not also */ /* a comment by using the recursive call */ string=next_string(f); } if(num_fields==EOF) string=NULL; return(string); } Listing 1: The main parsing function of h_filter. ACUITY_H acuity.h ACUITY_SCALE_FACTOR acuity.h CORRECT acuity.h DATAFILE acuity.h LARGER acuity.h NEW_SIZE acuity.h NO_RESPONSE acuity.h SEARCH acuity.h SMALLER acuity.h STDOUT acuity.h STDPRN acuity.h TARG_DOWN acuity.h TARG_LEFT acuity.h TARG_RIGHT acuity.h TARG_UP acuity.h TRACK acuity.h VERTICAL_DASH acuity.h WRONG acuity.h Table 1: Sample output of h_filter. AB_END acu_menu.h ABS itex100.h ABSOLUTE itex100.h ACU_MENU_H acu_menu.h ACUITY_ARRAY_SIZE acu_menu.h ACUITY_H acuity.h ACUITY_SCALE_FACTOR acuity.h AD_IN dt2808.h ADD itex100.h ALLOCATION_ERROR itex100.h ALT keys.h AND itex100.h ANSI_H ansi.h ANY_BUTTON cont_lib.h aslope scotoma.h AUTO_PAUSE scotoma.h Table 2: Fragment of sample output from h_merge, including the 'a' entries from table 1. /* h_filter.c is a utility for extracting names of #define'd constants */ /* and macros, structs, unions, and typedefs from a header file and */ /* creating an alphabetical listing file of the names, like this: */ /* NAME HEADER.H filename, one entry per line in the file. */ /* All header.h filename entries are the same in the output file */ /* The output file can be used to create a cross-reference list of */ /* header file names for a library by combining the appropriate */ /* alphabetical lists using h_merge.c, a companion utility. */ /* */ /* WARNING: h_filter.c uses a simplified version of C grammar, in */ /* which comment delimiters and keywords are assumed to be preceded */ /* and followed by either a space or a newline. Valid C code will not */ /* necessarily be parsed properly. Further, it is assumed that all */ /* struct and union definitions have names, i.e., struct {int a;char b;}c; */ /* will be viewed as having the name "int". */ /* */ /* Written by T. Clune 8/88. Copyright (c) 1988, Eye Research Institute */ /* Boston, MA. Permission is granted to individuals to use this utility */ /* for noncommercial applications. All commercial rights are reserved. */ /* Known MS C-specific aspects of this program are: use of process.h header */ /* file to decalre exit() and use of strcmpi(), which is a Microsoft function */ /* like strcmp() except that the string comparison is case-insensitive. A */ /* usable substitute for strcmpi() is available in my file strcmpi.c. */ #include #include /* MS C header that declares exit() */ #include #include #include #include #define MAXPTRS 500 /* max number of names supported from the .h file */ #define PATH_CHAR '\\' /* path delimiter in MS-DOS */ #define DRIVE_CHAR ':' /* drive designator in MS-DOS */ static char *ptr[MAXPTRS]; /* ptrs to names of definitions in .h file */ static int numptrs; /* the number of names that are actually in the file */ char * next_string(); char * lose_braces(); void extract_names(), put_name(); void make_list(); int compare(); /* main() Usage: h_filter foo.h bar.srt, */ /* where FOO.H is the name of the header file to work on */ /* and BAR.SRT is the alphabetically-sorted list of FOO.H defined names. */ main(argc, argv) int argc; char *argv[]; { FILE *f; numptrs=0; /* initialize number of names variable */ if(argc != 3) { printf("Usage: %s foo.h bar.srt,\n", argv[0]); printf("\twhere FOO.H is the name of the header file to work on,\n"); printf("\t and BAR.SRT is the alphabetically-sorted list of FOO.H defined names,\n"); exit(-1); } if((f=fopen(argv[1], "r"))==NULL) { printf("Unable to open %s\n", argv[1]); exit(-1); } extract_names(f); fclose(f); make_list(argv[1], argv[2]); } /* compare() is the function for qsort() comparisons in make_list() */ int compare(a, b) char **a, **b; { return(strcmpi(*a, *b)); } /* extract_names() parses the header file, throwing away everything except */ /* #define, struct, union, or typedef names, and sends the names to put_names() */ /* for storage in malloc()ed space. *f is the file pointer for the header file */ void extract_names(f) FILE *f; { char *string, oldstring[256], *str_ptr; do { string=next_string(f); /* get the names that immediately follow a keyword */ /* (i.e., #define name, struct name, or union name) */ if(!strcmp("#define", string)) { string=next_string(f); put_name(string); } /* get the '# define' names */ if(!strcmp("#", string)) { string=next_string(f); if(!strcmp("define", string)) { string=next_string(f); put_name(string); } } /* get struct or union name and throw away the braces */ if( (!strcmp("struct", string)) || (!strcmp("union", string)) ) { string=next_string(f); put_name(string); /* it's either 'struct name{' */ if(str_ptr=strchr(string, '{')) string=lose_braces(f, str_ptr); else { /* or 'struct name {' */ string=next_string(f); string=lose_braces(f, string); } } /* for typedefs, the name is the last thing before ';' */ /* i.e., typedef identifier {...} name; */ if(!strcmp("typedef", string)) { for(;;) { string=next_string(f); if(str_ptr=strchr(string, '{')) string=lose_braces(f, str_ptr); /* the end of the typedef condition */ if(str_ptr=strrchr(string,';')) { /* this selects between 'name ;' and 'name; ' */ /* if the former, the previous string had the name */ *str_ptr='\0'; if(strlen(string)) put_name(string); else put_name(oldstring); break; } strcpy(oldstring, string); } } }while(string != NULL); } /* lose_braces() throws away everything between the braces of a struct, */ /* union, or typedef, so that ' struct a{ struct b; union c;};' does not */ /* cause 'b' or 'c' to be listed as defined in this header. */ /* *f is the file pointer for the header file and *str_ptr is the string to */ /* work on. lose_braces() returns the last string it was working on */ char * lose_braces(f, str_ptr) FILE *f; char *str_ptr; { char *string; /* copy of str_ptr while working */ int level=0; /* level of braces counter for typedefs */ string=str_ptr; do { /* count the braces */ while(str_ptr=strchr(str_ptr,'{')) { str_ptr++; level++; } str_ptr=string; while(str_ptr=strchr(str_ptr,'}')) { str_ptr++; level--; } if(level) { string=next_string(f); str_ptr=string; } }while(level); return(string); } /* make_list() sorts and copies the names list to the output file, eliminating */ /* duplication and labeling each name as having come from the specified .h file */ /* hfile is the header file filespec, ofile is the output file filespec. */ void make_list(hfile, ofile) char *hfile, *ofile; { char oldname[256]; char *str_ptr; int i,j; FILE *f; if((f=fopen(ofile, "w"))==NULL) { printf("Unable to open %s\n", ofile); exit(-1); } /* strip out the path of the .h file name */ if(str_ptr=strrchr(hfile, PATH_CHAR)) hfile=str_ptr+1; else if(str_ptr=strrchr(hfile, DRIVE_CHAR)) hfile=str_ptr+1; /* sort the name pointers alphabetically */ qsort(ptr, (unsigned)numptrs, sizeof(char *), compare); oldname[0]='\0'; for(j=0;j=j) || (isalnum(*(string+i))) || (*(string+i) == '_'))) i++; if(i=MAXPTRS) { printf("File has too many names for this program.\n"); exit(-1); } } /* h_merge.c merges two alphabetically-ordered text files. Used with */ /* h_filter.c to build a cross-reference listing of a library's header */ /* files. Written by T. Clune 8/88. Copyright (c) 1988, Eye Research */ /* Institute, Boston MA. No rights reserved. */ /* See h_filter.c for comments on MS C dependencies */ #include #include /* MS C exit() declaration header */ #include void merge_list(); /* main() Usage: h_merge a.srt b.srt c.srt, */ /* where a.srt and b.srt are sorted files to be merged, */ /* and c.srt is the name for the output file. */ main(argc, argv) int argc; char *argv[]; { if(argc != 4) { printf("Usage: %s a.srt b.srt c.srt,\n", argv[0]); printf("\twhere a.srt and b.srt are sorted files to be merged,\n"); printf("\tand c.srt is the name for the output file\n"); exit(-1); } merge_list(argv[1], argv[2], argv[3]); } /* merge_list() merges the alphabetically-sorted FIRSTFILE and SECONDFILE */ /* and places the results in OUTFILE */ /* FIRSTFILE, SECONDFILE, and OUTFILE are the respective filespec strings */ void merge_list(firstfile, secondfile, outfile) char *firstfile, *secondfile, *outfile; { FILE *ff, *sf, *of; /* file pointers for firstfile, secondfile, outfile */ char f_string[256], s_string[256]; /* the active lines for interleaving */ char *f_end, *s_end; /* go to NULL when EOF for firstfile or secondfile */ int i; if((of=fopen(outfile, "w"))==NULL) { printf("Unable to open %s\n", outfile); exit(-1); } if((ff=fopen(firstfile, "r"))==NULL) { printf("Error opening %s\n", firstfile); exit(-1); } if((sf=fopen(secondfile, "r"))==NULL) { printf("Unable to open %s\n", secondfile); exit(-1); } /* prime the pump */ f_end=fgets(f_string, 256, ff); s_end=fgets(s_string, 256, sf); for(;;) { /* when one file is empty, just copy the other to output */ if(f_end==NULL) { while(s_end != NULL) { fprintf(of, "%s", s_string); s_end=fgets(s_string, 256, sf); } break; } else { if(s_end==NULL) { while(f_end != NULL) { fprintf(of,"%s",f_string); f_end=fgets(f_string, 256, ff); } break; } } /* compare the next entry from FIRST and SECOND. The alphabetically */ /* prior entry gets put to output, and a new entry is read */ i=strcmpi(f_string, s_string); if(i<0) { fprintf(of,"%s",f_string); f_end=fgets(f_string, 256, ff); } else { fprintf(of,"%s",s_string); s_end=fgets(s_string, 256, sf); } } fclose(ff); fclose(sf); fclose(of); }