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