home *** CD-ROM | disk | FTP | other *** search
- /*###########################################################################
- *
- * 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 <stdio.h>
- #include <ctype.h>
-
- #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() */
-
-
-