1822Speter /* Copyright (c) 1980 Regents of the University of California */ 2822Speter 3*7550Speter static char sccsid[] = "@(#)pc3.c 1.7 07/26/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 77822Speter int errors = 0; 78822Speter 79822Speter /* 80822Speter * check each of the argument .o files (or archives of .o files). 81822Speter */ 82822Speter main( argc , argv ) 83822Speter int argc; 84822Speter char **argv; 85822Speter { 86822Speter struct fileinfo ofile; 87822Speter 88831Speter while ( ++argv , --argc ) { 89822Speter # ifdef DEBUG 90822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv ); 91822Speter # endif DEBUG 92822Speter ofile.name = *argv; 93822Speter checkfile( &ofile ); 94822Speter } 95822Speter exit( errors ); 96822Speter } 97822Speter 98822Speter /* 99822Speter * check the namelist of a file, or all namelists of an archive. 100822Speter */ 101822Speter checkfile( ofilep ) 102822Speter struct fileinfo *ofilep; 103822Speter { 104822Speter union { 105822Speter char mag_armag[ SARMAG + 1 ]; 106822Speter struct exec mag_exec; 107822Speter } mag_un; 108822Speter int red; 109822Speter struct stat filestat; 110822Speter 111822Speter ofilep -> file = fopen( ofilep -> name , "r" ); 112822Speter if ( ofilep -> file == NULL ) { 113822Speter error( WARNING , "cannot open: %s" , ofilep -> name ); 114822Speter return; 115822Speter } 116822Speter fstat( fileno( ofilep -> file ) , &filestat ); 117822Speter ofilep -> modtime = filestat.st_mtime; 118822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); 119822Speter if ( red != sizeof mag_un ) { 120822Speter error( WARNING , "cannot read header: %s" , ofilep -> name ); 121822Speter return; 122822Speter } 123822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) { 124822Speter error( WARNING , "old archive: %s" , ofilep -> name ); 125822Speter return; 126822Speter } 127822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { 128822Speter /* archive, iterate through elements */ 129822Speter # ifdef DEBUG 130822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); 131822Speter # endif DEBUG 132822Speter ofilep -> nextoffset = SARMAG; 133822Speter while ( nextelement( ofilep ) ) { 134822Speter checknl( ofilep ); 135822Speter } 136822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) { 137822Speter /* not a file.o */ 138822Speter error( WARNING , "bad format: %s" , ofilep -> name ); 139822Speter return; 140822Speter } else { 141822Speter /* a file.o */ 142822Speter # ifdef DEBUG 143822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); 144822Speter # endif DEBUG 145822Speter fseek( ofilep -> file , 0L , 0 ); 146822Speter ofilep -> nextoffset = filestat.st_size; 147822Speter checknl( ofilep ); 148822Speter } 149822Speter fclose( ofilep -> file ); 150822Speter } 151822Speter 152822Speter /* 153822Speter * check the namelist of this file for conflicts with 154822Speter * previously entered symbols. 155822Speter */ 156822Speter checknl( ofilep ) 157822Speter register struct fileinfo *ofilep; 158822Speter { 159822Speter 160822Speter long red; 161831Speter struct exec oexec; 162822Speter off_t symoff; 163822Speter long numsyms; 164822Speter register struct nlist *nlp; 165822Speter register char *stringp; 166822Speter long strsize; 167822Speter long sym; 168822Speter 169831Speter red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); 170831Speter if ( red != sizeof oexec ) { 171822Speter error( WARNING , "error reading struct exec: %s" 172822Speter , ofilep -> name ); 173822Speter return; 174822Speter } 175831Speter if ( N_BADMAG( oexec ) ) { 176822Speter return; 177822Speter } 178831Speter symoff = N_SYMOFF( oexec ) - sizeof oexec; 179822Speter fseek( ofilep -> file , symoff , 1 ); 180831Speter numsyms = oexec.a_syms / sizeof ( struct nlist ); 181822Speter if ( numsyms == 0 ) { 182822Speter error( WARNING , "no name list: %s" , ofilep -> name ); 183822Speter return; 184822Speter } 185822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); 186822Speter if ( nlp == 0 ) { 187822Speter error( FATAL , "no room for %d nlists" , numsyms ); 188822Speter } 189822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) 190822Speter , ofilep -> file ); 191822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t ) 192822Speter >= ofilep -> nextoffset ) { 193822Speter error( WARNING , "no string table (old format .o?)" 194822Speter , ofilep -> name ); 195822Speter return; 196822Speter } 197822Speter red = fread( (char *) &strsize , sizeof strsize , 1 198822Speter , ofilep -> file ); 199822Speter if ( red != 1 ) { 200822Speter error( WARNING , "no string table (old format .o?)" 201822Speter , ofilep -> name ); 202822Speter return; 203822Speter } 204822Speter stringp = ( char * ) malloc( strsize ); 205822Speter if ( stringp == 0 ) { 206822Speter error( FATAL , "no room for %d bytes of strings" , strsize ); 207822Speter } 208822Speter red = fread( stringp + sizeof strsize 209822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); 210822Speter if ( red != 1 ) { 211822Speter error( WARNING , "error reading string table: %s" 212822Speter , ofilep -> name ); 213822Speter } 214822Speter # ifdef DEBUG 215822Speter fprintf( stderr , "[checknl] %s: %d symbols\n" 216822Speter , ofilep -> name , numsyms ); 217822Speter # endif DEBUG 218822Speter for ( sym = 0 ; sym < numsyms ; sym++) { 219822Speter if ( nlp[ sym ].n_un.n_strx ) { 220822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; 221822Speter } else { 222822Speter nlp[ sym ].n_un.n_name = ""; 223822Speter } 224822Speter checksymbol( &nlp[ sym ] , ofilep ); 225822Speter } 226822Speter if ( nlp ) { 227822Speter free( nlp ); 228822Speter } 229822Speter if ( stringp ) { 230822Speter free( stringp ); 231822Speter } 232822Speter } 233822Speter 234822Speter /* 235822Speter * check a symbol. 236822Speter * look it up in the hashed symbol table, 237822Speter * entering it if necessary. 238822Speter * this maintains a state of which .p and .i files 239822Speter * it is currently in the midst from the nlist entries 240822Speter * for source and included files. 241822Speter * if we are inside a .p but not a .i, pfilep == ifilep. 242822Speter */ 243822Speter checksymbol( nlp , ofilep ) 244822Speter struct nlist *nlp; 245822Speter struct fileinfo *ofilep; 246822Speter { 247822Speter static struct symbol *pfilep = NIL; 248822Speter static struct symbol *ifilep = NIL; 249822Speter register struct symbol *symbolp; 250822Speter 251822Speter # ifdef DEBUG 252822Speter if ( pfilep && ifilep ) { 253822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" 254822Speter , pfilep -> name , ifilep -> name ); 255822Speter } 256844Speter fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" 257844Speter , nlp -> n_un.n_name , nlp -> n_desc 258844Speter , classify( nlp -> n_desc ) ); 259822Speter # endif DEBUG 260844Speter if ( nlp -> n_type != N_PC ) { 261844Speter /* don't care about the others */ 262844Speter return; 263822Speter } 264844Speter symbolp = entersymbol( nlp -> n_un.n_name ); 265822Speter if ( symbolp -> lookup == NEW ) { 266822Speter # ifdef DEBUG 267822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n" 268822Speter , symbolp -> name ); 269822Speter # endif DEBUG 270844Speter symbolp -> desc = nlp -> n_desc; 271844Speter switch ( symbolp -> desc ) { 272*7550Speter default: 273*7550Speter error( FATAL , "panic: [checksymbol] NEW" ); 274844Speter case N_PGLABEL: 275844Speter case N_PGCONST: 276844Speter case N_PGTYPE: 277822Speter case N_PGVAR: 278844Speter case N_PGFUNC: 279844Speter case N_PGPROC: 280831Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 281831Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 282831Speter symbolp -> sym_un.sym_str.fromp = pfilep; 283831Speter symbolp -> sym_un.sym_str.fromi = ifilep; 284831Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 285831Speter return; 286844Speter case N_PEFUNC: 287844Speter case N_PEPROC: 288831Speter symbolp -> sym_un.sym_str.rfilep = NIL; 289831Speter symbolp -> sym_un.sym_str.rline = 0; 290831Speter /* 291831Speter * functions can only be declared external 292831Speter * in included files. 293831Speter */ 294831Speter if ( pfilep == ifilep ) { 295831Speter error( WARNING 296831Speter , "%s, line %d: %s %s must be declared in included file" 297831Speter , pfilep -> name , nlp -> n_value 298844Speter , classify( symbolp -> desc ) 299831Speter , symbolp -> name ); 300831Speter } 301822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 302822Speter symbolp -> sym_un.sym_str.fromi = ifilep; 303822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 304822Speter return; 305822Speter case N_PSO: 306822Speter pfilep = symbolp; 307822Speter /* and fall through */ 308822Speter case N_PSOL: 309822Speter ifilep = symbolp; 310822Speter symbolp -> sym_un.modtime = mtime( symbolp -> name ); 311822Speter if ( symbolp -> sym_un.modtime > ofilep -> modtime ) { 312822Speter error( WARNING , "%s is out of date with %s" 313822Speter , ofilep -> name , symbolp -> name ); 314822Speter } 315822Speter return; 316822Speter } 317822Speter } else { 318822Speter # ifdef DEBUG 319822Speter fprintf( stderr , "[checksymbol] ->name %s is OLD\n" 320822Speter , symbolp -> name ); 321822Speter # endif DEBUG 322844Speter switch ( symbolp -> desc ) { 323*7550Speter default: 324*7550Speter error( FATAL , "panic [checksymbol] OLD" ); 325822Speter case N_PSO: 326822Speter /* 327822Speter * finding a file again means you are back 328822Speter * in it after finishing an include file. 329822Speter */ 330822Speter pfilep = symbolp; 331822Speter /* and fall through */ 332822Speter case N_PSOL: 333822Speter /* 334822Speter * include files can be seen more than once, 335822Speter * but they still have to be timechecked. 336822Speter * (this will complain twice for out of date 337822Speter * include files which include other files. 338822Speter * sigh.) 339822Speter */ 340822Speter ifilep = symbolp; 341822Speter if ( symbolp -> sym_un.modtime > ofilep -> modtime ) { 342822Speter error( WARNING , "%s is out of date with %s" 343822Speter , ofilep -> name , symbolp -> name ); 344822Speter } 345822Speter return; 346844Speter case N_PEFUNC: 347844Speter case N_PEPROC: 348822Speter /* 349*7550Speter * this might be the resolution of the external 350*7550Speter * has to match func/proc of external 351*7550Speter * and has to have included external 352*7550Speter * and has to not have been previously resolved. 353822Speter */ 354*7550Speter if ( ( ( symbolp -> desc == N_PEFUNC 355*7550Speter && nlp -> n_desc == N_PGFUNC ) 356*7550Speter || ( symbolp -> desc == N_PEPROC 357*7550Speter && nlp -> n_desc == N_PGPROC ) ) 358*7550Speter && ( symbolp -> sym_un.sym_str.fromp == pfilep ) 359*7550Speter && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { 360*7550Speter /* 361*7550Speter * resolve external 362*7550Speter */ 363*7550Speter # ifdef DEBUG 364*7550Speter fprintf( stderr , "[checksymbol] resolving external\n" ); 365*7550Speter # endif DEBUG 366*7550Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 367*7550Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 368*7550Speter return; 369822Speter } 370822Speter /* 371*7550Speter * otherwise, it might be another external, 372*7550Speter * which is okay if it's 373*7550Speter * the same type and from the same include file 374822Speter */ 375*7550Speter if ( ( ( symbolp -> desc == N_PEFUNC 376*7550Speter && nlp -> n_desc == N_PEFUNC ) 377*7550Speter || ( symbolp -> desc == N_PEPROC 378*7550Speter && nlp -> n_desc == N_PEPROC ) ) 379*7550Speter && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { 380*7550Speter /* 381*7550Speter * just another pretty external 382*7550Speter * make it look like it comes from here. 383*7550Speter */ 384*7550Speter # ifdef DEBUG 385*7550Speter fprintf( stderr , "[checksymbol] just another pretty external\n" ); 386*7550Speter # endif DEBUG 387*7550Speter symbolp -> sym_un.sym_str.fromp = pfilep; 388*7550Speter return; 389822Speter } 390822Speter /* 391*7550Speter * something is wrong 392822Speter */ 393*7550Speter error( WARNING , 394*7550Speter "%s, line %d: %s already defined (%s, line %d)." , 395*7550Speter ifilep -> name , nlp -> n_value , 396*7550Speter nlp -> n_un.n_name , 397*7550Speter symbolp -> sym_un.sym_str.fromi -> name , 398*7550Speter symbolp -> sym_un.sym_str.iline ); 399822Speter return; 400844Speter case N_PGFUNC: 401844Speter case N_PGPROC: 402822Speter /* 403822Speter * functions may not be seen more than once. 404822Speter * the loader will complain about 405822Speter * `multiply defined', but we can, too. 406822Speter */ 407822Speter break; 408844Speter case N_PGLABEL: 409844Speter case N_PGCONST: 410844Speter case N_PGTYPE: 411822Speter case N_PGVAR: 412822Speter /* 413822Speter * labels, constants, types, variables 414822Speter * and external declarations 415822Speter * may be seen as many times as they want, 416822Speter * as long as they come from the same include file. 417822Speter * make it look like they come from this .p file. 418822Speter */ 419822Speter included: 420844Speter if ( nlp -> n_desc != symbolp -> desc 421822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) { 422822Speter break; 423822Speter } 424822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 425822Speter return; 426822Speter } 427822Speter /* 428822Speter * this is the breaks 429822Speter */ 430822Speter error( WARNING , "%s, line %d: %s already defined (%s, line %d)." 431822Speter , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name 432822Speter , symbolp -> sym_un.sym_str.rfilep -> name 433822Speter , symbolp -> sym_un.sym_str.rline ); 434822Speter } 435822Speter } 436822Speter 437822Speter /* 438822Speter * quadratically hashed symbol table. 439822Speter * things are never deleted from the hash symbol table. 440822Speter * as more hash table is needed, 441822Speter * a new one is alloc'ed and chained to the end. 442822Speter * search is by rehashing within each table, 443822Speter * traversing chains to next table if unsuccessful. 444822Speter */ 445822Speter struct symbol * 446822Speter entersymbol( name ) 447822Speter char *name; 448822Speter { 449822Speter static struct symboltableinfo *symboltable = NIL; 450822Speter char *enteredname; 451822Speter long hashindex; 452822Speter register struct symboltableinfo *tablep; 453822Speter register struct symbol **herep; 454822Speter register struct symbol **limitp; 455822Speter register long increment; 456822Speter 457822Speter enteredname = enterstring( name ); 458822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; 459822Speter for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) { 460822Speter if ( tablep == NIL ) { 461822Speter # ifdef DEBUG 462822Speter fprintf( stderr , "[entersymbol] calloc\n" ); 463822Speter # endif DEBUG 464822Speter tablep = ( struct symboltableinfo * ) 465822Speter calloc( sizeof ( struct symboltableinfo ) , 1 ); 466822Speter if ( tablep == NIL ) { 467822Speter error( FATAL , "ran out of memory (entersymbol)" ); 468822Speter } 469822Speter if ( symboltable == NIL ) { 470822Speter symboltable = tablep; 471822Speter } 472822Speter } 473822Speter herep = &( tablep -> entry[ hashindex ] ); 474822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] ); 475822Speter increment = 1; 476822Speter do { 477822Speter # ifdef DEBUG 478822Speter fprintf( stderr , "[entersymbol] increment %d\n" 479822Speter , increment ); 480822Speter # endif DEBUG 481822Speter if ( *herep == NIL ) { 482822Speter /* empty */ 483822Speter if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) { 484822Speter /* too full, break for next table */ 485822Speter break; 486822Speter } 487822Speter tablep -> used++; 488822Speter *herep = symbolalloc(); 489822Speter ( *herep ) -> name = enteredname; 490822Speter ( *herep ) -> lookup = NEW; 491822Speter # ifdef DEBUG 492822Speter fprintf( stderr , "[entersymbol] name %s NEW\n" 493822Speter , enteredname ); 494822Speter # endif DEBUG 495822Speter return *herep; 496822Speter } 497822Speter /* a find? */ 498822Speter if ( ( *herep ) -> name == enteredname ) { 499822Speter ( *herep ) -> lookup = OLD; 500822Speter # ifdef DEBUG 501822Speter fprintf( stderr , "[entersymbol] name %s OLD\n" 502822Speter , enteredname ); 503822Speter # endif DEBUG 504822Speter return *herep; 505822Speter } 506822Speter herep += increment; 507822Speter if ( herep >= limitp ) { 508822Speter herep -= SYMBOLPRIME; 509822Speter } 510822Speter increment += 2; 511822Speter } while ( increment < SYMBOLPRIME ); 512822Speter } 513822Speter } 514822Speter 515822Speter /* 516822Speter * allocate a symbol from the dynamically allocated symbol table. 517822Speter */ 518822Speter struct symbol * 519822Speter symbolalloc() 520822Speter { 521822Speter static struct symbol *nextsymbol = NIL; 522822Speter static long symbolsleft = 0; 523822Speter struct symbol *newsymbol; 524822Speter 525822Speter if ( symbolsleft <= 0 ) { 526822Speter # ifdef DEBUG 527822Speter fprintf( stderr , "[symbolalloc] malloc\n" ); 528822Speter # endif DEBUG 529822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); 530822Speter if ( nextsymbol == 0 ) { 531822Speter error( FATAL , "ran out of memory (symbolalloc)" ); 532822Speter } 533822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); 534822Speter } 535822Speter newsymbol = nextsymbol; 536822Speter nextsymbol++; 537822Speter symbolsleft--; 538822Speter return newsymbol; 539822Speter } 540822Speter 541822Speter /* 542822Speter * hash a string based on all of its characters. 543822Speter */ 544822Speter long 545822Speter hashstring( string ) 546822Speter char *string; 547822Speter { 548822Speter register char *cp; 549822Speter register long value; 550822Speter 551822Speter value = 0; 552822Speter for ( cp = string ; *cp ; cp++ ) { 553822Speter value = ( value * 2 ) + *cp; 554822Speter } 555822Speter return value; 556822Speter } 557822Speter 558822Speter /* 559822Speter * quadratically hashed string table. 560822Speter * things are never deleted from the hash string table. 561822Speter * as more hash table is needed, 562822Speter * a new one is alloc'ed and chained to the end. 563822Speter * search is by rehashing within each table, 564822Speter * traversing chains to next table if unsuccessful. 565822Speter */ 566822Speter char * 567822Speter enterstring( string ) 568822Speter char *string; 569822Speter { 570822Speter static struct stringtableinfo *stringtable = NIL; 571822Speter long hashindex; 572822Speter register struct stringtableinfo *tablep; 573822Speter register char **herep; 574822Speter register char **limitp; 575822Speter register long increment; 576822Speter 577822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; 578822Speter for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) { 579822Speter if ( tablep == NIL ) { 580822Speter # ifdef DEBUG 581822Speter fprintf( stderr , "[enterstring] calloc\n" ); 582822Speter # endif DEBUG 583822Speter tablep = ( struct stringtableinfo * ) 584822Speter calloc( sizeof ( struct stringtableinfo ) , 1 ); 585822Speter if ( tablep == NIL ) { 586822Speter error( FATAL , "ran out of memory (enterstring)" ); 587822Speter } 588822Speter if ( stringtable == NIL ) { 589822Speter stringtable = tablep; 590822Speter } 591822Speter } 592822Speter herep = &( tablep -> entry[ hashindex ] ); 593822Speter limitp = &( tablep -> entry[ STRINGPRIME ] ); 594822Speter increment = 1; 595822Speter do { 596822Speter # ifdef DEBUG 597822Speter fprintf( stderr , "[enterstring] increment %d\n" 598822Speter , increment ); 599822Speter # endif DEBUG 600822Speter if ( *herep == NIL ) { 601822Speter /* empty */ 602822Speter if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) { 603822Speter /* too full, break for next table */ 604822Speter break; 605822Speter } 606822Speter tablep -> used++; 607822Speter *herep = charalloc( strlen( string ) ); 608822Speter strcpy( *herep , string ); 609822Speter # ifdef DEBUG 610822Speter fprintf( stderr , "[enterstring] string %s copied\n" 611822Speter , *herep ); 612822Speter # endif DEBUG 613822Speter return *herep; 614822Speter } 615822Speter /* quick, check the first chars and then the rest */ 616822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) { 617822Speter # ifdef DEBUG 618822Speter fprintf( stderr , "[enterstring] string %s found\n" 619822Speter , *herep ); 620822Speter # endif DEBUG 621822Speter return *herep; 622822Speter } 623822Speter herep += increment; 624822Speter if ( herep >= limitp ) { 625822Speter herep -= STRINGPRIME; 626822Speter } 627822Speter increment += 2; 628822Speter } while ( increment < STRINGPRIME ); 629822Speter } 630822Speter } 631822Speter 632822Speter /* 633822Speter * copy a string to the dynamically allocated character table. 634822Speter */ 635822Speter char * 636822Speter charalloc( length ) 637822Speter register long length; 638822Speter { 639822Speter static char *nextchar = NIL; 640822Speter static long charsleft = 0; 641822Speter register long lengthplus1 = length + 1; 642822Speter register long askfor; 643822Speter char *newstring; 644822Speter 645822Speter if ( charsleft < lengthplus1 ) { 646822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; 647822Speter # ifdef DEBUG 648822Speter fprintf( stderr , "[charalloc] malloc( %d )\n" 649822Speter , askfor ); 650822Speter # endif DEBUG 651822Speter nextchar = ( char * ) malloc( askfor ); 652822Speter if ( nextchar == 0 ) { 653822Speter error( FATAL , "no room for %d characters" , askfor ); 654822Speter } 655822Speter charsleft = askfor; 656822Speter } 657822Speter newstring = nextchar; 658822Speter nextchar += lengthplus1; 659822Speter charsleft -= lengthplus1; 660822Speter return newstring; 661822Speter } 662822Speter 663822Speter /* 664822Speter * read an archive header for the next element 665822Speter * and find the offset of the one after this. 666822Speter */ 667822Speter BOOL 668822Speter nextelement( ofilep ) 669822Speter struct fileinfo *ofilep; 670822Speter { 671822Speter register char *cp; 672822Speter register long red; 673822Speter register off_t arsize; 674822Speter struct ar_hdr archdr; 675822Speter 676822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 ); 677822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); 678822Speter if ( red != sizeof archdr ) { 679822Speter return FALSE; 680822Speter } 681822Speter /* null terminate the blank-padded name */ 682822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; 683822Speter *cp = '\0'; 684822Speter while ( *--cp == ' ' ) { 685822Speter *cp = '\0'; 686822Speter } 687822Speter /* set up the address of the beginning of next element */ 688822Speter arsize = atol( archdr.ar_size ); 689822Speter /* archive elements are aligned on 0 mod 2 boundaries */ 690822Speter if ( arsize & 1 ) { 691822Speter arsize += 1; 692822Speter } 693822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; 694822Speter /* say we had one */ 695822Speter return TRUE; 696822Speter } 697822Speter 698822Speter /* 699822Speter * variable number of arguments to error, like printf. 700822Speter */ 701822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ) 702822Speter int fatal; 703822Speter char *message; 704822Speter { 705822Speter fprintf( stderr , "%s: " , program ); 706822Speter fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); 707822Speter fprintf( stderr , "\n" ); 708822Speter if ( fatal == FATAL ) { 709822Speter exit( 2 ); 710822Speter } 711822Speter errors = 1; 712822Speter } 713822Speter 714822Speter /* 715822Speter * find the last modify time of a file. 716822Speter * on error, return the current time. 717822Speter */ 718822Speter time_t 719822Speter mtime( filename ) 720822Speter char *filename; 721822Speter { 722822Speter struct stat filestat; 723822Speter 724822Speter # ifdef DEBUG 725822Speter fprintf( stderr , "[mtime] filename %s\n" 726822Speter , filename ); 727822Speter # endif DEBUG 728829Speter if ( stat( filename , &filestat ) != 0 ) { 729822Speter error( WARNING , "%s: cannot open" , filename ); 730822Speter return ( (time_t) time( 0 ) ); 731822Speter } 732822Speter return filestat.st_mtime; 733822Speter } 734822Speter 735822Speter char * 736822Speter classify( type ) 737822Speter unsigned char type; 738822Speter { 739822Speter switch ( type ) { 740822Speter case N_PSO: 741822Speter return "source file"; 742822Speter case N_PSOL: 743822Speter return "include file"; 744844Speter case N_PGLABEL: 745822Speter return "label"; 746844Speter case N_PGCONST: 747822Speter return "constant"; 748844Speter case N_PGTYPE: 749822Speter return "type"; 750822Speter case N_PGVAR: 751822Speter return "variable"; 752844Speter case N_PGFUNC: 753822Speter return "function"; 754844Speter case N_PGPROC: 755822Speter return "procedure"; 756844Speter case N_PEFUNC: 757822Speter return "external function"; 758844Speter case N_PEPROC: 759822Speter return "external procedure"; 760822Speter default: 761822Speter return "unknown symbol"; 762822Speter } 763822Speter } 764