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