1822Speter /* Copyright (c) 1980 Regents of the University of California */ 2822Speter 3*829Speter static char sccsid[] = "@(#)pc3.c 1.2 09/02/80"; 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; 31822Speter * - a type specifier; 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 64822Speter char program[] = "pc3"; 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> 74822Speter #include "/usr/src/new/pc0/p.a.out.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 88822Speter argc--; 89822Speter argv++; 90822Speter while ( argc-- ) { 91822Speter # ifdef DEBUG 92822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv ); 93822Speter # endif DEBUG 94822Speter ofile.name = *argv; 95822Speter checkfile( &ofile ); 96822Speter argv++; 97822Speter } 98822Speter exit( errors ); 99822Speter } 100822Speter 101822Speter /* 102822Speter * check the namelist of a file, or all namelists of an archive. 103822Speter */ 104822Speter checkfile( ofilep ) 105822Speter struct fileinfo *ofilep; 106822Speter { 107822Speter union { 108822Speter char mag_armag[ SARMAG + 1 ]; 109822Speter struct exec mag_exec; 110822Speter } mag_un; 111822Speter int red; 112822Speter struct stat filestat; 113822Speter 114822Speter ofilep -> file = fopen( ofilep -> name , "r" ); 115822Speter if ( ofilep -> file == NULL ) { 116822Speter error( WARNING , "cannot open: %s" , ofilep -> name ); 117822Speter return; 118822Speter } 119822Speter fstat( fileno( ofilep -> file ) , &filestat ); 120822Speter ofilep -> modtime = filestat.st_mtime; 121822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); 122822Speter if ( red != sizeof mag_un ) { 123822Speter error( WARNING , "cannot read header: %s" , ofilep -> name ); 124822Speter return; 125822Speter } 126822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) { 127822Speter error( WARNING , "old archive: %s" , ofilep -> name ); 128822Speter return; 129822Speter } 130822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { 131822Speter /* archive, iterate through elements */ 132822Speter # ifdef DEBUG 133822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); 134822Speter # endif DEBUG 135822Speter ofilep -> nextoffset = SARMAG; 136822Speter while ( nextelement( ofilep ) ) { 137822Speter checknl( ofilep ); 138822Speter } 139822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) { 140822Speter /* not a file.o */ 141822Speter error( WARNING , "bad format: %s" , ofilep -> name ); 142822Speter return; 143822Speter } else { 144822Speter /* a file.o */ 145822Speter # ifdef DEBUG 146822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); 147822Speter # endif DEBUG 148822Speter fseek( ofilep -> file , 0L , 0 ); 149822Speter ofilep -> nextoffset = filestat.st_size; 150822Speter checknl( ofilep ); 151822Speter } 152822Speter fclose( ofilep -> file ); 153822Speter } 154822Speter 155822Speter /* 156822Speter * check the namelist of this file for conflicts with 157822Speter * previously entered symbols. 158822Speter */ 159822Speter checknl( ofilep ) 160822Speter register struct fileinfo *ofilep; 161822Speter { 162822Speter 163822Speter long red; 164822Speter struct exec aexec; 165822Speter off_t symoff; 166822Speter long numsyms; 167822Speter register struct nlist *nlp; 168822Speter register char *stringp; 169822Speter long strsize; 170822Speter long sym; 171822Speter 172822Speter red = fread( (char *) &aexec , 1 , sizeof aexec , ofilep -> file ); 173822Speter if ( red != sizeof aexec ) { 174822Speter error( WARNING , "error reading struct exec: %s" 175822Speter , ofilep -> name ); 176822Speter return; 177822Speter } 178822Speter if ( N_BADMAG( aexec ) ) { 179822Speter return; 180822Speter } 181822Speter symoff = N_SYMOFF( aexec ) - sizeof aexec; 182822Speter fseek( ofilep -> file , symoff , 1 ); 183822Speter numsyms = aexec.a_syms / sizeof ( struct nlist ); 184822Speter if ( numsyms == 0 ) { 185822Speter error( WARNING , "no name list: %s" , ofilep -> name ); 186822Speter return; 187822Speter } 188822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); 189822Speter if ( nlp == 0 ) { 190822Speter error( FATAL , "no room for %d nlists" , numsyms ); 191822Speter } 192822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) 193822Speter , ofilep -> file ); 194822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t ) 195822Speter >= ofilep -> nextoffset ) { 196822Speter error( WARNING , "no string table (old format .o?)" 197822Speter , ofilep -> name ); 198822Speter return; 199822Speter } 200822Speter red = fread( (char *) &strsize , sizeof strsize , 1 201822Speter , ofilep -> file ); 202822Speter if ( red != 1 ) { 203822Speter error( WARNING , "no string table (old format .o?)" 204822Speter , ofilep -> name ); 205822Speter return; 206822Speter } 207822Speter stringp = ( char * ) malloc( strsize ); 208822Speter if ( stringp == 0 ) { 209822Speter error( FATAL , "no room for %d bytes of strings" , strsize ); 210822Speter } 211822Speter red = fread( stringp + sizeof strsize 212822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); 213822Speter if ( red != 1 ) { 214822Speter error( WARNING , "error reading string table: %s" 215822Speter , ofilep -> name ); 216822Speter } 217822Speter # ifdef DEBUG 218822Speter fprintf( stderr , "[checknl] %s: %d symbols\n" 219822Speter , ofilep -> name , numsyms ); 220822Speter # endif DEBUG 221822Speter for ( sym = 0 ; sym < numsyms ; sym++) { 222822Speter if ( nlp[ sym ].n_un.n_strx ) { 223822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; 224822Speter } else { 225822Speter nlp[ sym ].n_un.n_name = ""; 226822Speter } 227822Speter checksymbol( &nlp[ sym ] , ofilep ); 228822Speter } 229822Speter if ( nlp ) { 230822Speter free( nlp ); 231822Speter } 232822Speter if ( stringp ) { 233822Speter free( stringp ); 234822Speter } 235822Speter } 236822Speter 237822Speter /* 238822Speter * check a symbol. 239822Speter * look it up in the hashed symbol table, 240822Speter * entering it if necessary. 241822Speter * this maintains a state of which .p and .i files 242822Speter * it is currently in the midst from the nlist entries 243822Speter * for source and included files. 244822Speter * if we are inside a .p but not a .i, pfilep == ifilep. 245822Speter */ 246822Speter checksymbol( nlp , ofilep ) 247822Speter struct nlist *nlp; 248822Speter struct fileinfo *ofilep; 249822Speter { 250822Speter static struct symbol *pfilep = NIL; 251822Speter static struct symbol *ifilep = NIL; 252822Speter register struct symbol *symbolp; 253822Speter 254822Speter # ifdef DEBUG 255822Speter if ( pfilep && ifilep ) { 256822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" 257822Speter , pfilep -> name , ifilep -> name ); 258822Speter } 259822Speter fprintf( stderr , "[checksymbol] ->name %s ->n_type %x (%s)\n" 260822Speter , nlp -> n_un.n_name , nlp -> n_type 261822Speter , classify( nlp -> n_type ) ); 262822Speter # endif DEBUG 263822Speter switch ( nlp -> n_type ) { 264822Speter case N_PGLAB: 265822Speter case N_PGCON: 266822Speter case N_PGTYP: 267822Speter case N_PGVAR: 268822Speter case N_PGFUN: 269822Speter case N_PGPRC: 270822Speter case N_PEFUN: 271822Speter case N_PEPRC: 272822Speter case N_PSO: 273822Speter case N_PSOL: 274822Speter symbolp = entersymbol( nlp -> n_un.n_name ); 275822Speter break; 276822Speter default: 277822Speter /* don't care about the others */ 278822Speter return; 279822Speter } 280822Speter if ( symbolp -> lookup == NEW ) { 281822Speter # ifdef DEBUG 282822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n" 283822Speter , symbolp -> name ); 284822Speter # endif DEBUG 285822Speter symbolp -> type = nlp -> n_type; 286822Speter switch ( symbolp -> type ) { 287822Speter case N_PGLAB: 288822Speter case N_PGCON: 289822Speter case N_PGTYP: 290822Speter case N_PGVAR: 291822Speter case N_PGFUN: 292822Speter case N_PGPRC: 293822Speter /* and fall through */ 294822Speter case N_PEFUN: 295822Speter case N_PEPRC: 296822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 297822Speter symbolp -> sym_un.sym_str.fromi = ifilep; 298822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value; 299822Speter if ( symbolp -> type != N_PEFUN 300822Speter && symbolp -> type != N_PEPRC ) { 301822Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 302822Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 303822Speter } else { 304822Speter symbolp -> sym_un.sym_str.rfilep = NIL; 305822Speter symbolp -> sym_un.sym_str.rline = 0; 306822Speter /* 307822Speter * functions can only be declared external 308822Speter * in included files. 309822Speter */ 310822Speter if ( pfilep == ifilep ) { 311822Speter error( WARNING 312822Speter , "%s, line %d: %s %s must be declared in included file" 313822Speter , pfilep -> name , nlp -> n_value 314822Speter , classify( symbolp -> type ) 315822Speter , symbolp -> name ); 316822Speter } 317822Speter } 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 336822Speter switch ( symbolp -> type ) { 337822Speter case N_PSO: 338822Speter /* 339822Speter * finding a file again means you are back 340822Speter * in it after finishing an include file. 341822Speter */ 342822Speter pfilep = symbolp; 343822Speter /* and fall through */ 344822Speter case N_PSOL: 345822Speter /* 346822Speter * include files can be seen more than once, 347822Speter * but they still have to be timechecked. 348822Speter * (this will complain twice for out of date 349822Speter * include files which include other files. 350822Speter * sigh.) 351822Speter */ 352822Speter ifilep = symbolp; 353822Speter if ( symbolp -> sym_un.modtime > ofilep -> modtime ) { 354822Speter error( WARNING , "%s is out of date with %s" 355822Speter , ofilep -> name , symbolp -> name ); 356822Speter } 357822Speter return; 358822Speter case N_PEFUN: 359822Speter case N_PEPRC: 360822Speter /* 361822Speter * we may see any number of external declarations, 362822Speter * but they all have to come 363822Speter * from the same include file. 364822Speter */ 365822Speter if ( nlp -> n_type == N_PEFUN 366822Speter || nlp -> n_type == N_PEPRC ) { 367822Speter goto included; 368822Speter } 369822Speter /* 370822Speter * an external function can be resolved by 371822Speter * the resolution of the function 372822Speter * if the resolving file 373822Speter * included the external declaration. 374822Speter */ 375822Speter if ( ( symbolp -> type == N_PEFUN 376822Speter && nlp -> n_type != N_PGFUN ) 377822Speter || ( symbolp -> type == N_PEPRC 378822Speter && nlp -> n_type != N_PGPRC ) 379822Speter || symbolp -> sym_un.sym_str.fromp != pfilep ) { 380822Speter break; 381822Speter } 382822Speter /* 383822Speter * an external function can only be resolved once. 384822Speter */ 385822Speter if ( symbolp -> sym_un.sym_str.rfilep != NIL ) { 386822Speter break; 387822Speter } 388822Speter symbolp -> sym_un.sym_str.rfilep = ifilep; 389822Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value; 390822Speter return; 391822Speter case N_PGFUN: 392822Speter case N_PGPRC: 393822Speter /* 394822Speter * functions may not be seen more than once. 395822Speter * the loader will complain about 396822Speter * `multiply defined', but we can, too. 397822Speter */ 398822Speter break; 399822Speter case N_PGLAB: 400822Speter case N_PGCON: 401822Speter case N_PGTYP: 402822Speter case N_PGVAR: 403822Speter /* 404822Speter * labels, constants, types, variables 405822Speter * and external declarations 406822Speter * may be seen as many times as they want, 407822Speter * as long as they come from the same include file. 408822Speter * make it look like they come from this .p file. 409822Speter */ 410822Speter included: 411822Speter if ( nlp -> n_type != symbolp -> type 412822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) { 413822Speter break; 414822Speter } 415822Speter symbolp -> sym_un.sym_str.fromp = pfilep; 416822Speter return; 417822Speter } 418822Speter /* 419822Speter * this is the breaks 420822Speter */ 421822Speter error( WARNING , "%s, line %d: %s already defined (%s, line %d)." 422822Speter , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name 423822Speter , symbolp -> sym_un.sym_str.rfilep -> name 424822Speter , symbolp -> sym_un.sym_str.rline ); 425822Speter } 426822Speter } 427822Speter 428822Speter /* 429822Speter * quadratically hashed symbol table. 430822Speter * things are never deleted from the hash symbol table. 431822Speter * as more hash table is needed, 432822Speter * a new one is alloc'ed and chained to the end. 433822Speter * search is by rehashing within each table, 434822Speter * traversing chains to next table if unsuccessful. 435822Speter */ 436822Speter 437822Speter struct symbol * 438822Speter entersymbol( name ) 439822Speter char *name; 440822Speter { 441822Speter static struct symboltableinfo *symboltable = NIL; 442822Speter char *enteredname; 443822Speter long hashindex; 444822Speter register struct symboltableinfo *tablep; 445822Speter register struct symbol **herep; 446822Speter register struct symbol **limitp; 447822Speter register long increment; 448822Speter 449822Speter enteredname = enterstring( name ); 450822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; 451822Speter for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) { 452822Speter if ( tablep == NIL ) { 453822Speter # ifdef DEBUG 454822Speter fprintf( stderr , "[entersymbol] calloc\n" ); 455822Speter # endif DEBUG 456822Speter tablep = ( struct symboltableinfo * ) 457822Speter calloc( sizeof ( struct symboltableinfo ) , 1 ); 458822Speter if ( tablep == NIL ) { 459822Speter error( FATAL , "ran out of memory (entersymbol)" ); 460822Speter } 461822Speter if ( symboltable == NIL ) { 462822Speter symboltable = tablep; 463822Speter } 464822Speter } 465822Speter herep = &( tablep -> entry[ hashindex ] ); 466822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] ); 467822Speter increment = 1; 468822Speter do { 469822Speter # ifdef DEBUG 470822Speter fprintf( stderr , "[entersymbol] increment %d\n" 471822Speter , increment ); 472822Speter # endif DEBUG 473822Speter if ( *herep == NIL ) { 474822Speter /* empty */ 475822Speter if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) { 476822Speter /* too full, break for next table */ 477822Speter break; 478822Speter } 479822Speter tablep -> used++; 480822Speter *herep = symbolalloc(); 481822Speter ( *herep ) -> name = enteredname; 482822Speter ( *herep ) -> lookup = NEW; 483822Speter # ifdef DEBUG 484822Speter fprintf( stderr , "[entersymbol] name %s NEW\n" 485822Speter , enteredname ); 486822Speter # endif DEBUG 487822Speter return *herep; 488822Speter } 489822Speter /* a find? */ 490822Speter if ( ( *herep ) -> name == enteredname ) { 491822Speter ( *herep ) -> lookup = OLD; 492822Speter # ifdef DEBUG 493822Speter fprintf( stderr , "[entersymbol] name %s OLD\n" 494822Speter , enteredname ); 495822Speter # endif DEBUG 496822Speter return *herep; 497822Speter } 498822Speter herep += increment; 499822Speter if ( herep >= limitp ) { 500822Speter herep -= SYMBOLPRIME; 501822Speter } 502822Speter increment += 2; 503822Speter } while ( increment < SYMBOLPRIME ); 504822Speter } 505822Speter } 506822Speter 507822Speter /* 508822Speter * allocate a symbol from the dynamically allocated symbol table. 509822Speter */ 510822Speter 511822Speter struct symbol * 512822Speter symbolalloc() 513822Speter { 514822Speter static struct symbol *nextsymbol = NIL; 515822Speter static long symbolsleft = 0; 516822Speter struct symbol *newsymbol; 517822Speter 518822Speter if ( symbolsleft <= 0 ) { 519822Speter # ifdef DEBUG 520822Speter fprintf( stderr , "[symbolalloc] malloc\n" ); 521822Speter # endif DEBUG 522822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); 523822Speter if ( nextsymbol == 0 ) { 524822Speter error( FATAL , "ran out of memory (symbolalloc)" ); 525822Speter } 526822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); 527822Speter } 528822Speter newsymbol = nextsymbol; 529822Speter nextsymbol++; 530822Speter symbolsleft--; 531822Speter return newsymbol; 532822Speter } 533822Speter 534822Speter /* 535822Speter * hash a string based on all of its characters. 536822Speter */ 537822Speter long 538822Speter hashstring( string ) 539822Speter char *string; 540822Speter { 541822Speter register char *cp; 542822Speter register long value; 543822Speter 544822Speter value = 0; 545822Speter for ( cp = string ; *cp ; cp++ ) { 546822Speter value = ( value * 2 ) + *cp; 547822Speter } 548822Speter return value; 549822Speter } 550822Speter 551822Speter /* 552822Speter * quadratically hashed string table. 553822Speter * things are never deleted from the hash string table. 554822Speter * as more hash table is needed, 555822Speter * a new one is alloc'ed and chained to the end. 556822Speter * search is by rehashing within each table, 557822Speter * traversing chains to next table if unsuccessful. 558822Speter */ 559822Speter 560822Speter char * 561822Speter enterstring( string ) 562822Speter char *string; 563822Speter { 564822Speter static struct stringtableinfo *stringtable = NIL; 565822Speter long hashindex; 566822Speter register struct stringtableinfo *tablep; 567822Speter register char **herep; 568822Speter register char **limitp; 569822Speter register long increment; 570822Speter 571822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; 572822Speter for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) { 573822Speter if ( tablep == NIL ) { 574822Speter # ifdef DEBUG 575822Speter fprintf( stderr , "[enterstring] calloc\n" ); 576822Speter # endif DEBUG 577822Speter tablep = ( struct stringtableinfo * ) 578822Speter calloc( sizeof ( struct stringtableinfo ) , 1 ); 579822Speter if ( tablep == NIL ) { 580822Speter error( FATAL , "ran out of memory (enterstring)" ); 581822Speter } 582822Speter if ( stringtable == NIL ) { 583822Speter stringtable = tablep; 584822Speter } 585822Speter } 586822Speter herep = &( tablep -> entry[ hashindex ] ); 587822Speter limitp = &( tablep -> entry[ STRINGPRIME ] ); 588822Speter increment = 1; 589822Speter do { 590822Speter # ifdef DEBUG 591822Speter fprintf( stderr , "[enterstring] increment %d\n" 592822Speter , increment ); 593822Speter # endif DEBUG 594822Speter if ( *herep == NIL ) { 595822Speter /* empty */ 596822Speter if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) { 597822Speter /* too full, break for next table */ 598822Speter break; 599822Speter } 600822Speter tablep -> used++; 601822Speter *herep = charalloc( strlen( string ) ); 602822Speter strcpy( *herep , string ); 603822Speter # ifdef DEBUG 604822Speter fprintf( stderr , "[enterstring] string %s copied\n" 605822Speter , *herep ); 606822Speter # endif DEBUG 607822Speter return *herep; 608822Speter } 609822Speter /* quick, check the first chars and then the rest */ 610822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) { 611822Speter # ifdef DEBUG 612822Speter fprintf( stderr , "[enterstring] string %s found\n" 613822Speter , *herep ); 614822Speter # endif DEBUG 615822Speter return *herep; 616822Speter } 617822Speter herep += increment; 618822Speter if ( herep >= limitp ) { 619822Speter herep -= STRINGPRIME; 620822Speter } 621822Speter increment += 2; 622822Speter } while ( increment < STRINGPRIME ); 623822Speter } 624822Speter } 625822Speter 626822Speter /* 627822Speter * copy a string to the dynamically allocated character table. 628822Speter */ 629822Speter 630822Speter char * 631822Speter charalloc( length ) 632822Speter register long length; 633822Speter { 634822Speter static char *nextchar = NIL; 635822Speter static long charsleft = 0; 636822Speter register long lengthplus1 = length + 1; 637822Speter register long askfor; 638822Speter char *newstring; 639822Speter 640822Speter if ( charsleft < lengthplus1 ) { 641822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; 642822Speter # ifdef DEBUG 643822Speter fprintf( stderr , "[charalloc] malloc( %d )\n" 644822Speter , askfor ); 645822Speter # endif DEBUG 646822Speter nextchar = ( char * ) malloc( askfor ); 647822Speter if ( nextchar == 0 ) { 648822Speter error( FATAL , "no room for %d characters" , askfor ); 649822Speter } 650822Speter charsleft = askfor; 651822Speter } 652822Speter newstring = nextchar; 653822Speter nextchar += lengthplus1; 654822Speter charsleft -= lengthplus1; 655822Speter return newstring; 656822Speter } 657822Speter 658822Speter /* 659822Speter * read an archive header for the next element 660822Speter * and find the offset of the one after this. 661822Speter */ 662822Speter BOOL 663822Speter nextelement( ofilep ) 664822Speter struct fileinfo *ofilep; 665822Speter { 666822Speter register char *cp; 667822Speter register long red; 668822Speter register off_t arsize; 669822Speter struct ar_hdr archdr; 670822Speter 671822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 ); 672822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); 673822Speter if ( red != sizeof archdr ) { 674822Speter return FALSE; 675822Speter } 676822Speter /* null terminate the blank-padded name */ 677822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; 678822Speter *cp = '\0'; 679822Speter while ( *--cp == ' ' ) { 680822Speter *cp = '\0'; 681822Speter } 682822Speter /* set up the address of the beginning of next element */ 683822Speter arsize = atol( archdr.ar_size ); 684822Speter /* archive elements are aligned on 0 mod 2 boundaries */ 685822Speter if ( arsize & 1 ) { 686822Speter arsize += 1; 687822Speter } 688822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; 689822Speter /* say we had one */ 690822Speter return TRUE; 691822Speter } 692822Speter 693822Speter /* 694822Speter * variable number of arguments to error, like printf. 695822Speter */ 696822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ) 697822Speter int fatal; 698822Speter char *message; 699822Speter { 700822Speter fprintf( stderr , "%s: " , program ); 701822Speter fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); 702822Speter fprintf( stderr , "\n" ); 703822Speter if ( fatal == FATAL ) { 704822Speter exit( 2 ); 705822Speter } 706822Speter errors = 1; 707822Speter } 708822Speter 709822Speter /* 710822Speter * find the last modify time of a file. 711822Speter * on error, return the current time. 712822Speter */ 713822Speter time_t 714822Speter mtime( filename ) 715822Speter char *filename; 716822Speter { 717822Speter struct stat filestat; 718822Speter 719822Speter # ifdef DEBUG 720822Speter fprintf( stderr , "[mtime] filename %s\n" 721822Speter , filename ); 722822Speter # endif DEBUG 723*829Speter if ( stat( filename , &filestat ) != 0 ) { 724822Speter error( WARNING , "%s: cannot open" , filename ); 725822Speter return ( (time_t) time( 0 ) ); 726822Speter } 727822Speter return filestat.st_mtime; 728822Speter } 729822Speter 730822Speter char * 731822Speter classify( type ) 732822Speter unsigned char type; 733822Speter { 734822Speter switch ( type ) { 735822Speter case N_PSO: 736822Speter return "source file"; 737822Speter case N_PSOL: 738822Speter return "include file"; 739822Speter case N_PGLAB: 740822Speter return "label"; 741822Speter case N_PGCON: 742822Speter return "constant"; 743822Speter case N_PGTYP: 744822Speter return "type"; 745822Speter case N_PGVAR: 746822Speter return "variable"; 747822Speter case N_PGFUN: 748822Speter return "function"; 749822Speter case N_PGPRC: 750822Speter return "procedure"; 751822Speter case N_PEFUN: 752822Speter return "external function"; 753822Speter case N_PEPRC: 754822Speter return "external procedure"; 755822Speter default: 756822Speter return "unknown symbol"; 757822Speter } 758822Speter } 759