# include "lmanifest" # include "manifest" # define USED 01 # define VUSED 02 # define EUSED 04 # define RVAL 010 # define VARARGS 0100 typedef struct { TWORD aty; int extra; } atype; struct line { char name[8]; int decflag; atype type; int nargs; atype atyp[50]; int fline; char file[100]; } l1, l2, *pd, /* pointer to line having definition */ *pc, /* pointer to current line read */ *p3; /* used for swapping pc and pd */ int uses = USED; int hflag = 0; int pflag = 0; int xflag = 0; int uflag = 1; main( argc, argv ) char *argv[]; { register char *p; /* first argument is - options */ if( argc>=2 && argv[1][0] == '-' ){ for( p=argv[1]; *p; ++p ){ switch( *p ){ case 'h': hflag = 1; break; case 'p': pflag = 1; break; case 'x': xflag = 1; break; case 'u': uflag = 0; break; } } } pd = &l1; pc = &l2; pd->name[0] = '\0' ; pd->fline = 0; pd->file[0] = '\0'; pd->decflag = LDI; /* main loop: read a line; if same as last line, check compatibility if not same as last line, becomes df. */ for(;;){ lread(); if( steq(pc->name, pd->name) ) chkcompat(); else { lastone(); setuse(); p3=pc; pc = pd; pd = p3; } } } lread(){ /* read a line into pc */ register i, n; getnam( pc->name ); pc->decflag = rdin10(); rdinty( &pc->type ); n = pc->nargs = rdin10(); if( n<0 ) n = -n; for( i=0; iatyp[i] ); } getnam( pc->file ); pc->fline = rdin10(); while( getchar() != '\n' ) ; /* VOID */ } rdin10(){ register val, c, s; val = 0; s = 1; while( (c=getchar()) != '\t' ){ if( c <= 0 ) error( "unexpected EOF" ); else if( c == '-' ) { s = -1; continue; } else if( c<'0' || c>'9' ) { error("rotten digit: %o\n", c ); } val = val*10 + c - '0'; } return( val*s ); } rdinty( p ) atype *p; { register val, c, s; val = 0; s = 1; while( (c=getchar()) != '\t' && c!= '<' ){ if( c <= 0 ) error( "unexpected EOF" ); else if( c == '-' ) { s = -1; continue; } else if( c<'0' || c>'7' ) { error("rotten digit: %o\n", c ); } val = (val<<3) + c - '0'; } p->aty = val*s; if( c == '<' ) p->extra = rdin10(); else p->extra = 0; } getnam(p) char *p; { register c; while( (c=getchar()) != '\t' ){ if( c == '\n' ) error( "rotten name\n" ); if( c <= 0 ) cleanup(); *p++ = c; } *p = '\0'; } /* VARARGS */ error( s, a ) char *s; { fprintf( stderr, "pass 2 error: " ); fprintf( stderr, s, a ); fprintf( stderr, "\n" ); exit(1); } steq(p,q) char *p,*q; { /* check that the p and q names are the same */ while( *p == *q ){ if( *p == 0 ) return(1); ++p; ++q; } return(0); } chkcompat(){ /* are the types, etc. in pc and pd compatible */ register int i; setuse(); /* argument check */ if( pd->decflag & (LDI|LIB|LUV|LUE) ){ if( pc->decflag & (LUV|LIB|LUE) ){ if( pd->nargs != pc->nargs ){ if( !(uses&VARARGS) ){ printf( "%.7s: variable # of args.", pd->name ); viceversa(); } if( pc->nargs > pd->nargs ) pc->nargs = pd->nargs; if( !(pd->decflag & (LDI|LIB) ) ) { pd->nargs = pc->nargs; uses |= VARARGS; } } for( i=0; inargs; ++i ){ if( chktype(&pd->atyp[i], &pc->atyp[i]) ){ printf( "%.7s, arg. %d used inconsistently", pd->name, i+1 ); viceversa(); } } } } if( (pd->decflag&(LDI|LIB|LUV)) && pc->decflag==LUV ){ if( chktype( &pc->type, &pd->type ) ){ printf( "%.7s value used inconsistently", pd->name ); viceversa(); } } /* check for multiple declaration */ if( (pd->decflag&LDI) && (pc->decflag&(LDI|LIB)) ){ printf( "%.7s multiply declared", pd->name ); viceversa(); } /* do a bit of checking of definitions and uses... */ if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & (LDX|LDC)) && pd->type.aty != pc->type.aty ){ printf( "%.7s value declared inconsistently", pd->name ); viceversa(); } /* better not call functions which are declared to be structure or union returning */ if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & LUE) && pd->type.aty != pc->type.aty ){ /* only matters if the function returns union or structure */ TWORD ty; ty = pd->type.aty; if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){ printf( "%.7s function value type must be declared before use", pd->name ); viceversa(); } } if( pflag && pd->decflag==LDX && pc->decflag == LUM && !ISFTN(pd->type.aty) ){ /* make the external declaration go away */ /* in effect, it was used without being defined */ /* swap pc and pd */ p3 = pc; pc = pd; pd = p3; } } viceversa(){ /* print out file comparison */ printf( " %s(%d) :: %s(%d)\n", pd->file, pd->fline, pc->file, pc->fline ); } /* messages for defintion/use */ char * mess[2][2] = { "", "%.7s used( %s(%d) ), but not defined\n", "%.7s defined( %s(%d) ), but never used\n", "%.7s declared( %s(%d) ), but never used or defined\n" }; lastone(){ /* called when pc and pd are at last different */ register nu, nd; nu = nd = 0; if( !(uses&USED) && pd->decflag != LIB ) { if( !steq(pd->name,"main") ) nu = 1; } if( !ISFTN(pd->type.aty) ){ switch( pd->decflag ){ case LIB: nu = nd = 0; /* don't complain about uses on libraries */ break; case LDX: if( !xflag ) break; case LUV: case LUE: case LUM: nd = 1; } } if( uflag && ( nu || nd ) ) printf( mess[nu][nd], pd->name, pd->file, pd->fline ); if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){ printf( "%.7s returns value which is %s ignored\n", pd->name, uses&VUSED ? "sometimes" : "always" ); } if( (uses&(RVAL+VUSED)) == (VUSED) && (pd->decflag&(LDI|LIB)) ){ printf( "%.7s value is used, but none returned\n", pd->name ); } /* clean up pc, in preparation for the next thing */ uses = 0; if( pc->nargs < 0 ){ pc->nargs = -pc->nargs; uses = VARARGS; } } cleanup(){ /* call lastone and die gracefully */ lastone(); exit(0); } setuse(){ /* check new type to ensure that it is used */ switch( pc->decflag ){ case LRV: uses |= RVAL; return; case LUV: uses |= VUSED+USED; return; case LUE: uses |= EUSED+USED; return; case LUM: uses |= USED; return; } } chktype( pt1, pt2 ) register atype *pt1, *pt2; { /* check the two type words to see if they are compatible */ /* for the moment, enums are turned into ints, and should be checked as such */ if( pt1->aty == ENUMTY ) pt1->aty = INT; if( pt2->aty == ENUMTY ) pt2->aty = INT; if( pt2->extra ){ /* constant passed in */ if( pt1->aty == UNSIGNED && pt2->aty == INT ) return( 0 ); else if( pt1->aty == ULONG && pt2->aty == LONG ) return( 0 ); } else if( pt1->extra ){ /* for symmetry */ if( pt2->aty == UNSIGNED && pt1->aty == INT ) return( 0 ); else if( pt2->aty == ULONG && pt1->aty == LONG ) return( 0 ); } return( pt1->aty != pt2->aty ); }