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