xref: /original-bsd/usr.bin/pascal/pc3/pc3.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1980, 1982, 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1982, 1983, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)pc3.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
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:
26      *	(1)  All .o files must be up to date with respect to the
27      *	     runtime libraries.
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;
44      *	   - a subtype descriptor;
45      *	   - the file which logically contains the declaration of
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;
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 
79 char	program[] = "pc";
80 
81 #include <sys/types.h>
82 #include <sys/stat.h>
83 #include <ar.h>
84 #include <stdio.h>
85 #include <ctype.h>
86 #include <a.out.h>
87 #include <stab.h>
88 #include "pstab.h"
89 #include "pc3.h"
90 
91 int	errors = NONE;
92 BOOL	wflag = FALSE;
93 
94     /*
95      *	check each of the argument .o files (or archives of .o files).
96      */
97 main( argc , argv )
98     int		argc;
99     char	**argv;
100     {
101 	struct fileinfo	ofile;
102 
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++ ) {
114 #	    ifdef DEBUG
115 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
116 #	    endif DEBUG
117 	    ofile.name = *argv;
118 	    checkfile( &ofile );
119 	}
120 	exit( errors );
121     }
122 
123     /*
124      *	check the namelist of a file, or all namelists of an archive.
125      */
126 checkfile( 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 ) {
138 	    error( ERROR , "cannot open: %s" , ofilep -> name );
139 	    return;
140 	}
141 	fstat( fileno( ofilep -> file ) , &filestat );
142 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
143 	if ( red != sizeof mag_un ) {
144 	    error( ERROR , "cannot read header: %s" , ofilep -> name );
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 */
162 	    error( ERROR , "bad format: %s" , ofilep -> name );
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      */
180 checknl( ofilep )
181     register struct fileinfo	*ofilep;
182     {
183 
184 	long			red;
185 	struct exec		oexec;
186 	off_t			symoff;
187 	long			numsyms;
188 	register struct nlist	*nlp;
189 	register char		*stringp;
190 	long			strsize;
191 	long			sym;
192 
193 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
194 	if ( red != sizeof oexec ) {
195 	    error( ERROR , "error reading struct exec: %s"
196 		    , ofilep -> name );
197 	    return;
198 	}
199 	if ( N_BADMAG( oexec ) ) {
200 	    return;
201 	}
202 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
203 	fseek( ofilep -> file , symoff , 1 );
204 	numsyms = oexec.a_syms / sizeof ( struct nlist );
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      */
267 checksymbol( 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;
274 	int			errtype;
275 
276 #	ifdef DEBUG
277 	    if ( pfilep && ifilep ) {
278 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
279 			, pfilep -> name , ifilep -> name );
280 	    }
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 ) );
284 #	endif DEBUG
285 	if ( nlp -> n_type != N_PC ) {
286 		/* don't care about the others */
287 	    return;
288 	}
289 	symbolp = entersymbol( nlp -> n_un.n_name );
290 	if ( symbolp -> lookup == NEW ) {
291 #	    ifdef DEBUG
292 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
293 			, symbolp -> name );
294 #	    endif DEBUG
295 	    symbolp -> desc = nlp -> n_desc;
296 	    symbolp -> fromp = pfilep;
297 	    switch ( symbolp -> desc ) {
298 		default:
299 			error( FATAL , "panic: [checksymbol] NEW" );
300 		case N_PGLABEL:
301 		case N_PGCONST:
302 		case N_PGTYPE:
303 		case N_PGVAR:
304 		case N_PGFUNC:
305 		case N_PGPROC:
306 		case N_PLDATA:
307 		case N_PLTEXT:
308 			symbolp -> sym_un.sym_str.rfilep = ifilep;
309 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
310 			symbolp -> sym_un.sym_str.fromi = ifilep;
311 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
312 			return;
313 		case N_PEFUNC:
314 		case N_PEPROC:
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
325 				    , classify( symbolp -> desc )
326 				    , symbolp -> name );
327 			}
328 			symbolp -> sym_un.sym_str.fromi = ifilep;
329 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
330 			return;
331 		case N_PSO:
332 			if ( nlp -> n_value < N_FLAGCHECKSUM ) {
333 			    error( WARNING,
334 				"%s is out of date and should be recompiled",
335 				ofilep -> name );
336 			}
337 			pfilep = symbolp;
338 			ifilep = symbolp;
339 			symbolp -> sym_un.checksum = N_FLAGCHECKSUM;
340 			return;
341 		case N_PSOL:
342 			ifilep = symbolp;
343 			symbolp -> sym_un.checksum = nlp -> n_value;
344 			return;
345 	    }
346 	} else {
347 #	    ifdef DEBUG
348 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
349 			, symbolp -> name );
350 #	    endif DEBUG
351 	    errtype = ERROR;
352 	    switch ( symbolp -> desc ) {
353 		default:
354 			error( FATAL , "panic [checksymbol] OLD" );
355 			return;
356 		case N_PSO:
357 			    /*
358 			     *	finding a file again means you are back
359 			     *	in it after finishing an include file.
360 			     */
361 			if ( symbolp -> desc != nlp -> n_desc ) {
362 			    error( FATAL , "panic [checksymbol] PSO" );
363 			    return;
364 			}
365 			pfilep = symbolp;
366 			ifilep = symbolp;
367 			return;
368 		case N_PSOL:
369 			    /*
370 			     *	include files can be seen more than once,
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.
377 			     */
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 );
389 			}
390 			ifilep = symbolp;
391 			return;
392 		case N_PEFUNC:
393 		case N_PEPROC:
394 			    /*
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.
399 			     */
400 			if (  (  ( symbolp -> desc == N_PEFUNC
401 			         && nlp -> n_desc == N_PGFUNC )
402 			      || ( symbolp -> desc == N_PEPROC
403 				 && nlp -> n_desc == N_PGPROC ) )
404 			   && ( symbolp -> fromp == pfilep )
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;
415 			}
416 			    /*
417 			     *	otherwise, it might be another external,
418 			     *	which is okay if it's
419 			     *	the same type and from the same include file
420 			     */
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
433 			    symbolp -> fromp = pfilep;
434 			    return;
435 			}
436 			    /*
437 			     *	something is wrong
438 			     *	if it's not resolved, use the header file
439 			     *	otherwise, it's just a regular error
440 			     */
441 			if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
442 			    error( ERROR ,
443 		    "%s, line %d: %s is already defined\n\t(%s, line %d)." ,
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;
451 		case N_PGFUNC:
452 		case N_PGPROC:
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;
459 		case N_PGLABEL:
460 		case N_PGCONST:
461 		case N_PGTYPE:
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 			     */
470 included:
471 			if (  nlp -> n_desc != symbolp -> desc
472 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
473 			    break;
474 			}
475 			symbolp -> fromp = pfilep;
476 			return;
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;
502 	    }
503 		/*
504 		 *	this is the breaks
505 		 */
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 );
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      */
528 struct symbol *
529 entersymbol( name )
530     char	*name;
531     {
532 	static struct symboltableinfo	symboltable;
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;
542 	for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) {
543 	    if ( tablep == NIL ) {
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;
553 		}
554 		tablep->chain = ( struct symboltableinfo * )
555 			    calloc( 1 , sizeof ( struct symboltableinfo ) );
556 		if ( tablep->chain == NIL ) {
557 		    error( FATAL , "ran out of memory (entersymbol)" );
558 		}
559 		tablep = tablep->chain;
560 	    }
561 	    herep = &( tablep -> entry[ hashindex ] );
562 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
563 	    increment = 1;
564 	    do {
565 		if ( *herep == NIL ) {
566 			/* empty */
567 		    if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) {
568 			    /* too full, break for next table */
569 			break;
570 		    }
571 		    tablep -> used++;
572 		    *herep = symbolalloc();
573 		    ( *herep ) -> name = enteredname;
574 		    ( *herep ) -> lookup = NEW;
575 #		    ifdef HASHDEBUG
576 			fprintf( stderr ,
577 				"[entersymbol] name %s NEW after %d\n" ,
578 				enteredname , increment / 2 );
579 #		    endif HASHDEBUG
580 		    return *herep;
581 		}
582 		    /* a find? */
583 		if ( ( *herep ) -> name == enteredname ) {
584 		    ( *herep ) -> lookup = OLD;
585 #		    ifdef HASHDEBUG
586 			fprintf( stderr , "[entersymbol] name %s OLD at %d\n" ,
587 				enteredname , increment / 2 );
588 #		    endif HASHDEBUG
589 		    return *herep;
590 		}
591 		herep += increment;
592 		if ( herep >= limitp ) {
593 		    herep -= SYMBOLPRIME;
594 		}
595 		increment += 2;
596 	    } while ( increment < SYMBOLPRIME );
597 #	    ifdef HASHDEBUG
598 		fprintf( stderr , "[entersymbol] next symboltable\n" );
599 #	    endif HASHDEBUG
600 	}
601     }
602 
603     /*
604      *	allocate a symbol from the dynamically allocated symbol table.
605      */
606 struct symbol *
607 symbolalloc()
608     {
609 	static struct symbol	*nextsymbol = NIL;
610 	static long		symbolsleft = 0;
611 	struct symbol		*newsymbol;
612 
613 	if ( symbolsleft <= 0 ) {
614 #	    ifdef SPACEDEBUG
615 		fprintf( stderr ,
616 			"[symbolalloc] malloc space for %d symbols\n" ,
617 			SYMBOLALLOC / sizeof( struct symbol ) );
618 #	    endif SPACEDEBUG
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      */
634 long
635 hashstring( 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      */
656 char *
657 enterstring( string )
658     char	*string;
659     {
660 	static struct stringtableinfo	stringtable;
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;
668 	for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) {
669 	    if ( tablep == NIL ) {
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;
679 		}
680 		tablep->chain = ( struct stringtableinfo * )
681 			    calloc( 1 , sizeof ( struct stringtableinfo ) );
682 		if ( tablep->chain == NIL ) {
683 		    error( FATAL , "ran out of memory (enterstring)" );
684 		}
685 		tablep = tablep->chain;
686 	    }
687 	    herep = &( tablep -> entry[ hashindex ] );
688 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
689 	    increment = 1;
690 	    do {
691 		if ( *herep == NIL ) {
692 			/* empty */
693 		    if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) {
694 			    /* too full, break for next table */
695 			break;
696 		    }
697 		    tablep -> used++;
698 		    *herep = charalloc( strlen( string ) );
699 		    strcpy( *herep , string );
700 #		    ifdef HASHDEBUG
701 			fprintf( stderr ,
702 				"[enterstring] string %s copied after %d\n" ,
703 				*herep , increment / 2 );
704 #		    endif HASHDEBUG
705 		    return *herep;
706 		}
707 		    /* quick, check the first chars and then the rest */
708 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
709 #		    ifdef HASHDEBUG
710 			fprintf( stderr ,
711 				"[enterstring] string %s found after %d\n" ,
712 				*herep , increment / 2 );
713 #		    endif HASHDEBUG
714 		    return *herep;
715 		}
716 		herep += increment;
717 		if ( herep >= limitp ) {
718 		    herep -= STRINGPRIME;
719 		}
720 		increment += 2;
721 	    } while ( increment < STRINGPRIME );
722 #	    ifdef HASHDEBUG
723 		fprintf( stderr , "[enterstring] next stringtable\n" );
724 #	    endif HASHDEBUG
725 	}
726     }
727 
728     /*
729      *	copy a string to the dynamically allocated character table.
730      */
731 char *
732 charalloc( 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;
743 #	    ifdef SPACEDEBUG
744 		fprintf( stderr , "[charalloc] malloc space for %d chars\n"
745 			, askfor );
746 #	    endif SPACEDEBUG
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      */
763 BOOL
764 nextelement( 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      */
797 error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 )
798     int		type;
799     char	*message;
800     {
801 	errors = type > errors ? type : errors;
802 	if ( wflag && type == WARNING ) {
803 	    return;
804 	}
805 	fprintf( stderr , "%s: " , program );
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 	}
820 	fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 );
821 	fprintf( stderr , "\n" );
822 	if ( type == FATAL ) {
823 	    exit( FATAL );
824 	}
825     }
826 
827 char *
828 classify( 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";
836 	    case N_PGLABEL:
837 		return "label";
838 	    case N_PGCONST:
839 		return "constant";
840 	    case N_PGTYPE:
841 		return "type";
842 	    case N_PGVAR:
843 		return "variable";
844 	    case N_PGFUNC:
845 		return "function";
846 	    case N_PGPROC:
847 		return "procedure";
848 	    case N_PEFUNC:
849 		return "external function";
850 	    case N_PEPROC:
851 		return "external procedure";
852 	    case N_PLDATA:
853 		return "library variable";
854 	    case N_PLTEXT:
855 		return "library routine";
856 	    default:
857 		return "unknown symbol";
858 	}
859     }
860 
861 char *
862 article( 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     }
894