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