1822Speter /* Copyright (c) 1980 Regents of the University of California */ 2822Speter 3*7601Speter static char sccsid[] = "@(#)pc3.c 1.9 07/29/82"; 4822Speter 5822Speter /* 6822Speter * Pc3 is a pass in the Berkeley Pascal compilation 7822Speter * process that is performed just prior to linking Pascal 8822Speter * object files. Its purpose is to enforce the rules of 9822Speter * separate compilation for Berkeley Pascal. Pc3 is called 10822Speter * with the same argument list of object files that is sent to 11822Speter * the loader. These checks are performed by pc3 by examining 12822Speter * the symbol tables of the object files: 13822Speter * (1) All source and included files must be "up-to-date" with 14822Speter * the object files of which they are components. 15822Speter * (2) Each global Pascal symbol (label, constant, type, 16822Speter * variable, procedure, or function name) must be uniquely 17822Speter * declared, i.e. declared in only one included file or 18822Speter * source file. 19822Speter * (3) Each external function (or procedure) may be resolved 20822Speter * at most once in a source file which included the 21822Speter * external declaration of the function. 22822Speter * 23822Speter * The symbol table of each object file is scanned and 24822Speter * each global Pascal symbol is placed in a hashed symbol 25822Speter * table. The Pascal compiler has been modified to emit all 26822Speter * Pascal global symbols to the object file symbol table. The 27822Speter * information stored in the symbol table for each such symbol 28822Speter * is: 29822Speter * 30822Speter * - the name of the symbol; 31844Speter * - a subtype descriptor; 32822Speter * - for file symbols, their last modify time; 33822Speter * - the file which logically contains the declaration of 34822Speter * the symbol (not an include file); 35822Speter * - the file which textually contains the declaration of 36822Speter * the symbol (possibly an include file); 37822Speter * - the line number at which the symbol is declared; 38822Speter * - the file which contains the resolution of the symbol. 39822Speter * - the line number at which the symbol is resolved; 40822Speter * 41822Speter * If a symbol has been previously entered into the symbol 42822Speter * table, a check is made that the current declaration is of 43822Speter * the same type and from the same include file as the previous 44822Speter * one. Except for files and functions and procedures, it is 45822Speter * an error for a symbol declaration to be encountered more 46822Speter * than once, unless the re-declarations come from the same 47822Speter * included file as the original. 48822Speter * 49822Speter * As an include file symbol is encountered in a source 50822Speter * file, the symbol table entry of each symbol declared in that 51822Speter * include file is modified to reflect its new logical 52822Speter * inclusion in the source file. File symbols are also 53822Speter * encountered as an included file ends, signaling the 54822Speter * continuation of the enclosing file. 55822Speter * 56822Speter * Functions and procedures which have been declared 57822Speter * external may be resolved by declarations from source files 58822Speter * which included the external declaration of the function. 59822Speter * Functions and procedures may be resolved at most once across 60822Speter * a set of object files. The loader will complain if a 61822Speter * function is not resolved at least once. 62822Speter */ 63822Speter 64832Speter char program[] = "pc"; 65822Speter 66822Speter #include <sys/types.h> 67822Speter #include <ar.h> 68822Speter #include <stdio.h> 69822Speter #include <ctype.h> 70822Speter #include <a.out.h> 71822Speter #include <stab.h> 72822Speter #include <pagsiz.h> 73822Speter #include <stat.h> 74858Speter #include "pstab.h" 75822Speter #include "pc3.h" 76822Speter 777598Speter int errors = NONE; 787598Speter BOOL wflag = FALSE; 79822Speter 80822Speter /* 81822Speter * check each of the argument .o files (or archives of .o files). 82822Speter */ 83822Speter main( argc , argv ) 84822Speter int argc; 85822Speter char **argv; 86822Speter { 87822Speter struct fileinfo ofile; 88822Speter 897598Speter for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { 907598Speter (*argv)++; 917598Speter switch ( **argv ) { 927598Speter default: 937598Speter error( FATAL , "pc3: bad flag -%c\n" , **argv ); 947598Speter case 'w': 957598Speter wflag = TRUE; 967598Speter break; 977598Speter } 987598Speter } 997598Speter for ( /* void */ ; *argv != 0 ; argv++ ) { 100822Speter # ifdef DEBUG 101822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv ); 102822Speter # endif DEBUG 103822Speter ofile.name = *argv; 104822Speter checkfile( &ofile ); 105822Speter } 106822Speter exit( errors ); 107822Speter } 108822Speter 109822Speter /* 110822Speter * check the namelist of a file, or all namelists of an archive. 111822Speter */ 112822Speter checkfile( ofilep ) 113822Speter struct fileinfo *ofilep; 114822Speter { 115822Speter union { 116822Speter char mag_armag[ SARMAG + 1 ]; 117822Speter struct exec mag_exec; 118822Speter } mag_un; 119822Speter int red; 120822Speter struct stat filestat; 121822Speter 122822Speter ofilep -> file = fopen( ofilep -> name , "r" ); 123822Speter if ( ofilep -> file == NULL ) { 1247598Speter error( ERROR , "cannot open: %s" , ofilep -> name ); 125822Speter return; 126822Speter } 127822Speter fstat( fileno( ofilep -> file ) , &filestat ); 128822Speter ofilep -> modtime = filestat.st_mtime; 129822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); 130822Speter if ( red != sizeof mag_un ) { 1317598Speter error( ERROR , "cannot read header: %s" , ofilep -> name ); 132822Speter return; 133822Speter } 134822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) { 135822Speter error( WARNING , "old archive: %s" , ofilep -> name ); 136822Speter return; 137822Speter } 138822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { 139822Speter /* archive, iterate through elements */ 140822Speter # ifdef DEBUG 141822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); 142822Speter # endif DEBUG 143822Speter ofilep -> nextoffset = SARMAG; 144822Speter while ( nextelement( ofilep ) ) { 145822Speter checknl( ofilep ); 146822Speter } 147822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) { 148822Speter /* not a file.o */ 1497598Speter error( ERROR , "bad format: %s" , ofilep -> name ); 150822Speter return; 151822Speter } else { 152822Speter /* a file.o */ 153822Speter # ifdef DEBUG 154822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); 155822Speter # endif DEBUG 156822Speter fseek( ofilep -> file , 0L , 0 ); 157822Speter ofilep -> nextoffset = filestat.st_size; 158822Speter checknl( ofilep ); 159822Speter } 160822Speter fclose( ofilep -> file ); 161822Speter } 162822Speter 163822Speter /* 164822Speter * check the namelist of this file for conflicts with 165822Speter * previously entered symbols. 166822Speter */ 167822Speter checknl( ofilep ) 168822Speter register struct fileinfo *ofilep; 169822Speter { 170822Speter 171822Speter long red; 172831Speter struct exec oexec; 173822Speter off_t symoff; 174822Speter long numsyms; 175822Speter register struct nlist *nlp; 176822Speter register char *stringp; 177822Speter long strsize; 178822Speter long sym; 179822Speter 180831Speter red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); 181831Speter if ( red != sizeof oexec ) { 1827598Speter error( ERROR , "error reading struct exec: %s" 183822Speter , ofilep -> name ); 184822Speter return; 185822Speter } 186831Speter if ( N_BADMAG( oexec ) ) { 187822Speter return; 188822Speter } 189831Speter symoff = N_SYMOFF( oexec ) - sizeof oexec; 190822Speter fseek( ofilep -> file , symoff , 1 ); 191831Speter numsyms = oexec.a_syms / sizeof ( struct nlist ); 192822Speter if ( numsyms == 0 ) { 193822Speter error( WARNING , "no name list: %s" , ofilep -> name ); 194822Speter return; 195822Speter } 196822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); 197822Speter if ( nlp == 0 ) { 198822Speter error( FATAL , "no room for %d nlists" , numsyms ); 199822Speter } 200822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) 201822Speter , ofilep -> file ); 202822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t ) 203822Speter >= ofilep -> nextoffset ) { 204822Speter error( WARNING , "no string table (old format .o?)" 205822Speter , ofilep -> name ); 206822Speter return; 207822Speter } 208822Speter red = fread( (char *) &strsize , sizeof strsize , 1 209822Speter , ofilep -> file ); 210822Speter if ( red != 1 ) { 211822Speter error( WARNING , "no string table (old format .o?)" 212822Speter , ofilep -> name ); 213822Speter return; 214822Speter } 215822Speter stringp = ( char * ) malloc( strsize ); 216822Speter if ( stringp == 0 ) { 217822Speter error( FATAL , "no room for %d bytes of strings" , strsize ); 218822Speter } 219822Speter red = fread( stringp + sizeof strsize 220822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); 221822Speter if ( red != 1 ) { 222822Speter error( WARNING , "error reading string table: %s" 223822Speter , ofilep -> name ); 224822Speter } 225822Speter # ifdef DEBUG 226822Speter fprintf( stderr , "[checknl] %s: %d symbols\n" 227822Speter , ofilep -> name , numsyms ); 228822Speter # endif DEBUG 229822Speter for ( sym = 0 ; sym < numsyms ; sym++) { 230822Speter if ( nlp[ sym ].n_un.n_strx ) { 231822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; 232822Speter } else { 233822Speter nlp[ sym ].n_un.n_name = ""; 234822Speter } 235822Speter checksymbol( &nlp[ sym ] , ofilep ); 236822Speter } 237822Speter if ( nlp ) { 238822Speter free( nlp ); 239822Speter } 240822Speter if ( stringp ) { 241822Speter free( stringp ); 242822Speter } 243822Speter } 244822Speter 245822Speter /* 246822Speter * check a symbol. 247822Speter * look it up in the hashed symbol table, 248822Speter * entering it if necessary. 249822Speter * this maintains a state of which .p and .i files 250822Speter * it is currently in the midst from the nlist entries 251822Speter * for source and included files. 252822Speter * if we are inside a .p but not a .i, pfilep == ifilep. 253822Speter */ 254822Speter checksymbol( nlp , ofilep ) 255822Speter struct nlist *nlp; 256822Speter struct fileinfo *ofilep; 257822Speter { 258822Speter static struct symbol *pfilep = NIL; 259822Speter static struct symbol *ifilep = NIL; 260822Speter register struct symbol *symbolp; 261*7601Speter int errtype; 262822Speter 263822Speter # ifdef DEBUG 264822Speter if ( pfilep && ifilep ) { 265822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" 266822Speter , pfilep -> name , ifilep -> name ); 267822Speter } 268844Speter fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" 269844Speter , nlp -> n_un.n_name , nlp -> n_desc 270844Speter , classify( nlp -> n_desc ) ); 271822Speter # endif DEBUG 272844Speter if ( nlp -> n_type != N_PC ) { 273844Speter /* don't care about the others */ 274844Speter return; 275822Speter } 276844Speter symbolp = entersymbol( nlp -> n_un.n_name ); 277822Speter if ( symbolp -> lookup == NEW ) { 278822Speter # ifdef DEBUG 279822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n" 280822Speter , symbolp -> name ); 281822Speter # endif DEBUG 282844Speter symbolp -> desc = nlp -> n_desc; 283844Speter switch ( symbolp -> desc ) { 2847550Speter default: 2857550Speter error( FATAL , "panic: [checksymbol] NEW" ); 286844Speter case N_PGLABEL: 287844Speter case N_PGCONST: 288844Speter case N_PGTYPE: 289822Speter case N_PGVAR: 290844Speter case N_PGFUNC: 291844Speter case N_PGPROC: 292*7601Speter case N_PLDATA: 293*7601Speter case N_PLTEXT: 294831Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 295831Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 296831Speter symbolp -> sym_un.sym_str.fromp = pfilep; 297831Speter symbolp -> sym_un.sym_str.fromi = ifilep; 298831Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 299831Speter return; 300844Speter case N_PEFUNC: 301844Speter case N_PEPROC: 302831Speter symbolp -> sym_un.sym_str.rfilep = NIL; 303831Speter symbolp -> sym_un.sym_str.rline = 0; 304831Speter /* 305831Speter * functions can only be declared external 306831Speter * in included files. 307831Speter */ 308831Speter if ( pfilep == ifilep ) { 309831Speter error( WARNING 310831Speter , "%s, line %d: %s %s must be declared in included file" 311831Speter , pfilep -> name , nlp -> n_value 312844Speter , classify( symbolp -> desc ) 313831Speter , symbolp -> name ); 314831Speter } 315822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 316822Speter symbolp -> sym_un.sym_str.fromi = ifilep; 317822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 318822Speter return; 319822Speter case N_PSO: 320822Speter pfilep = symbolp; 321822Speter /* and fall through */ 322822Speter case N_PSOL: 323822Speter ifilep = symbolp; 324822Speter symbolp -> sym_un.modtime = mtime( symbolp -> name ); 325822Speter if ( symbolp -> sym_un.modtime > ofilep -> modtime ) { 326822Speter error( WARNING , "%s is out of date with %s" 327822Speter , ofilep -> name , symbolp -> name ); 328822Speter } 329822Speter return; 330822Speter } 331822Speter } else { 332822Speter # ifdef DEBUG 333822Speter fprintf( stderr , "[checksymbol] ->name %s is OLD\n" 334822Speter , symbolp -> name ); 335822Speter # endif DEBUG 336*7601Speter errtype = ERROR; 337844Speter switch ( symbolp -> desc ) { 3387550Speter default: 3397550Speter error( FATAL , "panic [checksymbol] OLD" ); 340822Speter case N_PSO: 341822Speter /* 342822Speter * finding a file again means you are back 343822Speter * in it after finishing an include file. 344822Speter */ 345822Speter pfilep = symbolp; 346822Speter /* and fall through */ 347822Speter case N_PSOL: 348822Speter /* 349822Speter * include files can be seen more than once, 350822Speter * but they still have to be timechecked. 351822Speter * (this will complain twice for out of date 352822Speter * include files which include other files. 353822Speter * sigh.) 354822Speter */ 355822Speter ifilep = symbolp; 356822Speter if ( symbolp -> sym_un.modtime > ofilep -> modtime ) { 357822Speter error( WARNING , "%s is out of date with %s" 358822Speter , ofilep -> name , symbolp -> name ); 359822Speter } 360822Speter return; 361844Speter case N_PEFUNC: 362844Speter case N_PEPROC: 363822Speter /* 3647550Speter * this might be the resolution of the external 3657550Speter * has to match func/proc of external 3667550Speter * and has to have included external 3677550Speter * and has to not have been previously resolved. 368822Speter */ 3697550Speter if ( ( ( symbolp -> desc == N_PEFUNC 3707550Speter && nlp -> n_desc == N_PGFUNC ) 3717550Speter || ( symbolp -> desc == N_PEPROC 3727550Speter && nlp -> n_desc == N_PGPROC ) ) 3737550Speter && ( symbolp -> sym_un.sym_str.fromp == pfilep ) 3747550Speter && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { 3757550Speter /* 3767550Speter * resolve external 3777550Speter */ 3787550Speter # ifdef DEBUG 3797550Speter fprintf( stderr , "[checksymbol] resolving external\n" ); 3807550Speter # endif DEBUG 3817550Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 3827550Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 3837550Speter return; 384822Speter } 385822Speter /* 3867550Speter * otherwise, it might be another external, 3877550Speter * which is okay if it's 3887550Speter * the same type and from the same include file 389822Speter */ 3907550Speter if ( ( ( symbolp -> desc == N_PEFUNC 3917550Speter && nlp -> n_desc == N_PEFUNC ) 3927550Speter || ( symbolp -> desc == N_PEPROC 3937550Speter && nlp -> n_desc == N_PEPROC ) ) 3947550Speter && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { 3957550Speter /* 3967550Speter * just another pretty external 3977550Speter * make it look like it comes from here. 3987550Speter */ 3997550Speter # ifdef DEBUG 4007550Speter fprintf( stderr , "[checksymbol] just another pretty external\n" ); 4017550Speter # endif DEBUG 4027550Speter symbolp -> sym_un.sym_str.fromp = pfilep; 4037550Speter return; 404822Speter } 405822Speter /* 4067550Speter * something is wrong 4077598Speter * if it's not resolved, use the header file 4087598Speter * otherwise, it's just a regular error 409822Speter */ 4107598Speter if ( symbolp -> sym_un.sym_str.rfilep == NIL ) { 4117598Speter error( ERROR , 412*7601Speter "%s, line %d: %s is already defined\n\t(%s, line %d)." , 4137598Speter ifilep -> name , nlp -> n_value , 4147598Speter nlp -> n_un.n_name , 4157598Speter symbolp -> sym_un.sym_str.fromi -> name , 4167598Speter symbolp -> sym_un.sym_str.iline ); 4177598Speter return; 4187598Speter } 4197598Speter break; 420844Speter case N_PGFUNC: 421844Speter case N_PGPROC: 422822Speter /* 423822Speter * functions may not be seen more than once. 424822Speter * the loader will complain about 425822Speter * `multiply defined', but we can, too. 426822Speter */ 427822Speter break; 428844Speter case N_PGLABEL: 429844Speter case N_PGCONST: 430844Speter case N_PGTYPE: 431822Speter case N_PGVAR: 432822Speter /* 433822Speter * labels, constants, types, variables 434822Speter * and external declarations 435822Speter * may be seen as many times as they want, 436822Speter * as long as they come from the same include file. 437822Speter * make it look like they come from this .p file. 438822Speter */ 439822Speter included: 440844Speter if ( nlp -> n_desc != symbolp -> desc 441822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) { 442822Speter break; 443822Speter } 444822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 445822Speter return; 446*7601Speter case N_PLDATA: 447*7601Speter case N_PLTEXT: 448*7601Speter switch ( nlp -> n_desc ) { 449*7601Speter default: 450*7601Speter error( FATAL , "pc3: unknown stab 0x%x" 451*7601Speter , nlp -> n_desc ); 452*7601Speter return; 453*7601Speter case N_PSO: 454*7601Speter case N_PSOL: 455*7601Speter case N_PGCONST: 456*7601Speter case N_PGTYPE: 457*7601Speter /* these won't conflict with library */ 458*7601Speter return; 459*7601Speter case N_PGLABEL: 460*7601Speter case N_PGVAR: 461*7601Speter case N_PGFUNC: 462*7601Speter case N_PGPROC: 463*7601Speter case N_PEFUNC: 464*7601Speter case N_PEPROC: 465*7601Speter case N_PLDATA: 466*7601Speter case N_PLTEXT: 467*7601Speter errtype = WARNING; 468*7601Speter break; 469*7601Speter } 470*7601Speter break; 471822Speter } 472822Speter /* 473822Speter * this is the breaks 474822Speter */ 475*7601Speter error( errtype 476*7601Speter , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)." 477*7601Speter , ifilep -> name 478*7601Speter , nlp -> n_value 479*7601Speter , classify( nlp -> n_desc ) 480*7601Speter , nlp -> n_un.n_name 481*7601Speter , ( symbolp -> desc == nlp -> n_desc ? "" : " as " ) 482*7601Speter , ( symbolp -> desc == nlp -> n_desc 483*7601Speter ? "" : article( symbolp -> desc ) ) 484*7601Speter , symbolp -> sym_un.sym_str.rfilep -> name 485*7601Speter , symbolp -> sym_un.sym_str.rline ); 486822Speter } 487822Speter } 488822Speter 489822Speter /* 490822Speter * quadratically hashed symbol table. 491822Speter * things are never deleted from the hash symbol table. 492822Speter * as more hash table is needed, 493822Speter * a new one is alloc'ed and chained to the end. 494822Speter * search is by rehashing within each table, 495822Speter * traversing chains to next table if unsuccessful. 496822Speter */ 497822Speter struct symbol * 498822Speter entersymbol( name ) 499822Speter char *name; 500822Speter { 501822Speter static struct symboltableinfo *symboltable = NIL; 502822Speter char *enteredname; 503822Speter long hashindex; 504822Speter register struct symboltableinfo *tablep; 505822Speter register struct symbol **herep; 506822Speter register struct symbol **limitp; 507822Speter register long increment; 508822Speter 509822Speter enteredname = enterstring( name ); 510822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; 511822Speter for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) { 512822Speter if ( tablep == NIL ) { 513822Speter # ifdef DEBUG 514822Speter fprintf( stderr , "[entersymbol] calloc\n" ); 515822Speter # endif DEBUG 516822Speter tablep = ( struct symboltableinfo * ) 517822Speter calloc( sizeof ( struct symboltableinfo ) , 1 ); 518822Speter if ( tablep == NIL ) { 519822Speter error( FATAL , "ran out of memory (entersymbol)" ); 520822Speter } 521822Speter if ( symboltable == NIL ) { 522822Speter symboltable = tablep; 523822Speter } 524822Speter } 525822Speter herep = &( tablep -> entry[ hashindex ] ); 526822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] ); 527822Speter increment = 1; 528822Speter do { 529822Speter # ifdef DEBUG 530822Speter fprintf( stderr , "[entersymbol] increment %d\n" 531822Speter , increment ); 532822Speter # endif DEBUG 533822Speter if ( *herep == NIL ) { 534822Speter /* empty */ 535822Speter if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) { 536822Speter /* too full, break for next table */ 537822Speter break; 538822Speter } 539822Speter tablep -> used++; 540822Speter *herep = symbolalloc(); 541822Speter ( *herep ) -> name = enteredname; 542822Speter ( *herep ) -> lookup = NEW; 543822Speter # ifdef DEBUG 544822Speter fprintf( stderr , "[entersymbol] name %s NEW\n" 545822Speter , enteredname ); 546822Speter # endif DEBUG 547822Speter return *herep; 548822Speter } 549822Speter /* a find? */ 550822Speter if ( ( *herep ) -> name == enteredname ) { 551822Speter ( *herep ) -> lookup = OLD; 552822Speter # ifdef DEBUG 553822Speter fprintf( stderr , "[entersymbol] name %s OLD\n" 554822Speter , enteredname ); 555822Speter # endif DEBUG 556822Speter return *herep; 557822Speter } 558822Speter herep += increment; 559822Speter if ( herep >= limitp ) { 560822Speter herep -= SYMBOLPRIME; 561822Speter } 562822Speter increment += 2; 563822Speter } while ( increment < SYMBOLPRIME ); 564822Speter } 565822Speter } 566822Speter 567822Speter /* 568822Speter * allocate a symbol from the dynamically allocated symbol table. 569822Speter */ 570822Speter struct symbol * 571822Speter symbolalloc() 572822Speter { 573822Speter static struct symbol *nextsymbol = NIL; 574822Speter static long symbolsleft = 0; 575822Speter struct symbol *newsymbol; 576822Speter 577822Speter if ( symbolsleft <= 0 ) { 578822Speter # ifdef DEBUG 579822Speter fprintf( stderr , "[symbolalloc] malloc\n" ); 580822Speter # endif DEBUG 581822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); 582822Speter if ( nextsymbol == 0 ) { 583822Speter error( FATAL , "ran out of memory (symbolalloc)" ); 584822Speter } 585822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); 586822Speter } 587822Speter newsymbol = nextsymbol; 588822Speter nextsymbol++; 589822Speter symbolsleft--; 590822Speter return newsymbol; 591822Speter } 592822Speter 593822Speter /* 594822Speter * hash a string based on all of its characters. 595822Speter */ 596822Speter long 597822Speter hashstring( string ) 598822Speter char *string; 599822Speter { 600822Speter register char *cp; 601822Speter register long value; 602822Speter 603822Speter value = 0; 604822Speter for ( cp = string ; *cp ; cp++ ) { 605822Speter value = ( value * 2 ) + *cp; 606822Speter } 607822Speter return value; 608822Speter } 609822Speter 610822Speter /* 611822Speter * quadratically hashed string table. 612822Speter * things are never deleted from the hash string table. 613822Speter * as more hash table is needed, 614822Speter * a new one is alloc'ed and chained to the end. 615822Speter * search is by rehashing within each table, 616822Speter * traversing chains to next table if unsuccessful. 617822Speter */ 618822Speter char * 619822Speter enterstring( string ) 620822Speter char *string; 621822Speter { 622822Speter static struct stringtableinfo *stringtable = NIL; 623822Speter long hashindex; 624822Speter register struct stringtableinfo *tablep; 625822Speter register char **herep; 626822Speter register char **limitp; 627822Speter register long increment; 628822Speter 629822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; 630822Speter for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) { 631822Speter if ( tablep == NIL ) { 632822Speter # ifdef DEBUG 633822Speter fprintf( stderr , "[enterstring] calloc\n" ); 634822Speter # endif DEBUG 635822Speter tablep = ( struct stringtableinfo * ) 636822Speter calloc( sizeof ( struct stringtableinfo ) , 1 ); 637822Speter if ( tablep == NIL ) { 638822Speter error( FATAL , "ran out of memory (enterstring)" ); 639822Speter } 640822Speter if ( stringtable == NIL ) { 641822Speter stringtable = tablep; 642822Speter } 643822Speter } 644822Speter herep = &( tablep -> entry[ hashindex ] ); 645822Speter limitp = &( tablep -> entry[ STRINGPRIME ] ); 646822Speter increment = 1; 647822Speter do { 648822Speter # ifdef DEBUG 649822Speter fprintf( stderr , "[enterstring] increment %d\n" 650822Speter , increment ); 651822Speter # endif DEBUG 652822Speter if ( *herep == NIL ) { 653822Speter /* empty */ 654822Speter if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) { 655822Speter /* too full, break for next table */ 656822Speter break; 657822Speter } 658822Speter tablep -> used++; 659822Speter *herep = charalloc( strlen( string ) ); 660822Speter strcpy( *herep , string ); 661822Speter # ifdef DEBUG 662822Speter fprintf( stderr , "[enterstring] string %s copied\n" 663822Speter , *herep ); 664822Speter # endif DEBUG 665822Speter return *herep; 666822Speter } 667822Speter /* quick, check the first chars and then the rest */ 668822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) { 669822Speter # ifdef DEBUG 670822Speter fprintf( stderr , "[enterstring] string %s found\n" 671822Speter , *herep ); 672822Speter # endif DEBUG 673822Speter return *herep; 674822Speter } 675822Speter herep += increment; 676822Speter if ( herep >= limitp ) { 677822Speter herep -= STRINGPRIME; 678822Speter } 679822Speter increment += 2; 680822Speter } while ( increment < STRINGPRIME ); 681822Speter } 682822Speter } 683822Speter 684822Speter /* 685822Speter * copy a string to the dynamically allocated character table. 686822Speter */ 687822Speter char * 688822Speter charalloc( length ) 689822Speter register long length; 690822Speter { 691822Speter static char *nextchar = NIL; 692822Speter static long charsleft = 0; 693822Speter register long lengthplus1 = length + 1; 694822Speter register long askfor; 695822Speter char *newstring; 696822Speter 697822Speter if ( charsleft < lengthplus1 ) { 698822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; 699822Speter # ifdef DEBUG 700822Speter fprintf( stderr , "[charalloc] malloc( %d )\n" 701822Speter , askfor ); 702822Speter # endif DEBUG 703822Speter nextchar = ( char * ) malloc( askfor ); 704822Speter if ( nextchar == 0 ) { 705822Speter error( FATAL , "no room for %d characters" , askfor ); 706822Speter } 707822Speter charsleft = askfor; 708822Speter } 709822Speter newstring = nextchar; 710822Speter nextchar += lengthplus1; 711822Speter charsleft -= lengthplus1; 712822Speter return newstring; 713822Speter } 714822Speter 715822Speter /* 716822Speter * read an archive header for the next element 717822Speter * and find the offset of the one after this. 718822Speter */ 719822Speter BOOL 720822Speter nextelement( ofilep ) 721822Speter struct fileinfo *ofilep; 722822Speter { 723822Speter register char *cp; 724822Speter register long red; 725822Speter register off_t arsize; 726822Speter struct ar_hdr archdr; 727822Speter 728822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 ); 729822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); 730822Speter if ( red != sizeof archdr ) { 731822Speter return FALSE; 732822Speter } 733822Speter /* null terminate the blank-padded name */ 734822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; 735822Speter *cp = '\0'; 736822Speter while ( *--cp == ' ' ) { 737822Speter *cp = '\0'; 738822Speter } 739822Speter /* set up the address of the beginning of next element */ 740822Speter arsize = atol( archdr.ar_size ); 741822Speter /* archive elements are aligned on 0 mod 2 boundaries */ 742822Speter if ( arsize & 1 ) { 743822Speter arsize += 1; 744822Speter } 745822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; 746822Speter /* say we had one */ 747822Speter return TRUE; 748822Speter } 749822Speter 750822Speter /* 751822Speter * variable number of arguments to error, like printf. 752822Speter */ 753*7601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ) 7547598Speter int type; 755822Speter char *message; 756822Speter { 7577598Speter errors = type > errors ? type : errors; 7587598Speter if ( wflag && type == WARNING ) { 7597598Speter return; 7607598Speter } 761822Speter fprintf( stderr , "%s: " , program ); 7627598Speter switch ( type ) { 7637598Speter case WARNING: 7647598Speter fprintf( stderr , "Warning: " ); 7657598Speter break; 7667598Speter case ERROR: 7677598Speter fprintf( stderr , "Error: " ); 7687598Speter break; 7697598Speter case FATAL: 7707598Speter fprintf( stderr , "Fatal: " ); 7717598Speter break; 7727598Speter default: 7737598Speter fprintf( stderr , "Ooops: " ); 7747598Speter break; 7757598Speter } 776*7601Speter fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 ); 777822Speter fprintf( stderr , "\n" ); 7787598Speter if ( type == FATAL ) { 7797598Speter exit( FATAL ); 780822Speter } 781822Speter } 782822Speter 783822Speter /* 784822Speter * find the last modify time of a file. 785822Speter * on error, return the current time. 786822Speter */ 787822Speter time_t 788822Speter mtime( filename ) 789822Speter char *filename; 790822Speter { 791822Speter struct stat filestat; 792822Speter 793822Speter # ifdef DEBUG 794822Speter fprintf( stderr , "[mtime] filename %s\n" 795822Speter , filename ); 796822Speter # endif DEBUG 797829Speter if ( stat( filename , &filestat ) != 0 ) { 7987598Speter error( WARNING , "%s: cannot stat" , filename ); 799822Speter return ( (time_t) time( 0 ) ); 800822Speter } 801822Speter return filestat.st_mtime; 802822Speter } 803822Speter 804822Speter char * 805822Speter classify( type ) 806822Speter unsigned char type; 807822Speter { 808822Speter switch ( type ) { 809822Speter case N_PSO: 810822Speter return "source file"; 811822Speter case N_PSOL: 812822Speter return "include file"; 813844Speter case N_PGLABEL: 814822Speter return "label"; 815844Speter case N_PGCONST: 816822Speter return "constant"; 817844Speter case N_PGTYPE: 818822Speter return "type"; 819822Speter case N_PGVAR: 820822Speter return "variable"; 821844Speter case N_PGFUNC: 822822Speter return "function"; 823844Speter case N_PGPROC: 824822Speter return "procedure"; 825844Speter case N_PEFUNC: 826822Speter return "external function"; 827844Speter case N_PEPROC: 828822Speter return "external procedure"; 829*7601Speter case N_PLDATA: 830*7601Speter return "library variable"; 831*7601Speter case N_PLTEXT: 832*7601Speter return "library routine"; 833822Speter default: 834822Speter return "unknown symbol"; 835822Speter } 836822Speter } 837*7601Speter 838*7601Speter char * 839*7601Speter article( type ) 840*7601Speter unsigned char type; 841*7601Speter { 842*7601Speter switch ( type ) { 843*7601Speter case N_PSO: 844*7601Speter return "a source file"; 845*7601Speter case N_PSOL: 846*7601Speter return "an include file"; 847*7601Speter case N_PGLABEL: 848*7601Speter return "a label"; 849*7601Speter case N_PGCONST: 850*7601Speter return "a constant"; 851*7601Speter case N_PGTYPE: 852*7601Speter return "a type"; 853*7601Speter case N_PGVAR: 854*7601Speter return "a variable"; 855*7601Speter case N_PGFUNC: 856*7601Speter return "a function"; 857*7601Speter case N_PGPROC: 858*7601Speter return "a procedure"; 859*7601Speter case N_PEFUNC: 860*7601Speter return "an external function"; 861*7601Speter case N_PEPROC: 862*7601Speter return "an external procedure"; 863*7601Speter case N_PLDATA: 864*7601Speter return "a library variable"; 865*7601Speter case N_PLTEXT: 866*7601Speter return "a library routine"; 867*7601Speter default: 868*7601Speter return "an unknown symbol"; 869*7601Speter } 870*7601Speter } 871