|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)pc3.c 1.13 (Berkeley) 7/26/83"; ! 3: #endif ! 4: /* Copyright (c) 1980 Regents of the University of California */ ! 5: ! 6: /* ! 7: * Pc3 is a pass in the Berkeley Pascal compilation ! 8: * process that is performed just prior to linking Pascal ! 9: * object files. Its purpose is to enforce the rules of ! 10: * separate compilation for Berkeley Pascal. Pc3 is called ! 11: * with the same argument list of object files that is sent to ! 12: * the loader. These checks are performed by pc3 by examining ! 13: * the symbol tables of the object files: ! 14: * (1) All .o files must be up to date with respect to the ! 15: * runtime libraries. ! 16: * (2) Each global Pascal symbol (label, constant, type, ! 17: * variable, procedure, or function name) must be uniquely ! 18: * declared, i.e. declared in only one included file or ! 19: * source file. ! 20: * (3) Each external function (or procedure) may be resolved ! 21: * at most once in a source file which included the ! 22: * external declaration of the function. ! 23: * ! 24: * The symbol table of each object file is scanned and ! 25: * each global Pascal symbol is placed in a hashed symbol ! 26: * table. The Pascal compiler has been modified to emit all ! 27: * Pascal global symbols to the object file symbol table. The ! 28: * information stored in the symbol table for each such symbol ! 29: * is: ! 30: * ! 31: * - the name of the symbol; ! 32: * - a subtype descriptor; ! 33: * - the file which logically contains the declaration of ! 34: * the symbol or which caused the inclusion of an include file. ! 35: * - for included files: ! 36: * - a checksum; ! 37: * - for symbols: ! 38: * - the file which textually contains the declaration of ! 39: * the symbol (possibly an include file); ! 40: * - the line number at which the symbol is declared; ! 41: * - the file which contains the resolution of the symbol. ! 42: * - the line number at which the symbol is resolved; ! 43: * ! 44: * If a symbol has been previously entered into the symbol ! 45: * table, a check is made that the current declaration is of ! 46: * the same type and from the same include file as the previous ! 47: * one. Except for files and functions and procedures, it is ! 48: * an error for a symbol declaration to be encountered more ! 49: * than once, unless the re-declarations come from the same ! 50: * included file as the original. ! 51: * ! 52: * As an include file symbol is encountered in a source ! 53: * file, the symbol table entry of each symbol declared in that ! 54: * include file is modified to reflect its new logical ! 55: * inclusion in the source file. File symbols are also ! 56: * encountered as an included file ends, signaling the ! 57: * continuation of the enclosing file. ! 58: * ! 59: * Functions and procedures which have been declared ! 60: * external may be resolved by declarations from source files ! 61: * which included the external declaration of the function. ! 62: * Functions and procedures may be resolved at most once across ! 63: * a set of object files. The loader will complain if a ! 64: * function is not resolved at least once. ! 65: */ ! 66: ! 67: char program[] = "pc"; ! 68: ! 69: #include <sys/types.h> ! 70: #include <sys/stat.h> ! 71: #include <ar.h> ! 72: #include <stdio.h> ! 73: #include <ctype.h> ! 74: #include <a.out.h> ! 75: #include <stab.h> ! 76: #include "pstab.h" ! 77: #include "pc3.h" ! 78: ! 79: int errors = NONE; ! 80: BOOL wflag = FALSE; ! 81: ! 82: /* ! 83: * check each of the argument .o files (or archives of .o files). ! 84: */ ! 85: main( argc , argv ) ! 86: int argc; ! 87: char **argv; ! 88: { ! 89: struct fileinfo ofile; ! 90: ! 91: for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { ! 92: (*argv)++; ! 93: switch ( **argv ) { ! 94: default: ! 95: error( FATAL , "pc3: bad flag -%c\n" , **argv ); ! 96: case 'w': ! 97: wflag = TRUE; ! 98: break; ! 99: } ! 100: } ! 101: for ( /* void */ ; *argv != 0 ; argv++ ) { ! 102: # ifdef DEBUG ! 103: fprintf( stderr , "[main] *argv = %s\n" , *argv ); ! 104: # endif DEBUG ! 105: ofile.name = *argv; ! 106: checkfile( &ofile ); ! 107: } ! 108: exit( errors ); ! 109: } ! 110: ! 111: /* ! 112: * check the namelist of a file, or all namelists of an archive. ! 113: */ ! 114: checkfile( ofilep ) ! 115: struct fileinfo *ofilep; ! 116: { ! 117: union { ! 118: char mag_armag[ SARMAG + 1 ]; ! 119: struct exec mag_exec; ! 120: } mag_un; ! 121: int red; ! 122: struct stat filestat; ! 123: ! 124: ofilep -> file = fopen( ofilep -> name , "r" ); ! 125: if ( ofilep -> file == NULL ) { ! 126: error( ERROR , "cannot open: %s" , ofilep -> name ); ! 127: return; ! 128: } ! 129: fstat( fileno( ofilep -> file ) , &filestat ); ! 130: red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); ! 131: if ( red != sizeof mag_un ) { ! 132: error( ERROR , "cannot read header: %s" , ofilep -> name ); ! 133: return; ! 134: } ! 135: if ( mag_un.mag_exec.a_magic == OARMAG ) { ! 136: error( WARNING , "old archive: %s" , ofilep -> name ); ! 137: return; ! 138: } ! 139: if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { ! 140: /* archive, iterate through elements */ ! 141: # ifdef DEBUG ! 142: fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); ! 143: # endif DEBUG ! 144: ofilep -> nextoffset = SARMAG; ! 145: while ( nextelement( ofilep ) ) { ! 146: checknl( ofilep ); ! 147: } ! 148: } else if ( N_BADMAG( mag_un.mag_exec ) ) { ! 149: /* not a file.o */ ! 150: error( ERROR , "bad format: %s" , ofilep -> name ); ! 151: return; ! 152: } else { ! 153: /* a file.o */ ! 154: # ifdef DEBUG ! 155: fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); ! 156: # endif DEBUG ! 157: fseek( ofilep -> file , 0L , 0 ); ! 158: ofilep -> nextoffset = filestat.st_size; ! 159: checknl( ofilep ); ! 160: } ! 161: fclose( ofilep -> file ); ! 162: } ! 163: ! 164: /* ! 165: * check the namelist of this file for conflicts with ! 166: * previously entered symbols. ! 167: */ ! 168: checknl( ofilep ) ! 169: register struct fileinfo *ofilep; ! 170: { ! 171: ! 172: long red; ! 173: struct exec oexec; ! 174: off_t symoff; ! 175: long numsyms; ! 176: register struct nlist *nlp; ! 177: register char *stringp; ! 178: long strsize; ! 179: long sym; ! 180: ! 181: red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); ! 182: if ( red != sizeof oexec ) { ! 183: error( ERROR , "error reading struct exec: %s" ! 184: , ofilep -> name ); ! 185: return; ! 186: } ! 187: if ( N_BADMAG( oexec ) ) { ! 188: return; ! 189: } ! 190: symoff = N_SYMOFF( oexec ) - sizeof oexec; ! 191: fseek( ofilep -> file , symoff , 1 ); ! 192: numsyms = oexec.a_syms / sizeof ( struct nlist ); ! 193: if ( numsyms == 0 ) { ! 194: error( WARNING , "no name list: %s" , ofilep -> name ); ! 195: return; ! 196: } ! 197: nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); ! 198: if ( nlp == 0 ) { ! 199: error( FATAL , "no room for %d nlists" , numsyms ); ! 200: } ! 201: red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) ! 202: , ofilep -> file ); ! 203: if ( ftell( ofilep -> file ) + sizeof ( off_t ) ! 204: >= ofilep -> nextoffset ) { ! 205: error( WARNING , "no string table (old format .o?)" ! 206: , ofilep -> name ); ! 207: return; ! 208: } ! 209: red = fread( (char *) &strsize , sizeof strsize , 1 ! 210: , ofilep -> file ); ! 211: if ( red != 1 ) { ! 212: error( WARNING , "no string table (old format .o?)" ! 213: , ofilep -> name ); ! 214: return; ! 215: } ! 216: stringp = ( char * ) malloc( strsize ); ! 217: if ( stringp == 0 ) { ! 218: error( FATAL , "no room for %d bytes of strings" , strsize ); ! 219: } ! 220: red = fread( stringp + sizeof strsize ! 221: , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); ! 222: if ( red != 1 ) { ! 223: error( WARNING , "error reading string table: %s" ! 224: , ofilep -> name ); ! 225: } ! 226: # ifdef DEBUG ! 227: fprintf( stderr , "[checknl] %s: %d symbols\n" ! 228: , ofilep -> name , numsyms ); ! 229: # endif DEBUG ! 230: for ( sym = 0 ; sym < numsyms ; sym++) { ! 231: if ( nlp[ sym ].n_un.n_strx ) { ! 232: nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; ! 233: } else { ! 234: nlp[ sym ].n_un.n_name = ""; ! 235: } ! 236: checksymbol( &nlp[ sym ] , ofilep ); ! 237: } ! 238: if ( nlp ) { ! 239: free( nlp ); ! 240: } ! 241: if ( stringp ) { ! 242: free( stringp ); ! 243: } ! 244: } ! 245: ! 246: /* ! 247: * check a symbol. ! 248: * look it up in the hashed symbol table, ! 249: * entering it if necessary. ! 250: * this maintains a state of which .p and .i files ! 251: * it is currently in the midst from the nlist entries ! 252: * for source and included files. ! 253: * if we are inside a .p but not a .i, pfilep == ifilep. ! 254: */ ! 255: checksymbol( nlp , ofilep ) ! 256: struct nlist *nlp; ! 257: struct fileinfo *ofilep; ! 258: { ! 259: static struct symbol *pfilep = NIL; ! 260: static struct symbol *ifilep = NIL; ! 261: register struct symbol *symbolp; ! 262: int errtype; ! 263: ! 264: # ifdef DEBUG ! 265: if ( pfilep && ifilep ) { ! 266: fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" ! 267: , pfilep -> name , ifilep -> name ); ! 268: } ! 269: fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" ! 270: , nlp -> n_un.n_name , nlp -> n_desc ! 271: , classify( nlp -> n_desc ) ); ! 272: # endif DEBUG ! 273: if ( nlp -> n_type != N_PC ) { ! 274: /* don't care about the others */ ! 275: return; ! 276: } ! 277: symbolp = entersymbol( nlp -> n_un.n_name ); ! 278: if ( symbolp -> lookup == NEW ) { ! 279: # ifdef DEBUG ! 280: fprintf( stderr , "[checksymbol] ->name %s is NEW\n" ! 281: , symbolp -> name ); ! 282: # endif DEBUG ! 283: symbolp -> desc = nlp -> n_desc; ! 284: symbolp -> fromp = pfilep; ! 285: switch ( symbolp -> desc ) { ! 286: default: ! 287: error( FATAL , "panic: [checksymbol] NEW" ); ! 288: case N_PGLABEL: ! 289: case N_PGCONST: ! 290: case N_PGTYPE: ! 291: case N_PGVAR: ! 292: case N_PGFUNC: ! 293: case N_PGPROC: ! 294: case N_PLDATA: ! 295: case N_PLTEXT: ! 296: symbolp -> sym_un.sym_str.rfilep = ifilep; ! 297: symbolp -> sym_un.sym_str.rline = nlp -> n_value; ! 298: symbolp -> sym_un.sym_str.fromi = ifilep; ! 299: symbolp -> sym_un.sym_str.iline = nlp -> n_value; ! 300: return; ! 301: case N_PEFUNC: ! 302: case N_PEPROC: ! 303: symbolp -> sym_un.sym_str.rfilep = NIL; ! 304: symbolp -> sym_un.sym_str.rline = 0; ! 305: /* ! 306: * functions can only be declared external ! 307: * in included files. ! 308: */ ! 309: if ( pfilep == ifilep ) { ! 310: error( WARNING ! 311: , "%s, line %d: %s %s must be declared in included file" ! 312: , pfilep -> name , nlp -> n_value ! 313: , classify( symbolp -> desc ) ! 314: , symbolp -> name ); ! 315: } ! 316: symbolp -> sym_un.sym_str.fromi = ifilep; ! 317: symbolp -> sym_un.sym_str.iline = nlp -> n_value; ! 318: return; ! 319: case N_PSO: ! 320: if ( nlp -> n_value < N_FLAGCHECKSUM ) { ! 321: error( WARNING, ! 322: "%s is out of date and should be recompiled", ! 323: ofilep -> name ); ! 324: } ! 325: pfilep = symbolp; ! 326: ifilep = symbolp; ! 327: symbolp -> sym_un.checksum = N_FLAGCHECKSUM; ! 328: return; ! 329: case N_PSOL: ! 330: ifilep = symbolp; ! 331: symbolp -> sym_un.checksum = nlp -> n_value; ! 332: return; ! 333: } ! 334: } else { ! 335: # ifdef DEBUG ! 336: fprintf( stderr , "[checksymbol] ->name %s is OLD\n" ! 337: , symbolp -> name ); ! 338: # endif DEBUG ! 339: errtype = ERROR; ! 340: switch ( symbolp -> desc ) { ! 341: default: ! 342: error( FATAL , "panic [checksymbol] OLD" ); ! 343: return; ! 344: case N_PSO: ! 345: /* ! 346: * finding a file again means you are back ! 347: * in it after finishing an include file. ! 348: */ ! 349: if ( symbolp -> desc != nlp -> n_desc ) { ! 350: error( FATAL , "panic [checksymbol] PSO" ); ! 351: return; ! 352: } ! 353: pfilep = symbolp; ! 354: ifilep = symbolp; ! 355: return; ! 356: case N_PSOL: ! 357: /* ! 358: * include files can be seen more than once, ! 359: * but their checksums are checked if they are ! 360: * greater than N_FLAGCHECKSUM. ! 361: * PSOL's are seen with checksums as the ! 362: * include file is entered, and with ! 363: * N_FLAGCHECKSUM as we are back in an ! 364: * included file from a nested include. ! 365: */ ! 366: if ( symbolp -> desc != nlp -> n_desc ) { ! 367: error( FATAL , "panic [checksymbol] PSOL" ); ! 368: return; ! 369: } ! 370: if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM ! 371: && (unsigned) nlp -> n_value > N_FLAGCHECKSUM ! 372: && symbolp -> sym_un.checksum != nlp -> n_value ) { ! 373: error( ERROR, ! 374: "%s included in %s differs from %s included in %s", ! 375: symbolp -> name, pfilep -> name, ! 376: symbolp -> name, symbolp -> fromp -> name ); ! 377: } ! 378: ifilep = symbolp; ! 379: return; ! 380: case N_PEFUNC: ! 381: case N_PEPROC: ! 382: /* ! 383: * this might be the resolution of the external ! 384: * has to match func/proc of external ! 385: * and has to have included external ! 386: * and has to not have been previously resolved. ! 387: */ ! 388: if ( ( ( symbolp -> desc == N_PEFUNC ! 389: && nlp -> n_desc == N_PGFUNC ) ! 390: || ( symbolp -> desc == N_PEPROC ! 391: && nlp -> n_desc == N_PGPROC ) ) ! 392: && ( symbolp -> fromp == pfilep ) ! 393: && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { ! 394: /* ! 395: * resolve external ! 396: */ ! 397: # ifdef DEBUG ! 398: fprintf( stderr , "[checksymbol] resolving external\n" ); ! 399: # endif DEBUG ! 400: symbolp -> sym_un.sym_str.rfilep = ifilep; ! 401: symbolp -> sym_un.sym_str.rline = nlp -> n_value; ! 402: return; ! 403: } ! 404: /* ! 405: * otherwise, it might be another external, ! 406: * which is okay if it's ! 407: * the same type and from the same include file ! 408: */ ! 409: if ( ( ( symbolp -> desc == N_PEFUNC ! 410: && nlp -> n_desc == N_PEFUNC ) ! 411: || ( symbolp -> desc == N_PEPROC ! 412: && nlp -> n_desc == N_PEPROC ) ) ! 413: && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { ! 414: /* ! 415: * just another pretty external ! 416: * make it look like it comes from here. ! 417: */ ! 418: # ifdef DEBUG ! 419: fprintf( stderr , "[checksymbol] just another pretty external\n" ); ! 420: # endif DEBUG ! 421: symbolp -> fromp = pfilep; ! 422: return; ! 423: } ! 424: /* ! 425: * something is wrong ! 426: * if it's not resolved, use the header file ! 427: * otherwise, it's just a regular error ! 428: */ ! 429: if ( symbolp -> sym_un.sym_str.rfilep == NIL ) { ! 430: error( ERROR , ! 431: "%s, line %d: %s is already defined\n\t(%s, line %d)." , ! 432: ifilep -> name , nlp -> n_value , ! 433: nlp -> n_un.n_name , ! 434: symbolp -> sym_un.sym_str.fromi -> name , ! 435: symbolp -> sym_un.sym_str.iline ); ! 436: return; ! 437: } ! 438: break; ! 439: case N_PGFUNC: ! 440: case N_PGPROC: ! 441: /* ! 442: * functions may not be seen more than once. ! 443: * the loader will complain about ! 444: * `multiply defined', but we can, too. ! 445: */ ! 446: break; ! 447: case N_PGLABEL: ! 448: case N_PGCONST: ! 449: case N_PGTYPE: ! 450: case N_PGVAR: ! 451: /* ! 452: * labels, constants, types, variables ! 453: * and external declarations ! 454: * may be seen as many times as they want, ! 455: * as long as they come from the same include file. ! 456: * make it look like they come from this .p file. ! 457: */ ! 458: included: ! 459: if ( nlp -> n_desc != symbolp -> desc ! 460: || symbolp -> sym_un.sym_str.fromi != ifilep ) { ! 461: break; ! 462: } ! 463: symbolp -> fromp = pfilep; ! 464: return; ! 465: case N_PLDATA: ! 466: case N_PLTEXT: ! 467: switch ( nlp -> n_desc ) { ! 468: default: ! 469: error( FATAL , "pc3: unknown stab 0x%x" ! 470: , nlp -> n_desc ); ! 471: return; ! 472: case N_PSO: ! 473: case N_PSOL: ! 474: case N_PGCONST: ! 475: case N_PGTYPE: ! 476: /* these won't conflict with library */ ! 477: return; ! 478: case N_PGLABEL: ! 479: case N_PGVAR: ! 480: case N_PGFUNC: ! 481: case N_PGPROC: ! 482: case N_PEFUNC: ! 483: case N_PEPROC: ! 484: case N_PLDATA: ! 485: case N_PLTEXT: ! 486: errtype = WARNING; ! 487: break; ! 488: } ! 489: break; ! 490: } ! 491: /* ! 492: * this is the breaks ! 493: */ ! 494: error( errtype ! 495: , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)." ! 496: , ifilep -> name ! 497: , nlp -> n_value ! 498: , classify( nlp -> n_desc ) ! 499: , nlp -> n_un.n_name ! 500: , ( symbolp -> desc == nlp -> n_desc ? "" : " as " ) ! 501: , ( symbolp -> desc == nlp -> n_desc ! 502: ? "" : article( symbolp -> desc ) ) ! 503: , symbolp -> sym_un.sym_str.rfilep -> name ! 504: , symbolp -> sym_un.sym_str.rline ); ! 505: } ! 506: } ! 507: ! 508: /* ! 509: * quadratically hashed symbol table. ! 510: * things are never deleted from the hash symbol table. ! 511: * as more hash table is needed, ! 512: * a new one is alloc'ed and chained to the end. ! 513: * search is by rehashing within each table, ! 514: * traversing chains to next table if unsuccessful. ! 515: */ ! 516: struct symbol * ! 517: entersymbol( name ) ! 518: char *name; ! 519: { ! 520: static struct symboltableinfo symboltable; ! 521: char *enteredname; ! 522: long hashindex; ! 523: register struct symboltableinfo *tablep; ! 524: register struct symbol **herep; ! 525: register struct symbol **limitp; ! 526: register long increment; ! 527: ! 528: enteredname = enterstring( name ); ! 529: hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; ! 530: for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) { ! 531: if ( tablep == NIL ) { ! 532: # ifdef SPACEDEBUG ! 533: fprintf( stderr , ! 534: "[entersymbol] calloc'ing table for %d symbols\n" , ! 535: SYMBOLPRIME ); ! 536: # endif SPACEDEBUG ! 537: for ( tablep = &symboltable ! 538: ; tablep->chain != NIL ! 539: ; tablep = tablep->chain ) { ! 540: continue; ! 541: } ! 542: tablep->chain = ( struct symboltableinfo * ) ! 543: calloc( 1 , sizeof ( struct symboltableinfo ) ); ! 544: if ( tablep->chain == NIL ) { ! 545: error( FATAL , "ran out of memory (entersymbol)" ); ! 546: } ! 547: tablep = tablep->chain; ! 548: } ! 549: herep = &( tablep -> entry[ hashindex ] ); ! 550: limitp = &( tablep -> entry[ SYMBOLPRIME ] ); ! 551: increment = 1; ! 552: do { ! 553: if ( *herep == NIL ) { ! 554: /* empty */ ! 555: if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) { ! 556: /* too full, break for next table */ ! 557: break; ! 558: } ! 559: tablep -> used++; ! 560: *herep = symbolalloc(); ! 561: ( *herep ) -> name = enteredname; ! 562: ( *herep ) -> lookup = NEW; ! 563: # ifdef HASHDEBUG ! 564: fprintf( stderr , ! 565: "[entersymbol] name %s NEW after %d\n" , ! 566: enteredname , increment / 2 ); ! 567: # endif HASHDEBUG ! 568: return *herep; ! 569: } ! 570: /* a find? */ ! 571: if ( ( *herep ) -> name == enteredname ) { ! 572: ( *herep ) -> lookup = OLD; ! 573: # ifdef HASHDEBUG ! 574: fprintf( stderr , "[entersymbol] name %s OLD at %d\n" , ! 575: enteredname , increment / 2 ); ! 576: # endif HASHDEBUG ! 577: return *herep; ! 578: } ! 579: herep += increment; ! 580: if ( herep >= limitp ) { ! 581: herep -= SYMBOLPRIME; ! 582: } ! 583: increment += 2; ! 584: } while ( increment < SYMBOLPRIME ); ! 585: # ifdef HASHDEBUG ! 586: fprintf( stderr , "[entersymbol] next symboltable\n" ); ! 587: # endif HASHDEBUG ! 588: } ! 589: } ! 590: ! 591: /* ! 592: * allocate a symbol from the dynamically allocated symbol table. ! 593: */ ! 594: struct symbol * ! 595: symbolalloc() ! 596: { ! 597: static struct symbol *nextsymbol = NIL; ! 598: static long symbolsleft = 0; ! 599: struct symbol *newsymbol; ! 600: ! 601: if ( symbolsleft <= 0 ) { ! 602: # ifdef SPACEDEBUG ! 603: fprintf( stderr , ! 604: "[symbolalloc] malloc space for %d symbols\n" , ! 605: SYMBOLALLOC / sizeof( struct symbol ) ); ! 606: # endif SPACEDEBUG ! 607: nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); ! 608: if ( nextsymbol == 0 ) { ! 609: error( FATAL , "ran out of memory (symbolalloc)" ); ! 610: } ! 611: symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); ! 612: } ! 613: newsymbol = nextsymbol; ! 614: nextsymbol++; ! 615: symbolsleft--; ! 616: return newsymbol; ! 617: } ! 618: ! 619: /* ! 620: * hash a string based on all of its characters. ! 621: */ ! 622: long ! 623: hashstring( string ) ! 624: char *string; ! 625: { ! 626: register char *cp; ! 627: register long value; ! 628: ! 629: value = 0; ! 630: for ( cp = string ; *cp ; cp++ ) { ! 631: value = ( value * 2 ) + *cp; ! 632: } ! 633: return value; ! 634: } ! 635: ! 636: /* ! 637: * quadratically hashed string table. ! 638: * things are never deleted from the hash string table. ! 639: * as more hash table is needed, ! 640: * a new one is alloc'ed and chained to the end. ! 641: * search is by rehashing within each table, ! 642: * traversing chains to next table if unsuccessful. ! 643: */ ! 644: char * ! 645: enterstring( string ) ! 646: char *string; ! 647: { ! 648: static struct stringtableinfo stringtable; ! 649: long hashindex; ! 650: register struct stringtableinfo *tablep; ! 651: register char **herep; ! 652: register char **limitp; ! 653: register long increment; ! 654: ! 655: hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; ! 656: for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) { ! 657: if ( tablep == NIL ) { ! 658: # ifdef SPACEDEBUG ! 659: fprintf( stderr , ! 660: "[enterstring] calloc space for %d strings\n" , ! 661: STRINGPRIME ); ! 662: # endif SPACEDEBUG ! 663: for ( tablep = &stringtable ! 664: ; tablep->chain != NIL ! 665: ; tablep = tablep->chain ) { ! 666: continue; ! 667: } ! 668: tablep->chain = ( struct stringtableinfo * ) ! 669: calloc( 1 , sizeof ( struct stringtableinfo ) ); ! 670: if ( tablep->chain == NIL ) { ! 671: error( FATAL , "ran out of memory (enterstring)" ); ! 672: } ! 673: tablep = tablep->chain; ! 674: } ! 675: herep = &( tablep -> entry[ hashindex ] ); ! 676: limitp = &( tablep -> entry[ STRINGPRIME ] ); ! 677: increment = 1; ! 678: do { ! 679: if ( *herep == NIL ) { ! 680: /* empty */ ! 681: if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) { ! 682: /* too full, break for next table */ ! 683: break; ! 684: } ! 685: tablep -> used++; ! 686: *herep = charalloc( strlen( string ) ); ! 687: strcpy( *herep , string ); ! 688: # ifdef HASHDEBUG ! 689: fprintf( stderr , ! 690: "[enterstring] string %s copied after %d\n" , ! 691: *herep , increment / 2 ); ! 692: # endif HASHDEBUG ! 693: return *herep; ! 694: } ! 695: /* quick, check the first chars and then the rest */ ! 696: if ( **herep == *string && strcmp( *herep , string ) == 0 ) { ! 697: # ifdef HASHDEBUG ! 698: fprintf( stderr , ! 699: "[enterstring] string %s found after %d\n" , ! 700: *herep , increment / 2 ); ! 701: # endif HASHDEBUG ! 702: return *herep; ! 703: } ! 704: herep += increment; ! 705: if ( herep >= limitp ) { ! 706: herep -= STRINGPRIME; ! 707: } ! 708: increment += 2; ! 709: } while ( increment < STRINGPRIME ); ! 710: # ifdef HASHDEBUG ! 711: fprintf( stderr , "[enterstring] next stringtable\n" ); ! 712: # endif HASHDEBUG ! 713: } ! 714: } ! 715: ! 716: /* ! 717: * copy a string to the dynamically allocated character table. ! 718: */ ! 719: char * ! 720: charalloc( length ) ! 721: register long length; ! 722: { ! 723: static char *nextchar = NIL; ! 724: static long charsleft = 0; ! 725: register long lengthplus1 = length + 1; ! 726: register long askfor; ! 727: char *newstring; ! 728: ! 729: if ( charsleft < lengthplus1 ) { ! 730: askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; ! 731: # ifdef SPACEDEBUG ! 732: fprintf( stderr , "[charalloc] malloc space for %d chars\n" ! 733: , askfor ); ! 734: # endif SPACEDEBUG ! 735: nextchar = ( char * ) malloc( askfor ); ! 736: if ( nextchar == 0 ) { ! 737: error( FATAL , "no room for %d characters" , askfor ); ! 738: } ! 739: charsleft = askfor; ! 740: } ! 741: newstring = nextchar; ! 742: nextchar += lengthplus1; ! 743: charsleft -= lengthplus1; ! 744: return newstring; ! 745: } ! 746: ! 747: /* ! 748: * read an archive header for the next element ! 749: * and find the offset of the one after this. ! 750: */ ! 751: BOOL ! 752: nextelement( ofilep ) ! 753: struct fileinfo *ofilep; ! 754: { ! 755: register char *cp; ! 756: register long red; ! 757: register off_t arsize; ! 758: struct ar_hdr archdr; ! 759: ! 760: fseek( ofilep -> file , ofilep -> nextoffset , 0 ); ! 761: red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); ! 762: if ( red != sizeof archdr ) { ! 763: return FALSE; ! 764: } ! 765: /* null terminate the blank-padded name */ ! 766: cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; ! 767: *cp = '\0'; ! 768: while ( *--cp == ' ' ) { ! 769: *cp = '\0'; ! 770: } ! 771: /* set up the address of the beginning of next element */ ! 772: arsize = atol( archdr.ar_size ); ! 773: /* archive elements are aligned on 0 mod 2 boundaries */ ! 774: if ( arsize & 1 ) { ! 775: arsize += 1; ! 776: } ! 777: ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; ! 778: /* say we had one */ ! 779: return TRUE; ! 780: } ! 781: ! 782: /* ! 783: * variable number of arguments to error, like printf. ! 784: */ ! 785: error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ) ! 786: int type; ! 787: char *message; ! 788: { ! 789: errors = type > errors ? type : errors; ! 790: if ( wflag && type == WARNING ) { ! 791: return; ! 792: } ! 793: fprintf( stderr , "%s: " , program ); ! 794: switch ( type ) { ! 795: case WARNING: ! 796: fprintf( stderr , "Warning: " ); ! 797: break; ! 798: case ERROR: ! 799: fprintf( stderr , "Error: " ); ! 800: break; ! 801: case FATAL: ! 802: fprintf( stderr , "Fatal: " ); ! 803: break; ! 804: default: ! 805: fprintf( stderr , "Ooops: " ); ! 806: break; ! 807: } ! 808: fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 ); ! 809: fprintf( stderr , "\n" ); ! 810: if ( type == FATAL ) { ! 811: exit( FATAL ); ! 812: } ! 813: } ! 814: ! 815: char * ! 816: classify( type ) ! 817: unsigned char type; ! 818: { ! 819: switch ( type ) { ! 820: case N_PSO: ! 821: return "source file"; ! 822: case N_PSOL: ! 823: return "include file"; ! 824: case N_PGLABEL: ! 825: return "label"; ! 826: case N_PGCONST: ! 827: return "constant"; ! 828: case N_PGTYPE: ! 829: return "type"; ! 830: case N_PGVAR: ! 831: return "variable"; ! 832: case N_PGFUNC: ! 833: return "function"; ! 834: case N_PGPROC: ! 835: return "procedure"; ! 836: case N_PEFUNC: ! 837: return "external function"; ! 838: case N_PEPROC: ! 839: return "external procedure"; ! 840: case N_PLDATA: ! 841: return "library variable"; ! 842: case N_PLTEXT: ! 843: return "library routine"; ! 844: default: ! 845: return "unknown symbol"; ! 846: } ! 847: } ! 848: ! 849: char * ! 850: article( type ) ! 851: unsigned char type; ! 852: { ! 853: switch ( type ) { ! 854: case N_PSO: ! 855: return "a source file"; ! 856: case N_PSOL: ! 857: return "an include file"; ! 858: case N_PGLABEL: ! 859: return "a label"; ! 860: case N_PGCONST: ! 861: return "a constant"; ! 862: case N_PGTYPE: ! 863: return "a type"; ! 864: case N_PGVAR: ! 865: return "a variable"; ! 866: case N_PGFUNC: ! 867: return "a function"; ! 868: case N_PGPROC: ! 869: return "a procedure"; ! 870: case N_PEFUNC: ! 871: return "an external function"; ! 872: case N_PEPROC: ! 873: return "an external procedure"; ! 874: case N_PLDATA: ! 875: return "a library variable"; ! 876: case N_PLTEXT: ! 877: return "a library routine"; ! 878: default: ! 879: return "an unknown symbol"; ! 880: } ! 881: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.