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