1*48061Sbostic /*- 2*48061Sbostic * Copyright (c) 1980, 1982, 1983 The Regents of the University of California. 3*48061Sbostic * All rights reserved. 4*48061Sbostic * 5*48061Sbostic * %sccs.include.redist.c% 622261Sdist */ 722261Sdist 813617Ssam #ifndef lint 922261Sdist char copyright[] = 10*48061Sbostic "@(#) Copyright (c) 1980, 1982, 1983 The Regents of the University of California.\n\ 1122261Sdist All rights reserved.\n"; 12*48061Sbostic #endif /* not lint */ 13822Speter 1422261Sdist #ifndef lint 15*48061Sbostic static char sccsid[] = "@(#)pc3.c 5.2 (Berkeley) 04/16/91"; 16*48061Sbostic #endif /* not lint */ 1722261Sdist 18822Speter /* 19822Speter * Pc3 is a pass in the Berkeley Pascal compilation 20822Speter * process that is performed just prior to linking Pascal 21822Speter * object files. Its purpose is to enforce the rules of 22822Speter * separate compilation for Berkeley Pascal. Pc3 is called 23822Speter * with the same argument list of object files that is sent to 24822Speter * the loader. These checks are performed by pc3 by examining 25822Speter * the symbol tables of the object files: 2614129Speter * (1) All .o files must be up to date with respect to the 2714129Speter * runtime libraries. 28822Speter * (2) Each global Pascal symbol (label, constant, type, 29822Speter * variable, procedure, or function name) must be uniquely 30822Speter * declared, i.e. declared in only one included file or 31822Speter * source file. 32822Speter * (3) Each external function (or procedure) may be resolved 33822Speter * at most once in a source file which included the 34822Speter * external declaration of the function. 35822Speter * 36822Speter * The symbol table of each object file is scanned and 37822Speter * each global Pascal symbol is placed in a hashed symbol 38822Speter * table. The Pascal compiler has been modified to emit all 39822Speter * Pascal global symbols to the object file symbol table. The 40822Speter * information stored in the symbol table for each such symbol 41822Speter * is: 42822Speter * 43822Speter * - the name of the symbol; 44844Speter * - a subtype descriptor; 45822Speter * - the file which logically contains the declaration of 4614129Speter * the symbol or which caused the inclusion of an include file. 4714129Speter * - for included files: 4814129Speter * - a checksum; 4914129Speter * - for symbols: 5014129Speter * - the file which textually contains the declaration of 5114129Speter * the symbol (possibly an include file); 5214129Speter * - the line number at which the symbol is declared; 5314129Speter * - the file which contains the resolution of the symbol. 5414129Speter * - the line number at which the symbol is resolved; 55822Speter * 56822Speter * If a symbol has been previously entered into the symbol 57822Speter * table, a check is made that the current declaration is of 58822Speter * the same type and from the same include file as the previous 59822Speter * one. Except for files and functions and procedures, it is 60822Speter * an error for a symbol declaration to be encountered more 61822Speter * than once, unless the re-declarations come from the same 62822Speter * included file as the original. 63822Speter * 64822Speter * As an include file symbol is encountered in a source 65822Speter * file, the symbol table entry of each symbol declared in that 66822Speter * include file is modified to reflect its new logical 67822Speter * inclusion in the source file. File symbols are also 68822Speter * encountered as an included file ends, signaling the 69822Speter * continuation of the enclosing file. 70822Speter * 71822Speter * Functions and procedures which have been declared 72822Speter * external may be resolved by declarations from source files 73822Speter * which included the external declaration of the function. 74822Speter * Functions and procedures may be resolved at most once across 75822Speter * a set of object files. The loader will complain if a 76822Speter * function is not resolved at least once. 77822Speter */ 78822Speter 79832Speter char program[] = "pc"; 80822Speter 81822Speter #include <sys/types.h> 8213617Ssam #include <sys/stat.h> 83822Speter #include <ar.h> 84822Speter #include <stdio.h> 85822Speter #include <ctype.h> 86822Speter #include <a.out.h> 87822Speter #include <stab.h> 88858Speter #include "pstab.h" 89822Speter #include "pc3.h" 90822Speter 917598Speter int errors = NONE; 927598Speter BOOL wflag = FALSE; 93822Speter 94822Speter /* 95822Speter * check each of the argument .o files (or archives of .o files). 96822Speter */ 97822Speter main( argc , argv ) 98822Speter int argc; 99822Speter char **argv; 100822Speter { 101822Speter struct fileinfo ofile; 102822Speter 1037598Speter for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { 1047598Speter (*argv)++; 1057598Speter switch ( **argv ) { 1067598Speter default: 1077598Speter error( FATAL , "pc3: bad flag -%c\n" , **argv ); 1087598Speter case 'w': 1097598Speter wflag = TRUE; 1107598Speter break; 1117598Speter } 1127598Speter } 1137598Speter for ( /* void */ ; *argv != 0 ; argv++ ) { 114822Speter # ifdef DEBUG 115822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv ); 116822Speter # endif DEBUG 117822Speter ofile.name = *argv; 118822Speter checkfile( &ofile ); 119822Speter } 120822Speter exit( errors ); 121822Speter } 122822Speter 123822Speter /* 124822Speter * check the namelist of a file, or all namelists of an archive. 125822Speter */ 126822Speter checkfile( ofilep ) 127822Speter struct fileinfo *ofilep; 128822Speter { 129822Speter union { 130822Speter char mag_armag[ SARMAG + 1 ]; 131822Speter struct exec mag_exec; 132822Speter } mag_un; 133822Speter int red; 134822Speter struct stat filestat; 135822Speter 136822Speter ofilep -> file = fopen( ofilep -> name , "r" ); 137822Speter if ( ofilep -> file == NULL ) { 1387598Speter error( ERROR , "cannot open: %s" , ofilep -> name ); 139822Speter return; 140822Speter } 141822Speter fstat( fileno( ofilep -> file ) , &filestat ); 142822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); 143822Speter if ( red != sizeof mag_un ) { 1447598Speter error( ERROR , "cannot read header: %s" , ofilep -> name ); 145822Speter return; 146822Speter } 147822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) { 148822Speter error( WARNING , "old archive: %s" , ofilep -> name ); 149822Speter return; 150822Speter } 151822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { 152822Speter /* archive, iterate through elements */ 153822Speter # ifdef DEBUG 154822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); 155822Speter # endif DEBUG 156822Speter ofilep -> nextoffset = SARMAG; 157822Speter while ( nextelement( ofilep ) ) { 158822Speter checknl( ofilep ); 159822Speter } 160822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) { 161822Speter /* not a file.o */ 1627598Speter error( ERROR , "bad format: %s" , ofilep -> name ); 163822Speter return; 164822Speter } else { 165822Speter /* a file.o */ 166822Speter # ifdef DEBUG 167822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); 168822Speter # endif DEBUG 169822Speter fseek( ofilep -> file , 0L , 0 ); 170822Speter ofilep -> nextoffset = filestat.st_size; 171822Speter checknl( ofilep ); 172822Speter } 173822Speter fclose( ofilep -> file ); 174822Speter } 175822Speter 176822Speter /* 177822Speter * check the namelist of this file for conflicts with 178822Speter * previously entered symbols. 179822Speter */ 180822Speter checknl( ofilep ) 181822Speter register struct fileinfo *ofilep; 182822Speter { 183822Speter 184822Speter long red; 185831Speter struct exec oexec; 186822Speter off_t symoff; 187822Speter long numsyms; 188822Speter register struct nlist *nlp; 189822Speter register char *stringp; 190822Speter long strsize; 191822Speter long sym; 192822Speter 193831Speter red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); 194831Speter if ( red != sizeof oexec ) { 1957598Speter error( ERROR , "error reading struct exec: %s" 196822Speter , ofilep -> name ); 197822Speter return; 198822Speter } 199831Speter if ( N_BADMAG( oexec ) ) { 200822Speter return; 201822Speter } 202831Speter symoff = N_SYMOFF( oexec ) - sizeof oexec; 203822Speter fseek( ofilep -> file , symoff , 1 ); 204831Speter numsyms = oexec.a_syms / sizeof ( struct nlist ); 205822Speter if ( numsyms == 0 ) { 206822Speter error( WARNING , "no name list: %s" , ofilep -> name ); 207822Speter return; 208822Speter } 209822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); 210822Speter if ( nlp == 0 ) { 211822Speter error( FATAL , "no room for %d nlists" , numsyms ); 212822Speter } 213822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) 214822Speter , ofilep -> file ); 215822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t ) 216822Speter >= ofilep -> nextoffset ) { 217822Speter error( WARNING , "no string table (old format .o?)" 218822Speter , ofilep -> name ); 219822Speter return; 220822Speter } 221822Speter red = fread( (char *) &strsize , sizeof strsize , 1 222822Speter , ofilep -> file ); 223822Speter if ( red != 1 ) { 224822Speter error( WARNING , "no string table (old format .o?)" 225822Speter , ofilep -> name ); 226822Speter return; 227822Speter } 228822Speter stringp = ( char * ) malloc( strsize ); 229822Speter if ( stringp == 0 ) { 230822Speter error( FATAL , "no room for %d bytes of strings" , strsize ); 231822Speter } 232822Speter red = fread( stringp + sizeof strsize 233822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); 234822Speter if ( red != 1 ) { 235822Speter error( WARNING , "error reading string table: %s" 236822Speter , ofilep -> name ); 237822Speter } 238822Speter # ifdef DEBUG 239822Speter fprintf( stderr , "[checknl] %s: %d symbols\n" 240822Speter , ofilep -> name , numsyms ); 241822Speter # endif DEBUG 242822Speter for ( sym = 0 ; sym < numsyms ; sym++) { 243822Speter if ( nlp[ sym ].n_un.n_strx ) { 244822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; 245822Speter } else { 246822Speter nlp[ sym ].n_un.n_name = ""; 247822Speter } 248822Speter checksymbol( &nlp[ sym ] , ofilep ); 249822Speter } 250822Speter if ( nlp ) { 251822Speter free( nlp ); 252822Speter } 253822Speter if ( stringp ) { 254822Speter free( stringp ); 255822Speter } 256822Speter } 257822Speter 258822Speter /* 259822Speter * check a symbol. 260822Speter * look it up in the hashed symbol table, 261822Speter * entering it if necessary. 262822Speter * this maintains a state of which .p and .i files 263822Speter * it is currently in the midst from the nlist entries 264822Speter * for source and included files. 265822Speter * if we are inside a .p but not a .i, pfilep == ifilep. 266822Speter */ 267822Speter checksymbol( nlp , ofilep ) 268822Speter struct nlist *nlp; 269822Speter struct fileinfo *ofilep; 270822Speter { 271822Speter static struct symbol *pfilep = NIL; 272822Speter static struct symbol *ifilep = NIL; 273822Speter register struct symbol *symbolp; 2747601Speter int errtype; 275822Speter 276822Speter # ifdef DEBUG 277822Speter if ( pfilep && ifilep ) { 278822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" 279822Speter , pfilep -> name , ifilep -> name ); 280822Speter } 281844Speter fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" 282844Speter , nlp -> n_un.n_name , nlp -> n_desc 283844Speter , classify( nlp -> n_desc ) ); 284822Speter # endif DEBUG 285844Speter if ( nlp -> n_type != N_PC ) { 286844Speter /* don't care about the others */ 287844Speter return; 288822Speter } 289844Speter symbolp = entersymbol( nlp -> n_un.n_name ); 290822Speter if ( symbolp -> lookup == NEW ) { 291822Speter # ifdef DEBUG 292822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n" 293822Speter , symbolp -> name ); 294822Speter # endif DEBUG 295844Speter symbolp -> desc = nlp -> n_desc; 29614129Speter symbolp -> fromp = pfilep; 297844Speter switch ( symbolp -> desc ) { 2987550Speter default: 2997550Speter error( FATAL , "panic: [checksymbol] NEW" ); 300844Speter case N_PGLABEL: 301844Speter case N_PGCONST: 302844Speter case N_PGTYPE: 303822Speter case N_PGVAR: 304844Speter case N_PGFUNC: 305844Speter case N_PGPROC: 3067601Speter case N_PLDATA: 3077601Speter case N_PLTEXT: 308831Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 309831Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 310831Speter symbolp -> sym_un.sym_str.fromi = ifilep; 311831Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 312831Speter return; 313844Speter case N_PEFUNC: 314844Speter case N_PEPROC: 315831Speter symbolp -> sym_un.sym_str.rfilep = NIL; 316831Speter symbolp -> sym_un.sym_str.rline = 0; 317831Speter /* 318831Speter * functions can only be declared external 319831Speter * in included files. 320831Speter */ 321831Speter if ( pfilep == ifilep ) { 322831Speter error( WARNING 323831Speter , "%s, line %d: %s %s must be declared in included file" 324831Speter , pfilep -> name , nlp -> n_value 325844Speter , classify( symbolp -> desc ) 326831Speter , symbolp -> name ); 327831Speter } 328822Speter symbolp -> sym_un.sym_str.fromi = ifilep; 329822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 330822Speter return; 331822Speter case N_PSO: 33214129Speter if ( nlp -> n_value < N_FLAGCHECKSUM ) { 33314129Speter error( WARNING, 33414129Speter "%s is out of date and should be recompiled", 33514129Speter ofilep -> name ); 33614129Speter } 337822Speter pfilep = symbolp; 33814129Speter ifilep = symbolp; 33914129Speter symbolp -> sym_un.checksum = N_FLAGCHECKSUM; 34014129Speter return; 341822Speter case N_PSOL: 342822Speter ifilep = symbolp; 34314129Speter symbolp -> sym_un.checksum = nlp -> n_value; 344822Speter return; 345822Speter } 346822Speter } else { 347822Speter # ifdef DEBUG 348822Speter fprintf( stderr , "[checksymbol] ->name %s is OLD\n" 349822Speter , symbolp -> name ); 350822Speter # endif DEBUG 3517601Speter errtype = ERROR; 352844Speter switch ( symbolp -> desc ) { 3537550Speter default: 3547550Speter error( FATAL , "panic [checksymbol] OLD" ); 35514129Speter return; 356822Speter case N_PSO: 357822Speter /* 358822Speter * finding a file again means you are back 359822Speter * in it after finishing an include file. 360822Speter */ 36114129Speter if ( symbolp -> desc != nlp -> n_desc ) { 36214129Speter error( FATAL , "panic [checksymbol] PSO" ); 36314129Speter return; 36414129Speter } 365822Speter pfilep = symbolp; 36614129Speter ifilep = symbolp; 36714129Speter return; 368822Speter case N_PSOL: 369822Speter /* 370822Speter * include files can be seen more than once, 37114129Speter * but their checksums are checked if they are 37214129Speter * greater than N_FLAGCHECKSUM. 37314129Speter * PSOL's are seen with checksums as the 37414129Speter * include file is entered, and with 37514129Speter * N_FLAGCHECKSUM as we are back in an 37614129Speter * included file from a nested include. 377822Speter */ 37814129Speter if ( symbolp -> desc != nlp -> n_desc ) { 37914129Speter error( FATAL , "panic [checksymbol] PSOL" ); 38014129Speter return; 38114129Speter } 38214129Speter if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM 38314129Speter && (unsigned) nlp -> n_value > N_FLAGCHECKSUM 38414129Speter && symbolp -> sym_un.checksum != nlp -> n_value ) { 38514129Speter error( ERROR, 38614129Speter "%s included in %s differs from %s included in %s", 38714129Speter symbolp -> name, pfilep -> name, 38814129Speter symbolp -> name, symbolp -> fromp -> name ); 38914129Speter } 390822Speter ifilep = symbolp; 391822Speter return; 392844Speter case N_PEFUNC: 393844Speter case N_PEPROC: 394822Speter /* 3957550Speter * this might be the resolution of the external 3967550Speter * has to match func/proc of external 3977550Speter * and has to have included external 3987550Speter * and has to not have been previously resolved. 399822Speter */ 4007550Speter if ( ( ( symbolp -> desc == N_PEFUNC 4017550Speter && nlp -> n_desc == N_PGFUNC ) 4027550Speter || ( symbolp -> desc == N_PEPROC 4037550Speter && nlp -> n_desc == N_PGPROC ) ) 40414129Speter && ( symbolp -> fromp == pfilep ) 4057550Speter && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { 4067550Speter /* 4077550Speter * resolve external 4087550Speter */ 4097550Speter # ifdef DEBUG 4107550Speter fprintf( stderr , "[checksymbol] resolving external\n" ); 4117550Speter # endif DEBUG 4127550Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 4137550Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 4147550Speter return; 415822Speter } 416822Speter /* 4177550Speter * otherwise, it might be another external, 4187550Speter * which is okay if it's 4197550Speter * the same type and from the same include file 420822Speter */ 4217550Speter if ( ( ( symbolp -> desc == N_PEFUNC 4227550Speter && nlp -> n_desc == N_PEFUNC ) 4237550Speter || ( symbolp -> desc == N_PEPROC 4247550Speter && nlp -> n_desc == N_PEPROC ) ) 4257550Speter && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { 4267550Speter /* 4277550Speter * just another pretty external 4287550Speter * make it look like it comes from here. 4297550Speter */ 4307550Speter # ifdef DEBUG 4317550Speter fprintf( stderr , "[checksymbol] just another pretty external\n" ); 4327550Speter # endif DEBUG 43314129Speter symbolp -> fromp = pfilep; 4347550Speter return; 435822Speter } 436822Speter /* 4377550Speter * something is wrong 4387598Speter * if it's not resolved, use the header file 4397598Speter * otherwise, it's just a regular error 440822Speter */ 4417598Speter if ( symbolp -> sym_un.sym_str.rfilep == NIL ) { 4427598Speter error( ERROR , 4437601Speter "%s, line %d: %s is already defined\n\t(%s, line %d)." , 4447598Speter ifilep -> name , nlp -> n_value , 4457598Speter nlp -> n_un.n_name , 4467598Speter symbolp -> sym_un.sym_str.fromi -> name , 4477598Speter symbolp -> sym_un.sym_str.iline ); 4487598Speter return; 4497598Speter } 4507598Speter break; 451844Speter case N_PGFUNC: 452844Speter case N_PGPROC: 453822Speter /* 454822Speter * functions may not be seen more than once. 455822Speter * the loader will complain about 456822Speter * `multiply defined', but we can, too. 457822Speter */ 458822Speter break; 459844Speter case N_PGLABEL: 460844Speter case N_PGCONST: 461844Speter case N_PGTYPE: 462822Speter case N_PGVAR: 463822Speter /* 464822Speter * labels, constants, types, variables 465822Speter * and external declarations 466822Speter * may be seen as many times as they want, 467822Speter * as long as they come from the same include file. 468822Speter * make it look like they come from this .p file. 469822Speter */ 470822Speter included: 471844Speter if ( nlp -> n_desc != symbolp -> desc 472822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) { 473822Speter break; 474822Speter } 47514129Speter symbolp -> fromp = pfilep; 476822Speter return; 4777601Speter case N_PLDATA: 4787601Speter case N_PLTEXT: 4797601Speter switch ( nlp -> n_desc ) { 4807601Speter default: 4817601Speter error( FATAL , "pc3: unknown stab 0x%x" 4827601Speter , nlp -> n_desc ); 4837601Speter return; 4847601Speter case N_PSO: 4857601Speter case N_PSOL: 4867601Speter case N_PGCONST: 4877601Speter case N_PGTYPE: 4887601Speter /* these won't conflict with library */ 4897601Speter return; 4907601Speter case N_PGLABEL: 4917601Speter case N_PGVAR: 4927601Speter case N_PGFUNC: 4937601Speter case N_PGPROC: 4947601Speter case N_PEFUNC: 4957601Speter case N_PEPROC: 4967601Speter case N_PLDATA: 4977601Speter case N_PLTEXT: 4987601Speter errtype = WARNING; 4997601Speter break; 5007601Speter } 5017601Speter break; 502822Speter } 503822Speter /* 504822Speter * this is the breaks 505822Speter */ 5067601Speter error( errtype 5077601Speter , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)." 5087601Speter , ifilep -> name 5097601Speter , nlp -> n_value 5107601Speter , classify( nlp -> n_desc ) 5117601Speter , nlp -> n_un.n_name 5127601Speter , ( symbolp -> desc == nlp -> n_desc ? "" : " as " ) 5137601Speter , ( symbolp -> desc == nlp -> n_desc 5147601Speter ? "" : article( symbolp -> desc ) ) 5157601Speter , symbolp -> sym_un.sym_str.rfilep -> name 5167601Speter , symbolp -> sym_un.sym_str.rline ); 517822Speter } 518822Speter } 519822Speter 520822Speter /* 521822Speter * quadratically hashed symbol table. 522822Speter * things are never deleted from the hash symbol table. 523822Speter * as more hash table is needed, 524822Speter * a new one is alloc'ed and chained to the end. 525822Speter * search is by rehashing within each table, 526822Speter * traversing chains to next table if unsuccessful. 527822Speter */ 528822Speter struct symbol * 529822Speter entersymbol( name ) 530822Speter char *name; 531822Speter { 5329572Speter static struct symboltableinfo symboltable; 533822Speter char *enteredname; 534822Speter long hashindex; 535822Speter register struct symboltableinfo *tablep; 536822Speter register struct symbol **herep; 537822Speter register struct symbol **limitp; 538822Speter register long increment; 539822Speter 540822Speter enteredname = enterstring( name ); 541822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; 5429572Speter for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) { 543822Speter if ( tablep == NIL ) { 5449572Speter # ifdef SPACEDEBUG 5459572Speter fprintf( stderr , 5469572Speter "[entersymbol] calloc'ing table for %d symbols\n" , 5479572Speter SYMBOLPRIME ); 5489572Speter # endif SPACEDEBUG 5499572Speter for ( tablep = &symboltable 5509572Speter ; tablep->chain != NIL 5519572Speter ; tablep = tablep->chain ) { 5529572Speter continue; 5539572Speter } 5549572Speter tablep->chain = ( struct symboltableinfo * ) 5559572Speter calloc( 1 , sizeof ( struct symboltableinfo ) ); 5569572Speter if ( tablep->chain == NIL ) { 557822Speter error( FATAL , "ran out of memory (entersymbol)" ); 558822Speter } 5599572Speter tablep = tablep->chain; 560822Speter } 561822Speter herep = &( tablep -> entry[ hashindex ] ); 562822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] ); 563822Speter increment = 1; 564822Speter do { 565822Speter if ( *herep == NIL ) { 566822Speter /* empty */ 5679572Speter if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) { 568822Speter /* too full, break for next table */ 569822Speter break; 570822Speter } 571822Speter tablep -> used++; 572822Speter *herep = symbolalloc(); 573822Speter ( *herep ) -> name = enteredname; 574822Speter ( *herep ) -> lookup = NEW; 5759572Speter # ifdef HASHDEBUG 5769572Speter fprintf( stderr , 5779572Speter "[entersymbol] name %s NEW after %d\n" , 5789572Speter enteredname , increment / 2 ); 5799572Speter # endif HASHDEBUG 580822Speter return *herep; 581822Speter } 582822Speter /* a find? */ 583822Speter if ( ( *herep ) -> name == enteredname ) { 584822Speter ( *herep ) -> lookup = OLD; 5859572Speter # ifdef HASHDEBUG 5869572Speter fprintf( stderr , "[entersymbol] name %s OLD at %d\n" , 5879572Speter enteredname , increment / 2 ); 5889572Speter # endif HASHDEBUG 589822Speter return *herep; 590822Speter } 591822Speter herep += increment; 592822Speter if ( herep >= limitp ) { 593822Speter herep -= SYMBOLPRIME; 594822Speter } 595822Speter increment += 2; 596822Speter } while ( increment < SYMBOLPRIME ); 5979572Speter # ifdef HASHDEBUG 5989572Speter fprintf( stderr , "[entersymbol] next symboltable\n" ); 5999572Speter # endif HASHDEBUG 600822Speter } 601822Speter } 602822Speter 603822Speter /* 604822Speter * allocate a symbol from the dynamically allocated symbol table. 605822Speter */ 606822Speter struct symbol * 607822Speter symbolalloc() 608822Speter { 609822Speter static struct symbol *nextsymbol = NIL; 610822Speter static long symbolsleft = 0; 611822Speter struct symbol *newsymbol; 612822Speter 613822Speter if ( symbolsleft <= 0 ) { 6149572Speter # ifdef SPACEDEBUG 6159572Speter fprintf( stderr , 6169572Speter "[symbolalloc] malloc space for %d symbols\n" , 6179572Speter SYMBOLALLOC / sizeof( struct symbol ) ); 6189572Speter # endif SPACEDEBUG 619822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); 620822Speter if ( nextsymbol == 0 ) { 621822Speter error( FATAL , "ran out of memory (symbolalloc)" ); 622822Speter } 623822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); 624822Speter } 625822Speter newsymbol = nextsymbol; 626822Speter nextsymbol++; 627822Speter symbolsleft--; 628822Speter return newsymbol; 629822Speter } 630822Speter 631822Speter /* 632822Speter * hash a string based on all of its characters. 633822Speter */ 634822Speter long 635822Speter hashstring( string ) 636822Speter char *string; 637822Speter { 638822Speter register char *cp; 639822Speter register long value; 640822Speter 641822Speter value = 0; 642822Speter for ( cp = string ; *cp ; cp++ ) { 643822Speter value = ( value * 2 ) + *cp; 644822Speter } 645822Speter return value; 646822Speter } 647822Speter 648822Speter /* 649822Speter * quadratically hashed string table. 650822Speter * things are never deleted from the hash string table. 651822Speter * as more hash table is needed, 652822Speter * a new one is alloc'ed and chained to the end. 653822Speter * search is by rehashing within each table, 654822Speter * traversing chains to next table if unsuccessful. 655822Speter */ 656822Speter char * 657822Speter enterstring( string ) 658822Speter char *string; 659822Speter { 6609572Speter static struct stringtableinfo stringtable; 661822Speter long hashindex; 662822Speter register struct stringtableinfo *tablep; 663822Speter register char **herep; 664822Speter register char **limitp; 665822Speter register long increment; 666822Speter 667822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; 6689572Speter for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) { 669822Speter if ( tablep == NIL ) { 6709572Speter # ifdef SPACEDEBUG 6719572Speter fprintf( stderr , 6729572Speter "[enterstring] calloc space for %d strings\n" , 6739572Speter STRINGPRIME ); 6749572Speter # endif SPACEDEBUG 6759572Speter for ( tablep = &stringtable 6769572Speter ; tablep->chain != NIL 6779572Speter ; tablep = tablep->chain ) { 6789572Speter continue; 6799572Speter } 6809572Speter tablep->chain = ( struct stringtableinfo * ) 6819572Speter calloc( 1 , sizeof ( struct stringtableinfo ) ); 6829572Speter if ( tablep->chain == NIL ) { 683822Speter error( FATAL , "ran out of memory (enterstring)" ); 684822Speter } 6859572Speter tablep = tablep->chain; 686822Speter } 687822Speter herep = &( tablep -> entry[ hashindex ] ); 688822Speter limitp = &( tablep -> entry[ STRINGPRIME ] ); 689822Speter increment = 1; 690822Speter do { 691822Speter if ( *herep == NIL ) { 692822Speter /* empty */ 6939572Speter if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) { 694822Speter /* too full, break for next table */ 695822Speter break; 696822Speter } 697822Speter tablep -> used++; 698822Speter *herep = charalloc( strlen( string ) ); 699822Speter strcpy( *herep , string ); 7009572Speter # ifdef HASHDEBUG 7019572Speter fprintf( stderr , 7029572Speter "[enterstring] string %s copied after %d\n" , 7039572Speter *herep , increment / 2 ); 7049572Speter # endif HASHDEBUG 705822Speter return *herep; 706822Speter } 707822Speter /* quick, check the first chars and then the rest */ 708822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) { 7099572Speter # ifdef HASHDEBUG 7109572Speter fprintf( stderr , 7119572Speter "[enterstring] string %s found after %d\n" , 7129572Speter *herep , increment / 2 ); 7139572Speter # endif HASHDEBUG 714822Speter return *herep; 715822Speter } 716822Speter herep += increment; 717822Speter if ( herep >= limitp ) { 718822Speter herep -= STRINGPRIME; 719822Speter } 720822Speter increment += 2; 721822Speter } while ( increment < STRINGPRIME ); 7229572Speter # ifdef HASHDEBUG 7239572Speter fprintf( stderr , "[enterstring] next stringtable\n" ); 7249572Speter # endif HASHDEBUG 725822Speter } 726822Speter } 727822Speter 728822Speter /* 729822Speter * copy a string to the dynamically allocated character table. 730822Speter */ 731822Speter char * 732822Speter charalloc( length ) 733822Speter register long length; 734822Speter { 735822Speter static char *nextchar = NIL; 736822Speter static long charsleft = 0; 737822Speter register long lengthplus1 = length + 1; 738822Speter register long askfor; 739822Speter char *newstring; 740822Speter 741822Speter if ( charsleft < lengthplus1 ) { 742822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; 7439572Speter # ifdef SPACEDEBUG 7449572Speter fprintf( stderr , "[charalloc] malloc space for %d chars\n" 745822Speter , askfor ); 7469572Speter # endif SPACEDEBUG 747822Speter nextchar = ( char * ) malloc( askfor ); 748822Speter if ( nextchar == 0 ) { 749822Speter error( FATAL , "no room for %d characters" , askfor ); 750822Speter } 751822Speter charsleft = askfor; 752822Speter } 753822Speter newstring = nextchar; 754822Speter nextchar += lengthplus1; 755822Speter charsleft -= lengthplus1; 756822Speter return newstring; 757822Speter } 758822Speter 759822Speter /* 760822Speter * read an archive header for the next element 761822Speter * and find the offset of the one after this. 762822Speter */ 763822Speter BOOL 764822Speter nextelement( ofilep ) 765822Speter struct fileinfo *ofilep; 766822Speter { 767822Speter register char *cp; 768822Speter register long red; 769822Speter register off_t arsize; 770822Speter struct ar_hdr archdr; 771822Speter 772822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 ); 773822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); 774822Speter if ( red != sizeof archdr ) { 775822Speter return FALSE; 776822Speter } 777822Speter /* null terminate the blank-padded name */ 778822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; 779822Speter *cp = '\0'; 780822Speter while ( *--cp == ' ' ) { 781822Speter *cp = '\0'; 782822Speter } 783822Speter /* set up the address of the beginning of next element */ 784822Speter arsize = atol( archdr.ar_size ); 785822Speter /* archive elements are aligned on 0 mod 2 boundaries */ 786822Speter if ( arsize & 1 ) { 787822Speter arsize += 1; 788822Speter } 789822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; 790822Speter /* say we had one */ 791822Speter return TRUE; 792822Speter } 793822Speter 794822Speter /* 795822Speter * variable number of arguments to error, like printf. 796822Speter */ 7977601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ) 7987598Speter int type; 799822Speter char *message; 800822Speter { 8017598Speter errors = type > errors ? type : errors; 8027598Speter if ( wflag && type == WARNING ) { 8037598Speter return; 8047598Speter } 805822Speter fprintf( stderr , "%s: " , program ); 8067598Speter switch ( type ) { 8077598Speter case WARNING: 8087598Speter fprintf( stderr , "Warning: " ); 8097598Speter break; 8107598Speter case ERROR: 8117598Speter fprintf( stderr , "Error: " ); 8127598Speter break; 8137598Speter case FATAL: 8147598Speter fprintf( stderr , "Fatal: " ); 8157598Speter break; 8167598Speter default: 8177598Speter fprintf( stderr , "Ooops: " ); 8187598Speter break; 8197598Speter } 8207601Speter fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 ); 821822Speter fprintf( stderr , "\n" ); 8227598Speter if ( type == FATAL ) { 8237598Speter exit( FATAL ); 824822Speter } 825822Speter } 826822Speter 827822Speter char * 828822Speter classify( type ) 829822Speter unsigned char type; 830822Speter { 831822Speter switch ( type ) { 832822Speter case N_PSO: 833822Speter return "source file"; 834822Speter case N_PSOL: 835822Speter return "include file"; 836844Speter case N_PGLABEL: 837822Speter return "label"; 838844Speter case N_PGCONST: 839822Speter return "constant"; 840844Speter case N_PGTYPE: 841822Speter return "type"; 842822Speter case N_PGVAR: 843822Speter return "variable"; 844844Speter case N_PGFUNC: 845822Speter return "function"; 846844Speter case N_PGPROC: 847822Speter return "procedure"; 848844Speter case N_PEFUNC: 849822Speter return "external function"; 850844Speter case N_PEPROC: 851822Speter return "external procedure"; 8527601Speter case N_PLDATA: 8537601Speter return "library variable"; 8547601Speter case N_PLTEXT: 8557601Speter return "library routine"; 856822Speter default: 857822Speter return "unknown symbol"; 858822Speter } 859822Speter } 8607601Speter 8617601Speter char * 8627601Speter article( type ) 8637601Speter unsigned char type; 8647601Speter { 8657601Speter switch ( type ) { 8667601Speter case N_PSO: 8677601Speter return "a source file"; 8687601Speter case N_PSOL: 8697601Speter return "an include file"; 8707601Speter case N_PGLABEL: 8717601Speter return "a label"; 8727601Speter case N_PGCONST: 8737601Speter return "a constant"; 8747601Speter case N_PGTYPE: 8757601Speter return "a type"; 8767601Speter case N_PGVAR: 8777601Speter return "a variable"; 8787601Speter case N_PGFUNC: 8797601Speter return "a function"; 8807601Speter case N_PGPROC: 8817601Speter return "a procedure"; 8827601Speter case N_PEFUNC: 8837601Speter return "an external function"; 8847601Speter case N_PEPROC: 8857601Speter return "an external procedure"; 8867601Speter case N_PLDATA: 8877601Speter return "a library variable"; 8887601Speter case N_PLTEXT: 8897601Speter return "a library routine"; 8907601Speter default: 8917601Speter return "an unknown symbol"; 8927601Speter } 8937601Speter } 894