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