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