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