1: # include "lmanifest" 2: # include "manifest" 3: 4: # define USED 01 5: # define VUSED 02 6: # define EUSED 04 7: # define RVAL 010 8: # define VARARGS 0100 9: 10: typedef struct { TWORD aty; int extra; } atype; 11: 12: struct line { 13: char name[8]; 14: int decflag; 15: atype type; 16: int nargs; 17: atype atyp[50]; 18: int fline; 19: char file[100]; 20: } 21: 22: l1, 23: l2, 24: *pd, /* pointer to line having definition */ 25: *pc, /* pointer to current line read */ 26: *p3; /* used for swapping pc and pd */ 27: 28: int uses = USED; 29: int hflag = 0; 30: int pflag = 0; 31: int xflag = 0; 32: int uflag = 1; 33: 34: 35: main( argc, argv ) char *argv[]; { 36: 37: register char *p; 38: 39: /* first argument is - options */ 40: 41: if( argc>=2 && argv[1][0] == '-' ){ 42: for( p=argv[1]; *p; ++p ){ 43: switch( *p ){ 44: 45: case 'h': 46: hflag = 1; 47: break; 48: 49: case 'p': 50: pflag = 1; 51: break; 52: 53: case 'x': 54: xflag = 1; 55: break; 56: 57: case 'u': 58: uflag = 0; 59: break; 60: 61: } 62: } 63: } 64: 65: 66: 67: pd = &l1; 68: pc = &l2; 69: pd->name[0] = '\0' ; 70: pd->fline = 0; 71: pd->file[0] = '\0'; 72: pd->decflag = LDI; 73: 74: /* main loop: read a line; 75: if same as last line, check compatibility 76: if not same as last line, becomes df. 77: */ 78: 79: for(;;){ 80: lread(); 81: if( steq(pc->name, pd->name) ) chkcompat(); 82: else { 83: lastone(); 84: setuse(); 85: p3=pc; 86: pc = pd; 87: pd = p3; 88: } 89: } 90: 91: } 92: 93: lread(){ /* read a line into pc */ 94: 95: register i, n; 96: 97: getnam( pc->name ); 98: 99: pc->decflag = rdin10(); 100: rdinty( &pc->type ); 101: n = pc->nargs = rdin10(); 102: if( n<0 ) n = -n; 103: 104: for( i=0; i<n; ++i ){ 105: rdinty( &pc->atyp[i] ); 106: } 107: 108: getnam( pc->file ); 109: pc->fline = rdin10(); 110: 111: while( getchar() != '\n' ) ; /* VOID */ 112: } 113: 114: rdin10(){ 115: register val, c, s; 116: 117: val = 0; 118: s = 1; 119: 120: while( (c=getchar()) != '\t' ){ 121: if( c <= 0 ) error( "unexpected EOF" ); 122: else if( c == '-' ) { 123: s = -1; 124: continue; 125: } 126: else if( c<'0' || c>'9' ) { 127: error("rotten digit: %o\n", c ); 128: } 129: val = val*10 + c - '0'; 130: } 131: return( val*s ); 132: } 133: 134: rdinty( p ) atype *p; { 135: register val, c, s; 136: 137: val = 0; 138: s = 1; 139: 140: while( (c=getchar()) != '\t' && c!= '<' ){ 141: if( c <= 0 ) error( "unexpected EOF" ); 142: else if( c == '-' ) { 143: s = -1; 144: continue; 145: } 146: else if( c<'0' || c>'7' ) { 147: error("rotten digit: %o\n", c ); 148: } 149: val = (val<<3) + c - '0'; 150: } 151: p->aty = val*s; 152: if( c == '<' ) p->extra = rdin10(); 153: else p->extra = 0; 154: } 155: 156: getnam(p) char *p; { 157: register c; 158: while( (c=getchar()) != '\t' ){ 159: if( c == '\n' ) error( "rotten name\n" ); 160: if( c <= 0 ) cleanup(); 161: *p++ = c; 162: } 163: *p = '\0'; 164: } 165: 166: /* VARARGS */ 167: error( s, a ) char *s; { 168: 169: fprintf( stderr, "pass 2 error: " ); 170: fprintf( stderr, s, a ); 171: fprintf( stderr, "\n" ); 172: exit(1); 173: } 174: 175: steq(p,q) char *p,*q; { /* check that the p and q names are the same */ 176: 177: 178: while( *p == *q ){ 179: if( *p == 0 ) return(1); 180: ++p; 181: ++q; 182: } 183: 184: return(0); 185: } 186: 187: chkcompat(){ 188: /* are the types, etc. in pc and pd compatible */ 189: register int i; 190: 191: setuse(); 192: 193: /* argument check */ 194: 195: if( pd->decflag & (LDI|LIB|LUV|LUE) ){ 196: if( pc->decflag & (LUV|LIB|LUE) ){ 197: if( pd->nargs != pc->nargs ){ 198: if( !(uses&VARARGS) ){ 199: printf( "%.7s: variable # of args.", pd->name ); 200: viceversa(); 201: } 202: if( pc->nargs > pd->nargs ) pc->nargs = pd->nargs; 203: if( !(pd->decflag & (LDI|LIB) ) ) { 204: pd->nargs = pc->nargs; 205: uses |= VARARGS; 206: } 207: } 208: for( i=0; i<pc->nargs; ++i ){ 209: if( chktype(&pd->atyp[i], &pc->atyp[i]) ){ 210: printf( "%.7s, arg. %d used inconsistently", 211: pd->name, i+1 ); 212: viceversa(); 213: } 214: } 215: } 216: } 217: 218: if( (pd->decflag&(LDI|LIB|LUV)) && pc->decflag==LUV ){ 219: if( chktype( &pc->type, &pd->type ) ){ 220: printf( "%.7s value used inconsistently", pd->name ); 221: viceversa(); 222: } 223: } 224: 225: /* check for multiple declaration */ 226: 227: if( (pd->decflag&LDI) && (pc->decflag&(LDI|LIB)) ){ 228: printf( "%.7s multiply declared", pd->name ); 229: viceversa(); 230: } 231: 232: /* do a bit of checking of definitions and uses... */ 233: 234: if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & (LDX|LDC)) && pd->type.aty != pc->type.aty ){ 235: printf( "%.7s value declared inconsistently", pd->name ); 236: viceversa(); 237: } 238: 239: /* better not call functions which are declared to be structure or union returning */ 240: 241: if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & LUE) && pd->type.aty != pc->type.aty ){ 242: /* only matters if the function returns union or structure */ 243: TWORD ty; 244: ty = pd->type.aty; 245: if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){ 246: printf( "%.7s function value type must be declared before use", pd->name ); 247: viceversa(); 248: } 249: } 250: 251: if( pflag && pd->decflag==LDX && pc->decflag == LUM && !ISFTN(pd->type.aty) ){ 252: /* make the external declaration go away */ 253: /* in effect, it was used without being defined */ 254: 255: /* swap pc and pd */ 256: p3 = pc; 257: pc = pd; 258: pd = p3; 259: } 260: 261: } 262: 263: viceversa(){ 264: /* print out file comparison */ 265: printf( " %s(%d) :: %s(%d)\n", pd->file, pd->fline, pc->file, pc->fline ); 266: } 267: 268: /* messages for defintion/use */ 269: char * 270: mess[2][2] = { 271: "", 272: "%.7s used( %s(%d) ), but not defined\n", 273: "%.7s defined( %s(%d) ), but never used\n", 274: "%.7s declared( %s(%d) ), but never used or defined\n" 275: }; 276: 277: lastone(){ 278: 279: /* called when pc and pd are at last different */ 280: register nu, nd; 281: 282: nu = nd = 0; 283: 284: if( !(uses&USED) && pd->decflag != LIB ) { 285: if( !steq(pd->name,"main") ) 286: nu = 1; 287: } 288: 289: if( !ISFTN(pd->type.aty) ){ 290: switch( pd->decflag ){ 291: 292: case LIB: 293: nu = nd = 0; /* don't complain about uses on libraries */ 294: break; 295: case LDX: 296: if( !xflag ) break; 297: case LUV: 298: case LUE: 299: case LUM: 300: nd = 1; 301: } 302: } 303: 304: if( uflag && ( nu || nd ) ) printf( mess[nu][nd], pd->name, pd->file, pd->fline ); 305: 306: if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){ 307: printf( "%.7s returns value which is %s ignored\n", pd->name, 308: uses&VUSED ? "sometimes" : "always" ); 309: } 310: 311: if( (uses&(RVAL+VUSED)) == (VUSED) && (pd->decflag&(LDI|LIB)) ){ 312: printf( "%.7s value is used, but none returned\n", pd->name ); 313: } 314: 315: /* clean up pc, in preparation for the next thing */ 316: 317: uses = 0; 318: if( pc->nargs < 0 ){ 319: pc->nargs = -pc->nargs; 320: uses = VARARGS; 321: } 322: 323: } 324: 325: cleanup(){ /* call lastone and die gracefully */ 326: lastone(); 327: exit(0); 328: } 329: 330: setuse(){ /* check new type to ensure that it is used */ 331: 332: switch( pc->decflag ){ 333: 334: case LRV: 335: uses |= RVAL; 336: return; 337: case LUV: 338: uses |= VUSED+USED; 339: return; 340: case LUE: 341: uses |= EUSED+USED; 342: return; 343: case LUM: 344: uses |= USED; 345: return; 346: 347: } 348: } 349: 350: chktype( pt1, pt2 ) register atype *pt1, *pt2; { 351: 352: /* check the two type words to see if they are compatible */ 353: /* for the moment, enums are turned into ints, and should be checked as such */ 354: if( pt1->aty == ENUMTY ) pt1->aty = INT; 355: if( pt2->aty == ENUMTY ) pt2->aty = INT; 356: 357: if( pt2->extra ){ /* constant passed in */ 358: if( pt1->aty == UNSIGNED && pt2->aty == INT ) return( 0 ); 359: else if( pt1->aty == ULONG && pt2->aty == LONG ) return( 0 ); 360: } 361: else if( pt1->extra ){ /* for symmetry */ 362: if( pt2->aty == UNSIGNED && pt1->aty == INT ) return( 0 ); 363: else if( pt2->aty == ULONG && pt1->aty == LONG ) return( 0 ); 364: } 365: 366: return( pt1->aty != pt2->aty ); 367: }