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