/*########################################################################### * * This program is used to find those pesty errors in varags type * functions such as printf. It only handles those functions defined * in the structure"fu". * * By Daniel B. Suthers Mar 3, 1988 * * Copyright 1988 by Daniel B. Suthers, Concord, California, USA. * License is granted to distribute this program at will, as long as * the source is also provided free of charge to anyone who recieves * the binaries, or to anyone who wants it, * AND all copyright notices are left intact. * The * ###move $This_File 755 uprog none /uprog/bin/src/varlint.c ##move $This_File 755 uprog none /usr/uprog/src/bin/varlint.c *#########################################################################*/ #include #include #define VER "2.7" #define MAX 512 #define NUMNAMES 6 #ifdef pdp11 char APPL[] ="\n##move $This_File 755 uprog none /usr/uprog/bin/varlint\n"; #else char APPL[]="\n###move $This_File 755 uprog none /usr/lbin/varlint\n"; FILE *fopen(); void scandoos(); #endif struct funcdat{ char nam[9]; /* stores function names*/ int len; /* number of chars in names*/ int pos; /* position of control string*/ int scan; }; struct funcdat fu[ NUMNAMES] = { { "printf", 6, 0, 0}, { "scanf", 5, 0, 1}, { "sprintf", 7,1, 0}, { "sscanf", 6, 1, 1}, { "fprintf", 7,1, 0}, { "fscanf", 6, 1, 1} }; char *fgets(), *findname(); int in_comment = 0; /* flag = 1 when in a comment*/ main(argc, argv, env) int argc; char *argv[], *env[]; { extern int optind; extern char *optarg; register int inta; char filename[128]; FILE *infile ; while( (inta = getopt( argc, argv, "vVhH")) != EOF) { switch (inta) { case 'V': case 'v': fprintf (stderr, "%s\n" , VER); return(0); case 'h': case 'H': help(); return(0); default: printf("Bad argument\nTry -h for help.\n"); return(1); } } while( optind < argc ) /* these would be files*/ { strcpy(filename, argv[optind++]); if( (infile = fopen(filename, "r") ) == NULL) { fprintf(stderr, "Unable to open source file %s\n", filename); } else { printf("Working on %s\n", filename); scandoos(infile); if( infile != (FILE *) NULL) fclose(infile); } } return(0); } /*end of main*/ help() { printf( "\n\tCopyright 1988 by Daniel B. Suthers, Concord, California, USA.\n"); printf( "\tLicense is granted to distribute this program at will, as long as\n"); printf( "\tthe source is also provided free of charge to anyone who recieves\n"); printf("\tthe binaries, or to anyone who wants it,\n"); printf("\tAND all copyright notices are left intact.\n"); printf("\n\tThis program checks for mismatched arguments in functions\n"); printf("\tthat accept variable arguments ala printf().\n"); printf("\tCurrently supports: printf, scanf and their cousins.\n"); printf("\t(Checks only for # of args and & for integers)\n"); printf("\n\tThe arguments accepted are:\n\n"); printf("\t-v\tPrint the version number and exit.\n"); printf("\t-help\tPrint the most current help.\n"); return(0); } #ifdef u3b5 void #endif scandoos(infile) FILE *infile; { register int linenum, reterr, oldline; char buff[MAX*3], *buffp; /* allow 10 lines */ char tempstr[MAX*3]; int funcindex; linenum = oldline = 0; reterr = 0; while( fgets(buff, MAX, infile) != (char *)NULL ) { if(reterr == 100 ) /* multi line statement */ { if( oldline == 0) oldline = linenum; strcat(tempstr,buff); strcpy(buff, tempstr); reterr = 0; } linenum++; if( (buffp = findname(buff,&funcindex)) == NULL ) continue; if( in_comment ) continue; /* printf("%4d: %s",linenum, buffp); */ if( (reterr = parsedo(buffp,funcindex)) > 0) { if( reterr < 100 ) { if( oldline != 0) { printf("***** Error at line %5d\n%s", oldline, buffp); oldline = 0; } else printf("***** Error at line %5d\n%s", linenum, buffp); } switch(reterr) { case 1: printf("More \"%%\" in control string than there are variables.\n\n"); break; case 2: printf("A varible type did not match the \"%%\".\n\n"); break; case 3: printf("An undefined variable used.\n\n"); break; case 4: printf("An un-recognized construct, might be ok.\n\n"); break; case 5: printf("Fewer \"%%\" in control string than there are variables.\n\n"); break; case 6: printf("Integer type requires an ampersand (\&).\n\n"); break; case 7: printf("Print found a string, expecting an int.\n\n"); break; case 8: printf("Unknown %% specifier.\n\n"); break; case 9: printf("Re declaration of the function. You sure this is ok?\n\n"); break; case 10: printf("Null control string. You sure this is ok?\n\n"); break; case 100: strcpy( tempstr, buff); break; } } /* end of if(parsedo) */ else oldline = 0; } } /* end of scandoos() */ char * findname(string, funcind) char string[]; int *funcind; { char *ptr; register int a; ptr = string; while( *ptr != NULL ) { if( *ptr == '/') /* set flag if this */ if( *(ptr + 1) == '*') /* is start of comment*/ { in_comment = 1; ptr += 2; continue; } if( *ptr == '*' ) /* un-set flag if end */ if( *(ptr+1) == '/') /* of comment */ { in_comment = 0; ptr +=2; continue; } for( a = 0; a < NUMNAMES; a++) { if( strncmp( ptr, fu[a].nam, fu[a].len ) == 0 ) { *funcind = a; return(ptr); } } ptr++; } return(NULL); } int parsedo(buff, fi) char buff[]; /* function string */ int fi; /* fu.[] index */ { register int parens, pcntnum, c; char *buffp; int end=0, inquotes = 0; int vartype[124]; /* for var type */ parens = 0; buffp = buff; buffp += fu[fi].len; /* get past function */ while( isspace(*buffp) ) /* skip white space */ buffp++; if( *buffp == NULL) return(100); if( *buffp != '(' ) /* not a function */ return(0); if( *(buffp +1) == ')' ) /* function definition */ return(9); buffp++; while( isspace(*buffp) ) /* skip white space */ buffp++; if( *buffp == NULL) return(100); for(c = 0;c < fu[fi].pos; c++) /* skip to control string*/ { /* (stop on comma) */ while( (*buffp != NULL) && (*buffp != ',') ) buffp++; if( *buffp == NULL) return(100); buffp++; } if( *buffp == NULL) return(100); while( isspace( *(buffp)) ) /* for ' , "test"' */ buffp++; if( *buffp == NULL) return(100); if( *buffp != '"') /* should be on first quote*/ return(4); if( *(buffp+1) == '"') /* dont want "" as cntl str */ return(10); /* count the percent signs */ /* starting on first quote */ pcntnum = 0; end = 0; while( *buffp++ != NULL ) { switch(*buffp) { case '"': if( *(buffp-1) != '\\') /* \" is not end */ end = 1; else if( *(buffp-2) == '\\') /* \\" is end */ end = 1; break; case '%': if( *(buffp-1) != '%') pcntnum++; else { pcntnum--; /* delete first % of pair */ continue; } if( *(buffp+1) == '*' ) { if( fu[fi].scan == 1) { pcntnum--; /* no matching variable */ } else { pcntnum++; } } /*###################### # load array with var type ######################*/ /* throw away justification*/ if( *(buffp +1 ) == '-' || *(buffp +1) == '+') buffp++; /* remove blanks and sharps */ while( isspace( *(buffp + 1)) || *(buffp + 1) == '#' ) buffp++; /* throw away size spec */ while( isdigit(*(buffp+1)) || *(buffp+1) == '.' ) buffp++; switch (*(buffp + 1) ) /* look at next char for type */ { case 's': case '[': case 'c': vartype[pcntnum] = 's'; break; case 'd': case 'l': case 'h': case 'i': case 'o': case 'x': case 'u': case 'f': case 'e': case 'g': vartype[pcntnum] = 'i'; break; case '%': /* no action */ case '*': break; default: printf("error at %s\n\n", buffp + 1); return(8); break; } break; } if( end ) break; } parens = 0; inquotes = 1; /* start on last " */ c = 1; while( *buffp != NULL ) /* look for variables */ { switch( *buffp ) { case '(': parens--; break; case ')': parens++; break; case '"': /* for strings */ if( parens == 0) /* at the base level */ { if( *(buffp-1) != '\\' ) /* \" is not end of str */ { inquotes = !inquotes; } else if( *(buffp-2) == '\\') /* \\" is end */ inquotes = !inquotes; } break; case ',': if( parens == 0 && inquotes != 1) /* commas outside of func*/ { pcntnum --; buffp++; while( isspace(*buffp) ) buffp++; if( *buffp == NULL) return(100); if( fu[fi].scan == 1 ) { if( vartype[c] == 'i' && *buffp != '\&' ) return(6); } else if( vartype[c] == 'i' && *buffp == '"') return(7); c++; continue; /* buffp already ++ */ } break; } if( parens == 1) /* hit end of function */ { if( pcntnum > 0 ) return(1); if( pcntnum < 0) return(5); return(0); } buffp++; } if( parens < 1 ) return(100); return(0); } /* end of parsedo() */