113617Ssam #ifndef lint 2*14129Speter static char sccsid[] = "@(#)pc3.c 1.13 (Berkeley) 07/26/83"; 313617Ssam #endif 4822Speter /* Copyright (c) 1980 Regents of the University of California */ 5822Speter 6822Speter /* 7822Speter * Pc3 is a pass in the Berkeley Pascal compilation 8822Speter * process that is performed just prior to linking Pascal 9822Speter * object files. Its purpose is to enforce the rules of 10822Speter * separate compilation for Berkeley Pascal. Pc3 is called 11822Speter * with the same argument list of object files that is sent to 12822Speter * the loader. These checks are performed by pc3 by examining 13822Speter * the symbol tables of the object files: 14*14129Speter * (1) All .o files must be up to date with respect to the 15*14129Speter * runtime libraries. 16822Speter * (2) Each global Pascal symbol (label, constant, type, 17822Speter * variable, procedure, or function name) must be uniquely 18822Speter * declared, i.e. declared in only one included file or 19822Speter * source file. 20822Speter * (3) Each external function (or procedure) may be resolved 21822Speter * at most once in a source file which included the 22822Speter * external declaration of the function. 23822Speter * 24822Speter * The symbol table of each object file is scanned and 25822Speter * each global Pascal symbol is placed in a hashed symbol 26822Speter * table. The Pascal compiler has been modified to emit all 27822Speter * Pascal global symbols to the object file symbol table. The 28822Speter * information stored in the symbol table for each such symbol 29822Speter * is: 30822Speter * 31822Speter * - the name of the symbol; 32844Speter * - a subtype descriptor; 33822Speter * - the file which logically contains the declaration of 34*14129Speter * the symbol or which caused the inclusion of an include file. 35*14129Speter * - for included files: 36*14129Speter * - a checksum; 37*14129Speter * - for symbols: 38*14129Speter * - the file which textually contains the declaration of 39*14129Speter * the symbol (possibly an include file); 40*14129Speter * - the line number at which the symbol is declared; 41*14129Speter * - the file which contains the resolution of the symbol. 42*14129Speter * - the line number at which the symbol is resolved; 43822Speter * 44822Speter * If a symbol has been previously entered into the symbol 45822Speter * table, a check is made that the current declaration is of 46822Speter * the same type and from the same include file as the previous 47822Speter * one. Except for files and functions and procedures, it is 48822Speter * an error for a symbol declaration to be encountered more 49822Speter * than once, unless the re-declarations come from the same 50822Speter * included file as the original. 51822Speter * 52822Speter * As an include file symbol is encountered in a source 53822Speter * file, the symbol table entry of each symbol declared in that 54822Speter * include file is modified to reflect its new logical 55822Speter * inclusion in the source file. File symbols are also 56822Speter * encountered as an included file ends, signaling the 57822Speter * continuation of the enclosing file. 58822Speter * 59822Speter * Functions and procedures which have been declared 60822Speter * external may be resolved by declarations from source files 61822Speter * which included the external declaration of the function. 62822Speter * Functions and procedures may be resolved at most once across 63822Speter * a set of object files. The loader will complain if a 64822Speter * function is not resolved at least once. 65822Speter */ 66822Speter 67832Speter char program[] = "pc"; 68822Speter 69822Speter #include <sys/types.h> 7013617Ssam #include <sys/stat.h> 71822Speter #include <ar.h> 72822Speter #include <stdio.h> 73822Speter #include <ctype.h> 74822Speter #include <a.out.h> 75822Speter #include <stab.h> 76858Speter #include "pstab.h" 77822Speter #include "pc3.h" 78822Speter 797598Speter int errors = NONE; 807598Speter BOOL wflag = FALSE; 81822Speter 82822Speter /* 83822Speter * check each of the argument .o files (or archives of .o files). 84822Speter */ 85822Speter main( argc , argv ) 86822Speter int argc; 87822Speter char **argv; 88822Speter { 89822Speter struct fileinfo ofile; 90822Speter 917598Speter for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { 927598Speter (*argv)++; 937598Speter switch ( **argv ) { 947598Speter default: 957598Speter error( FATAL , "pc3: bad flag -%c\n" , **argv ); 967598Speter case 'w': 977598Speter wflag = TRUE; 987598Speter break; 997598Speter } 1007598Speter } 1017598Speter for ( /* void */ ; *argv != 0 ; argv++ ) { 102822Speter # ifdef DEBUG 103822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv ); 104822Speter # endif DEBUG 105822Speter ofile.name = *argv; 106822Speter checkfile( &ofile ); 107822Speter } 108822Speter exit( errors ); 109822Speter } 110822Speter 111822Speter /* 112822Speter * check the namelist of a file, or all namelists of an archive. 113822Speter */ 114822Speter checkfile( ofilep ) 115822Speter struct fileinfo *ofilep; 116822Speter { 117822Speter union { 118822Speter char mag_armag[ SARMAG + 1 ]; 119822Speter struct exec mag_exec; 120822Speter } mag_un; 121822Speter int red; 122822Speter struct stat filestat; 123822Speter 124822Speter ofilep -> file = fopen( ofilep -> name , "r" ); 125822Speter if ( ofilep -> file == NULL ) { 1267598Speter error( ERROR , "cannot open: %s" , ofilep -> name ); 127822Speter return; 128822Speter } 129822Speter fstat( fileno( ofilep -> file ) , &filestat ); 130822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); 131822Speter if ( red != sizeof mag_un ) { 1327598Speter error( ERROR , "cannot read header: %s" , ofilep -> name ); 133822Speter return; 134822Speter } 135822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) { 136822Speter error( WARNING , "old archive: %s" , ofilep -> name ); 137822Speter return; 138822Speter } 139822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { 140822Speter /* archive, iterate through elements */ 141822Speter # ifdef DEBUG 142822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); 143822Speter # endif DEBUG 144822Speter ofilep -> nextoffset = SARMAG; 145822Speter while ( nextelement( ofilep ) ) { 146822Speter checknl( ofilep ); 147822Speter } 148822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) { 149822Speter /* not a file.o */ 1507598Speter error( ERROR , "bad format: %s" , ofilep -> name ); 151822Speter return; 152822Speter } else { 153822Speter /* a file.o */ 154822Speter # ifdef DEBUG 155822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); 156822Speter # endif DEBUG 157822Speter fseek( ofilep -> file , 0L , 0 ); 158822Speter ofilep -> nextoffset = filestat.st_size; 159822Speter checknl( ofilep ); 160822Speter } 161822Speter fclose( ofilep -> file ); 162822Speter } 163822Speter 164822Speter /* 165822Speter * check the namelist of this file for conflicts with 166822Speter * previously entered symbols. 167822Speter */ 168822Speter checknl( ofilep ) 169822Speter register struct fileinfo *ofilep; 170822Speter { 171822Speter 172822Speter long red; 173831Speter struct exec oexec; 174822Speter off_t symoff; 175822Speter long numsyms; 176822Speter register struct nlist *nlp; 177822Speter register char *stringp; 178822Speter long strsize; 179822Speter long sym; 180822Speter 181831Speter red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); 182831Speter if ( red != sizeof oexec ) { 1837598Speter error( ERROR , "error reading struct exec: %s" 184822Speter , ofilep -> name ); 185822Speter return; 186822Speter } 187831Speter if ( N_BADMAG( oexec ) ) { 188822Speter return; 189822Speter } 190831Speter symoff = N_SYMOFF( oexec ) - sizeof oexec; 191822Speter fseek( ofilep -> file , symoff , 1 ); 192831Speter numsyms = oexec.a_syms / sizeof ( struct nlist ); 193822Speter if ( numsyms == 0 ) { 194822Speter error( WARNING , "no name list: %s" , ofilep -> name ); 195822Speter return; 196822Speter } 197822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); 198822Speter if ( nlp == 0 ) { 199822Speter error( FATAL , "no room for %d nlists" , numsyms ); 200822Speter } 201822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) 202822Speter , ofilep -> file ); 203822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t ) 204822Speter >= ofilep -> nextoffset ) { 205822Speter error( WARNING , "no string table (old format .o?)" 206822Speter , ofilep -> name ); 207822Speter return; 208822Speter } 209822Speter red = fread( (char *) &strsize , sizeof strsize , 1 210822Speter , ofilep -> file ); 211822Speter if ( red != 1 ) { 212822Speter error( WARNING , "no string table (old format .o?)" 213822Speter , ofilep -> name ); 214822Speter return; 215822Speter } 216822Speter stringp = ( char * ) malloc( strsize ); 217822Speter if ( stringp == 0 ) { 218822Speter error( FATAL , "no room for %d bytes of strings" , strsize ); 219822Speter } 220822Speter red = fread( stringp + sizeof strsize 221822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); 222822Speter if ( red != 1 ) { 223822Speter error( WARNING , "error reading string table: %s" 224822Speter , ofilep -> name ); 225822Speter } 226822Speter # ifdef DEBUG 227822Speter fprintf( stderr , "[checknl] %s: %d symbols\n" 228822Speter , ofilep -> name , numsyms ); 229822Speter # endif DEBUG 230822Speter for ( sym = 0 ; sym < numsyms ; sym++) { 231822Speter if ( nlp[ sym ].n_un.n_strx ) { 232822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; 233822Speter } else { 234822Speter nlp[ sym ].n_un.n_name = ""; 235822Speter } 236822Speter checksymbol( &nlp[ sym ] , ofilep ); 237822Speter } 238822Speter if ( nlp ) { 239822Speter free( nlp ); 240822Speter } 241822Speter if ( stringp ) { 242822Speter free( stringp ); 243822Speter } 244822Speter } 245822Speter 246822Speter /* 247822Speter * check a symbol. 248822Speter * look it up in the hashed symbol table, 249822Speter * entering it if necessary. 250822Speter * this maintains a state of which .p and .i files 251822Speter * it is currently in the midst from the nlist entries 252822Speter * for source and included files. 253822Speter * if we are inside a .p but not a .i, pfilep == ifilep. 254822Speter */ 255822Speter checksymbol( nlp , ofilep ) 256822Speter struct nlist *nlp; 257822Speter struct fileinfo *ofilep; 258822Speter { 259822Speter static struct symbol *pfilep = NIL; 260822Speter static struct symbol *ifilep = NIL; 261822Speter register struct symbol *symbolp; 2627601Speter int errtype; 263822Speter 264822Speter # ifdef DEBUG 265822Speter if ( pfilep && ifilep ) { 266822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" 267822Speter , pfilep -> name , ifilep -> name ); 268822Speter } 269844Speter fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" 270844Speter , nlp -> n_un.n_name , nlp -> n_desc 271844Speter , classify( nlp -> n_desc ) ); 272822Speter # endif DEBUG 273844Speter if ( nlp -> n_type != N_PC ) { 274844Speter /* don't care about the others */ 275844Speter return; 276822Speter } 277844Speter symbolp = entersymbol( nlp -> n_un.n_name ); 278822Speter if ( symbolp -> lookup == NEW ) { 279822Speter # ifdef DEBUG 280822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n" 281822Speter , symbolp -> name ); 282822Speter # endif DEBUG 283844Speter symbolp -> desc = nlp -> n_desc; 284*14129Speter symbolp -> fromp = pfilep; 285844Speter switch ( symbolp -> desc ) { 2867550Speter default: 2877550Speter error( FATAL , "panic: [checksymbol] NEW" ); 288844Speter case N_PGLABEL: 289844Speter case N_PGCONST: 290844Speter case N_PGTYPE: 291822Speter case N_PGVAR: 292844Speter case N_PGFUNC: 293844Speter case N_PGPROC: 2947601Speter case N_PLDATA: 2957601Speter case N_PLTEXT: 296831Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 297831Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 298831Speter symbolp -> sym_un.sym_str.fromi = ifilep; 299831Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 300831Speter return; 301844Speter case N_PEFUNC: 302844Speter case N_PEPROC: 303831Speter symbolp -> sym_un.sym_str.rfilep = NIL; 304831Speter symbolp -> sym_un.sym_str.rline = 0; 305831Speter /* 306831Speter * functions can only be declared external 307831Speter * in included files. 308831Speter */ 309831Speter if ( pfilep == ifilep ) { 310831Speter error( WARNING 311831Speter , "%s, line %d: %s %s must be declared in included file" 312831Speter , pfilep -> name , nlp -> n_value 313844Speter , classify( symbolp -> desc ) 314831Speter , symbolp -> name ); 315831Speter } 316822Speter symbolp -> sym_un.sym_str.fromi = ifilep; 317822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 318822Speter return; 319822Speter case N_PSO: 320*14129Speter if ( nlp -> n_value < N_FLAGCHECKSUM ) { 321*14129Speter error( WARNING, 322*14129Speter "%s is out of date and should be recompiled", 323*14129Speter ofilep -> name ); 324*14129Speter } 325822Speter pfilep = symbolp; 326*14129Speter ifilep = symbolp; 327*14129Speter symbolp -> sym_un.checksum = N_FLAGCHECKSUM; 328*14129Speter return; 329822Speter case N_PSOL: 330822Speter ifilep = symbolp; 331*14129Speter symbolp -> sym_un.checksum = nlp -> n_value; 332822Speter return; 333822Speter } 334822Speter } else { 335822Speter # ifdef DEBUG 336822Speter fprintf( stderr , "[checksymbol] ->name %s is OLD\n" 337822Speter , symbolp -> name ); 338822Speter # endif DEBUG 3397601Speter errtype = ERROR; 340844Speter switch ( symbolp -> desc ) { 3417550Speter default: 3427550Speter error( FATAL , "panic [checksymbol] OLD" ); 343*14129Speter return; 344822Speter case N_PSO: 345822Speter /* 346822Speter * finding a file again means you are back 347822Speter * in it after finishing an include file. 348822Speter */ 349*14129Speter if ( symbolp -> desc != nlp -> n_desc ) { 350*14129Speter error( FATAL , "panic [checksymbol] PSO" ); 351*14129Speter return; 352*14129Speter } 353822Speter pfilep = symbolp; 354*14129Speter ifilep = symbolp; 355*14129Speter return; 356822Speter case N_PSOL: 357822Speter /* 358822Speter * include files can be seen more than once, 359*14129Speter * but their checksums are checked if they are 360*14129Speter * greater than N_FLAGCHECKSUM. 361*14129Speter * PSOL's are seen with checksums as the 362*14129Speter * include file is entered, and with 363*14129Speter * N_FLAGCHECKSUM as we are back in an 364*14129Speter * included file from a nested include. 365822Speter */ 366*14129Speter if ( symbolp -> desc != nlp -> n_desc ) { 367*14129Speter error( FATAL , "panic [checksymbol] PSOL" ); 368*14129Speter return; 369*14129Speter } 370*14129Speter if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM 371*14129Speter && (unsigned) nlp -> n_value > N_FLAGCHECKSUM 372*14129Speter && symbolp -> sym_un.checksum != nlp -> n_value ) { 373*14129Speter error( ERROR, 374*14129Speter "%s included in %s differs from %s included in %s", 375*14129Speter symbolp -> name, pfilep -> name, 376*14129Speter symbolp -> name, symbolp -> fromp -> name ); 377*14129Speter } 378822Speter ifilep = symbolp; 379822Speter return; 380844Speter case N_PEFUNC: 381844Speter case N_PEPROC: 382822Speter /* 3837550Speter * this might be the resolution of the external 3847550Speter * has to match func/proc of external 3857550Speter * and has to have included external 3867550Speter * and has to not have been previously resolved. 387822Speter */ 3887550Speter if ( ( ( symbolp -> desc == N_PEFUNC 3897550Speter && nlp -> n_desc == N_PGFUNC ) 3907550Speter || ( symbolp -> desc == N_PEPROC 3917550Speter && nlp -> n_desc == N_PGPROC ) ) 392*14129Speter && ( symbolp -> fromp == pfilep ) 3937550Speter && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { 3947550Speter /* 3957550Speter * resolve external 3967550Speter */ 3977550Speter # ifdef DEBUG 3987550Speter fprintf( stderr , "[checksymbol] resolving external\n" ); 3997550Speter # endif DEBUG 4007550Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 4017550Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 4027550Speter return; 403822Speter } 404822Speter /* 4057550Speter * otherwise, it might be another external, 4067550Speter * which is okay if it's 4077550Speter * the same type and from the same include file 408822Speter */ 4097550Speter if ( ( ( symbolp -> desc == N_PEFUNC 4107550Speter && nlp -> n_desc == N_PEFUNC ) 4117550Speter || ( symbolp -> desc == N_PEPROC 4127550Speter && nlp -> n_desc == N_PEPROC ) ) 4137550Speter && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { 4147550Speter /* 4157550Speter * just another pretty external 4167550Speter * make it look like it comes from here. 4177550Speter */ 4187550Speter # ifdef DEBUG 4197550Speter fprintf( stderr , "[checksymbol] just another pretty external\n" ); 4207550Speter # endif DEBUG 421*14129Speter symbolp -> fromp = pfilep; 4227550Speter return; 423822Speter } 424822Speter /* 4257550Speter * something is wrong 4267598Speter * if it's not resolved, use the header file 4277598Speter * otherwise, it's just a regular error 428822Speter */ 4297598Speter if ( symbolp -> sym_un.sym_str.rfilep == NIL ) { 4307598Speter error( ERROR , 4317601Speter "%s, line %d: %s is already defined\n\t(%s, line %d)." , 4327598Speter ifilep -> name , nlp -> n_value , 4337598Speter nlp -> n_un.n_name , 4347598Speter symbolp -> sym_un.sym_str.fromi -> name , 4357598Speter symbolp -> sym_un.sym_str.iline ); 4367598Speter return; 4377598Speter } 4387598Speter break; 439844Speter case N_PGFUNC: 440844Speter case N_PGPROC: 441822Speter /* 442822Speter * functions may not be seen more than once. 443822Speter * the loader will complain about 444822Speter * `multiply defined', but we can, too. 445822Speter */ 446822Speter break; 447844Speter case N_PGLABEL: 448844Speter case N_PGCONST: 449844Speter case N_PGTYPE: 450822Speter case N_PGVAR: 451822Speter /* 452822Speter * labels, constants, types, variables 453822Speter * and external declarations 454822Speter * may be seen as many times as they want, 455822Speter * as long as they come from the same include file. 456822Speter * make it look like they come from this .p file. 457822Speter */ 458822Speter included: 459844Speter if ( nlp -> n_desc != symbolp -> desc 460822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) { 461822Speter break; 462822Speter } 463*14129Speter symbolp -> fromp = pfilep; 464822Speter return; 4657601Speter case N_PLDATA: 4667601Speter case N_PLTEXT: 4677601Speter switch ( nlp -> n_desc ) { 4687601Speter default: 4697601Speter error( FATAL , "pc3: unknown stab 0x%x" 4707601Speter , nlp -> n_desc ); 4717601Speter return; 4727601Speter case N_PSO: 4737601Speter case N_PSOL: 4747601Speter case N_PGCONST: 4757601Speter case N_PGTYPE: 4767601Speter /* these won't conflict with library */ 4777601Speter return; 4787601Speter case N_PGLABEL: 4797601Speter case N_PGVAR: 4807601Speter case N_PGFUNC: 4817601Speter case N_PGPROC: 4827601Speter case N_PEFUNC: 4837601Speter case N_PEPROC: 4847601Speter case N_PLDATA: 4857601Speter case N_PLTEXT: 4867601Speter errtype = WARNING; 4877601Speter break; 4887601Speter } 4897601Speter break; 490822Speter } 491822Speter /* 492822Speter * this is the breaks 493822Speter */ 4947601Speter error( errtype 4957601Speter , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)." 4967601Speter , ifilep -> name 4977601Speter , nlp -> n_value 4987601Speter , classify( nlp -> n_desc ) 4997601Speter , nlp -> n_un.n_name 5007601Speter , ( symbolp -> desc == nlp -> n_desc ? "" : " as " ) 5017601Speter , ( symbolp -> desc == nlp -> n_desc 5027601Speter ? "" : article( symbolp -> desc ) ) 5037601Speter , symbolp -> sym_un.sym_str.rfilep -> name 5047601Speter , symbolp -> sym_un.sym_str.rline ); 505822Speter } 506822Speter } 507822Speter 508822Speter /* 509822Speter * quadratically hashed symbol table. 510822Speter * things are never deleted from the hash symbol table. 511822Speter * as more hash table is needed, 512822Speter * a new one is alloc'ed and chained to the end. 513822Speter * search is by rehashing within each table, 514822Speter * traversing chains to next table if unsuccessful. 515822Speter */ 516822Speter struct symbol * 517822Speter entersymbol( name ) 518822Speter char *name; 519822Speter { 5209572Speter static struct symboltableinfo symboltable; 521822Speter char *enteredname; 522822Speter long hashindex; 523822Speter register struct symboltableinfo *tablep; 524822Speter register struct symbol **herep; 525822Speter register struct symbol **limitp; 526822Speter register long increment; 527822Speter 528822Speter enteredname = enterstring( name ); 529822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; 5309572Speter for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) { 531822Speter if ( tablep == NIL ) { 5329572Speter # ifdef SPACEDEBUG 5339572Speter fprintf( stderr , 5349572Speter "[entersymbol] calloc'ing table for %d symbols\n" , 5359572Speter SYMBOLPRIME ); 5369572Speter # endif SPACEDEBUG 5379572Speter for ( tablep = &symboltable 5389572Speter ; tablep->chain != NIL 5399572Speter ; tablep = tablep->chain ) { 5409572Speter continue; 5419572Speter } 5429572Speter tablep->chain = ( struct symboltableinfo * ) 5439572Speter calloc( 1 , sizeof ( struct symboltableinfo ) ); 5449572Speter if ( tablep->chain == NIL ) { 545822Speter error( FATAL , "ran out of memory (entersymbol)" ); 546822Speter } 5479572Speter tablep = tablep->chain; 548822Speter } 549822Speter herep = &( tablep -> entry[ hashindex ] ); 550822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] ); 551822Speter increment = 1; 552822Speter do { 553822Speter if ( *herep == NIL ) { 554822Speter /* empty */ 5559572Speter if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) { 556822Speter /* too full, break for next table */ 557822Speter break; 558822Speter } 559822Speter tablep -> used++; 560822Speter *herep = symbolalloc(); 561822Speter ( *herep ) -> name = enteredname; 562822Speter ( *herep ) -> lookup = NEW; 5639572Speter # ifdef HASHDEBUG 5649572Speter fprintf( stderr , 5659572Speter "[entersymbol] name %s NEW after %d\n" , 5669572Speter enteredname , increment / 2 ); 5679572Speter # endif HASHDEBUG 568822Speter return *herep; 569822Speter } 570822Speter /* a find? */ 571822Speter if ( ( *herep ) -> name == enteredname ) { 572822Speter ( *herep ) -> lookup = OLD; 5739572Speter # ifdef HASHDEBUG 5749572Speter fprintf( stderr , "[entersymbol] name %s OLD at %d\n" , 5759572Speter enteredname , increment / 2 ); 5769572Speter # endif HASHDEBUG 577822Speter return *herep; 578822Speter } 579822Speter herep += increment; 580822Speter if ( herep >= limitp ) { 581822Speter herep -= SYMBOLPRIME; 582822Speter } 583822Speter increment += 2; 584822Speter } while ( increment < SYMBOLPRIME ); 5859572Speter # ifdef HASHDEBUG 5869572Speter fprintf( stderr , "[entersymbol] next symboltable\n" ); 5879572Speter # endif HASHDEBUG 588822Speter } 589822Speter } 590822Speter 591822Speter /* 592822Speter * allocate a symbol from the dynamically allocated symbol table. 593822Speter */ 594822Speter struct symbol * 595822Speter symbolalloc() 596822Speter { 597822Speter static struct symbol *nextsymbol = NIL; 598822Speter static long symbolsleft = 0; 599822Speter struct symbol *newsymbol; 600822Speter 601822Speter if ( symbolsleft <= 0 ) { 6029572Speter # ifdef SPACEDEBUG 6039572Speter fprintf( stderr , 6049572Speter "[symbolalloc] malloc space for %d symbols\n" , 6059572Speter SYMBOLALLOC / sizeof( struct symbol ) ); 6069572Speter # endif SPACEDEBUG 607822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); 608822Speter if ( nextsymbol == 0 ) { 609822Speter error( FATAL , "ran out of memory (symbolalloc)" ); 610822Speter } 611822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); 612822Speter } 613822Speter newsymbol = nextsymbol; 614822Speter nextsymbol++; 615822Speter symbolsleft--; 616822Speter return newsymbol; 617822Speter } 618822Speter 619822Speter /* 620822Speter * hash a string based on all of its characters. 621822Speter */ 622822Speter long 623822Speter hashstring( string ) 624822Speter char *string; 625822Speter { 626822Speter register char *cp; 627822Speter register long value; 628822Speter 629822Speter value = 0; 630822Speter for ( cp = string ; *cp ; cp++ ) { 631822Speter value = ( value * 2 ) + *cp; 632822Speter } 633822Speter return value; 634822Speter } 635822Speter 636822Speter /* 637822Speter * quadratically hashed string table. 638822Speter * things are never deleted from the hash string table. 639822Speter * as more hash table is needed, 640822Speter * a new one is alloc'ed and chained to the end. 641822Speter * search is by rehashing within each table, 642822Speter * traversing chains to next table if unsuccessful. 643822Speter */ 644822Speter char * 645822Speter enterstring( string ) 646822Speter char *string; 647822Speter { 6489572Speter static struct stringtableinfo stringtable; 649822Speter long hashindex; 650822Speter register struct stringtableinfo *tablep; 651822Speter register char **herep; 652822Speter register char **limitp; 653822Speter register long increment; 654822Speter 655822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; 6569572Speter for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) { 657822Speter if ( tablep == NIL ) { 6589572Speter # ifdef SPACEDEBUG 6599572Speter fprintf( stderr , 6609572Speter "[enterstring] calloc space for %d strings\n" , 6619572Speter STRINGPRIME ); 6629572Speter # endif SPACEDEBUG 6639572Speter for ( tablep = &stringtable 6649572Speter ; tablep->chain != NIL 6659572Speter ; tablep = tablep->chain ) { 6669572Speter continue; 6679572Speter } 6689572Speter tablep->chain = ( struct stringtableinfo * ) 6699572Speter calloc( 1 , sizeof ( struct stringtableinfo ) ); 6709572Speter if ( tablep->chain == NIL ) { 671822Speter error( FATAL , "ran out of memory (enterstring)" ); 672822Speter } 6739572Speter tablep = tablep->chain; 674822Speter } 675822Speter herep = &( tablep -> entry[ hashindex ] ); 676822Speter limitp = &( tablep -> entry[ STRINGPRIME ] ); 677822Speter increment = 1; 678822Speter do { 679822Speter if ( *herep == NIL ) { 680822Speter /* empty */ 6819572Speter if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) { 682822Speter /* too full, break for next table */ 683822Speter break; 684822Speter } 685822Speter tablep -> used++; 686822Speter *herep = charalloc( strlen( string ) ); 687822Speter strcpy( *herep , string ); 6889572Speter # ifdef HASHDEBUG 6899572Speter fprintf( stderr , 6909572Speter "[enterstring] string %s copied after %d\n" , 6919572Speter *herep , increment / 2 ); 6929572Speter # endif HASHDEBUG 693822Speter return *herep; 694822Speter } 695822Speter /* quick, check the first chars and then the rest */ 696822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) { 6979572Speter # ifdef HASHDEBUG 6989572Speter fprintf( stderr , 6999572Speter "[enterstring] string %s found after %d\n" , 7009572Speter *herep , increment / 2 ); 7019572Speter # endif HASHDEBUG 702822Speter return *herep; 703822Speter } 704822Speter herep += increment; 705822Speter if ( herep >= limitp ) { 706822Speter herep -= STRINGPRIME; 707822Speter } 708822Speter increment += 2; 709822Speter } while ( increment < STRINGPRIME ); 7109572Speter # ifdef HASHDEBUG 7119572Speter fprintf( stderr , "[enterstring] next stringtable\n" ); 7129572Speter # endif HASHDEBUG 713822Speter } 714822Speter } 715822Speter 716822Speter /* 717822Speter * copy a string to the dynamically allocated character table. 718822Speter */ 719822Speter char * 720822Speter charalloc( length ) 721822Speter register long length; 722822Speter { 723822Speter static char *nextchar = NIL; 724822Speter static long charsleft = 0; 725822Speter register long lengthplus1 = length + 1; 726822Speter register long askfor; 727822Speter char *newstring; 728822Speter 729822Speter if ( charsleft < lengthplus1 ) { 730822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; 7319572Speter # ifdef SPACEDEBUG 7329572Speter fprintf( stderr , "[charalloc] malloc space for %d chars\n" 733822Speter , askfor ); 7349572Speter # endif SPACEDEBUG 735822Speter nextchar = ( char * ) malloc( askfor ); 736822Speter if ( nextchar == 0 ) { 737822Speter error( FATAL , "no room for %d characters" , askfor ); 738822Speter } 739822Speter charsleft = askfor; 740822Speter } 741822Speter newstring = nextchar; 742822Speter nextchar += lengthplus1; 743822Speter charsleft -= lengthplus1; 744822Speter return newstring; 745822Speter } 746822Speter 747822Speter /* 748822Speter * read an archive header for the next element 749822Speter * and find the offset of the one after this. 750822Speter */ 751822Speter BOOL 752822Speter nextelement( ofilep ) 753822Speter struct fileinfo *ofilep; 754822Speter { 755822Speter register char *cp; 756822Speter register long red; 757822Speter register off_t arsize; 758822Speter struct ar_hdr archdr; 759822Speter 760822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 ); 761822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); 762822Speter if ( red != sizeof archdr ) { 763822Speter return FALSE; 764822Speter } 765822Speter /* null terminate the blank-padded name */ 766822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; 767822Speter *cp = '\0'; 768822Speter while ( *--cp == ' ' ) { 769822Speter *cp = '\0'; 770822Speter } 771822Speter /* set up the address of the beginning of next element */ 772822Speter arsize = atol( archdr.ar_size ); 773822Speter /* archive elements are aligned on 0 mod 2 boundaries */ 774822Speter if ( arsize & 1 ) { 775822Speter arsize += 1; 776822Speter } 777822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; 778822Speter /* say we had one */ 779822Speter return TRUE; 780822Speter } 781822Speter 782822Speter /* 783822Speter * variable number of arguments to error, like printf. 784822Speter */ 7857601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ) 7867598Speter int type; 787822Speter char *message; 788822Speter { 7897598Speter errors = type > errors ? type : errors; 7907598Speter if ( wflag && type == WARNING ) { 7917598Speter return; 7927598Speter } 793822Speter fprintf( stderr , "%s: " , program ); 7947598Speter switch ( type ) { 7957598Speter case WARNING: 7967598Speter fprintf( stderr , "Warning: " ); 7977598Speter break; 7987598Speter case ERROR: 7997598Speter fprintf( stderr , "Error: " ); 8007598Speter break; 8017598Speter case FATAL: 8027598Speter fprintf( stderr , "Fatal: " ); 8037598Speter break; 8047598Speter default: 8057598Speter fprintf( stderr , "Ooops: " ); 8067598Speter break; 8077598Speter } 8087601Speter fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 ); 809822Speter fprintf( stderr , "\n" ); 8107598Speter if ( type == FATAL ) { 8117598Speter exit( FATAL ); 812822Speter } 813822Speter } 814822Speter 815822Speter char * 816822Speter classify( type ) 817822Speter unsigned char type; 818822Speter { 819822Speter switch ( type ) { 820822Speter case N_PSO: 821822Speter return "source file"; 822822Speter case N_PSOL: 823822Speter return "include file"; 824844Speter case N_PGLABEL: 825822Speter return "label"; 826844Speter case N_PGCONST: 827822Speter return "constant"; 828844Speter case N_PGTYPE: 829822Speter return "type"; 830822Speter case N_PGVAR: 831822Speter return "variable"; 832844Speter case N_PGFUNC: 833822Speter return "function"; 834844Speter case N_PGPROC: 835822Speter return "procedure"; 836844Speter case N_PEFUNC: 837822Speter return "external function"; 838844Speter case N_PEPROC: 839822Speter return "external procedure"; 8407601Speter case N_PLDATA: 8417601Speter return "library variable"; 8427601Speter case N_PLTEXT: 8437601Speter return "library routine"; 844822Speter default: 845822Speter return "unknown symbol"; 846822Speter } 847822Speter } 8487601Speter 8497601Speter char * 8507601Speter article( type ) 8517601Speter unsigned char type; 8527601Speter { 8537601Speter switch ( type ) { 8547601Speter case N_PSO: 8557601Speter return "a source file"; 8567601Speter case N_PSOL: 8577601Speter return "an include file"; 8587601Speter case N_PGLABEL: 8597601Speter return "a label"; 8607601Speter case N_PGCONST: 8617601Speter return "a constant"; 8627601Speter case N_PGTYPE: 8637601Speter return "a type"; 8647601Speter case N_PGVAR: 8657601Speter return "a variable"; 8667601Speter case N_PGFUNC: 8677601Speter return "a function"; 8687601Speter case N_PGPROC: 8697601Speter return "a procedure"; 8707601Speter case N_PEFUNC: 8717601Speter return "an external function"; 8727601Speter case N_PEPROC: 8737601Speter return "an external procedure"; 8747601Speter case N_PLDATA: 8757601Speter return "a library variable"; 8767601Speter case N_PLTEXT: 8777601Speter return "a library routine"; 8787601Speter default: 8797601Speter return "an unknown symbol"; 8807601Speter } 8817601Speter } 882