xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 831)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*831Speter static	char sccsid[] = "@(#)pc3.c 1.3 09/02/80";
4822Speter 
5822Speter     /*
6822Speter      *	     Pc3 is a pass in the Berkeley Pascal compilation
7822Speter      *	process that is performed just prior to linking Pascal
8822Speter      *	object files.  Its purpose is to enforce the rules of
9822Speter      *	separate compilation for Berkeley Pascal.  Pc3 is called
10822Speter      *	with the same argument list of object files that is sent to
11822Speter      *	the loader.  These checks are performed by pc3 by examining
12822Speter      *	the symbol tables of the object files:
13822Speter      *	(1)  All source and included files must be "up-to-date" with
14822Speter      *	     the object files of which they are components.
15822Speter      *	(2)  Each global Pascal symbol (label, constant, type,
16822Speter      *	     variable, procedure, or function name) must be uniquely
17822Speter      *	     declared, i.e. declared in only one included file or
18822Speter      *	     source file.
19822Speter      *	(3)  Each external function (or procedure) may be resolved
20822Speter      *	     at most once in a source file which included the
21822Speter      *	     external declaration of the function.
22822Speter      *
23822Speter      *	     The symbol table of each object file is scanned and
24822Speter      *	each global Pascal symbol is placed in a hashed symbol
25822Speter      *	table.  The Pascal compiler has been modified to emit all
26822Speter      *	Pascal global symbols to the object file symbol table.  The
27822Speter      *	information stored in the symbol table for each such symbol
28822Speter      *	is:
29822Speter      *
30822Speter      *	   - the name of the symbol;
31822Speter      *	   - a type specifier;
32822Speter      *	   - for file symbols, their last modify time;
33822Speter      *	   - the file which logically contains the declaration of
34822Speter      *	     the symbol (not an include file);
35822Speter      *	   - the file which textually contains the declaration of
36822Speter      *	     the symbol (possibly an include file);
37822Speter      *	   - the line number at which the symbol is declared;
38822Speter      *	   - the file which contains the resolution of the symbol.
39822Speter      *	   - the line number at which the symbol is resolved;
40822Speter      *
41822Speter      *	     If a symbol has been previously entered into the symbol
42822Speter      *	table, a check is made that the current declaration is of
43822Speter      *	the same type and from the same include file as the previous
44822Speter      *	one.  Except for files and functions and procedures, it is
45822Speter      *	an error for a symbol declaration to be encountered more
46822Speter      *	than once, unless the re-declarations come from the same
47822Speter      *	included file as the original.
48822Speter      *
49822Speter      *	     As an include file symbol is encountered in a source
50822Speter      *	file, the symbol table entry of each symbol declared in that
51822Speter      *	include file is modified to reflect its new logical
52822Speter      *	inclusion in the source file.  File symbols are also
53822Speter      *	encountered as an included file ends, signaling the
54822Speter      *	continuation of the enclosing file.
55822Speter      *
56822Speter      *	     Functions and procedures which have been declared
57822Speter      *	external may be resolved by declarations from source files
58822Speter      *	which included the external declaration of the function.
59822Speter      *	Functions and procedures may be resolved at most once across
60822Speter      *	a set of object files.  The loader will complain if a
61822Speter      *	function is not resolved at least once.
62822Speter      */
63822Speter 
64822Speter char	program[] = "pc3";
65822Speter 
66822Speter #include <sys/types.h>
67822Speter #include <ar.h>
68822Speter #include <stdio.h>
69822Speter #include <ctype.h>
70822Speter #include <a.out.h>
71822Speter #include <stab.h>
72822Speter #include <pagsiz.h>
73822Speter #include <stat.h>
74822Speter #include "/usr/src/new/pc0/p.a.out.h"
75822Speter #include "pc3.h"
76822Speter 
77822Speter int	errors = 0;
78822Speter 
79822Speter     /*
80822Speter      *	check each of the argument .o files (or archives of .o files).
81822Speter      */
82822Speter main( argc , argv )
83822Speter     int		argc;
84822Speter     char	**argv;
85822Speter     {
86822Speter 	struct fileinfo	ofile;
87822Speter 
88*831Speter 	while ( ++argv , --argc ) {
89822Speter #	    ifdef DEBUG
90822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
91822Speter #	    endif DEBUG
92822Speter 	    ofile.name = *argv;
93822Speter 	    checkfile( &ofile );
94822Speter 	}
95822Speter 	exit( errors );
96822Speter     }
97822Speter 
98822Speter     /*
99822Speter      *	check the namelist of a file, or all namelists of an archive.
100822Speter      */
101822Speter checkfile( ofilep )
102822Speter     struct fileinfo	*ofilep;
103822Speter     {
104822Speter 	union {
105822Speter 	    char	mag_armag[ SARMAG + 1 ];
106822Speter 	    struct exec	mag_exec;
107822Speter 	}		mag_un;
108822Speter 	int		red;
109822Speter 	struct stat	filestat;
110822Speter 
111822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
112822Speter 	if ( ofilep -> file == NULL ) {
113822Speter 	    error( WARNING , "cannot open: %s" , ofilep -> name );
114822Speter 	    return;
115822Speter 	}
116822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
117822Speter 	ofilep -> modtime = filestat.st_mtime;
118822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
119822Speter 	if ( red != sizeof mag_un ) {
120822Speter 	    error( WARNING , "cannot read header: %s" , ofilep -> name );
121822Speter 	    return;
122822Speter 	}
123822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
124822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
125822Speter 	    return;
126822Speter 	}
127822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
128822Speter 		/* archive, iterate through elements */
129822Speter #	    ifdef DEBUG
130822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
131822Speter #	    endif DEBUG
132822Speter 	    ofilep -> nextoffset = SARMAG;
133822Speter 	    while ( nextelement( ofilep ) ) {
134822Speter 		checknl( ofilep );
135822Speter 	    }
136822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
137822Speter 		/* not a file.o */
138822Speter 	    error( WARNING , "bad format: %s" , ofilep -> name );
139822Speter 	    return;
140822Speter 	} else {
141822Speter 		/* a file.o */
142822Speter #	    ifdef DEBUG
143822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
144822Speter #	    endif DEBUG
145822Speter 	    fseek( ofilep -> file , 0L , 0 );
146822Speter 	    ofilep -> nextoffset = filestat.st_size;
147822Speter 	    checknl( ofilep );
148822Speter 	}
149822Speter 	fclose( ofilep -> file );
150822Speter     }
151822Speter 
152822Speter     /*
153822Speter      *	check the namelist of this file for conflicts with
154822Speter      *	previously entered symbols.
155822Speter      */
156822Speter checknl( ofilep )
157822Speter     register struct fileinfo	*ofilep;
158822Speter     {
159822Speter 
160822Speter 	long			red;
161*831Speter 	struct exec		oexec;
162822Speter 	off_t			symoff;
163822Speter 	long			numsyms;
164822Speter 	register struct nlist	*nlp;
165822Speter 	register char		*stringp;
166822Speter 	long			strsize;
167822Speter 	long			sym;
168822Speter 
169*831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
170*831Speter 	if ( red != sizeof oexec ) {
171822Speter 	    error( WARNING , "error reading struct exec: %s"
172822Speter 		    , ofilep -> name );
173822Speter 	    return;
174822Speter 	}
175*831Speter 	if ( N_BADMAG( oexec ) ) {
176822Speter 	    return;
177822Speter 	}
178*831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
179822Speter 	fseek( ofilep -> file , symoff , 1 );
180*831Speter 	numsyms = oexec.a_syms / sizeof ( struct nlist );
181822Speter 	if ( numsyms == 0 ) {
182822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
183822Speter 	    return;
184822Speter 	}
185822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
186822Speter 	if ( nlp == 0 ) {
187822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
188822Speter 	}
189822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
190822Speter 		    , ofilep -> file );
191822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
192822Speter 	    >= ofilep -> nextoffset ) {
193822Speter 	    error( WARNING , "no string table (old format .o?)"
194822Speter 		    , ofilep -> name );
195822Speter 	    return;
196822Speter 	}
197822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
198822Speter 		    , ofilep -> file );
199822Speter 	if ( red != 1 ) {
200822Speter 	    error( WARNING , "no string table (old format .o?)"
201822Speter 		    , ofilep -> name );
202822Speter 	    return;
203822Speter 	}
204822Speter 	stringp  = ( char * ) malloc( strsize );
205822Speter 	if ( stringp == 0 ) {
206822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
207822Speter 	}
208822Speter 	red = fread( stringp + sizeof strsize
209822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
210822Speter 	if ( red != 1 ) {
211822Speter 	    error( WARNING , "error reading string table: %s"
212822Speter 		    , ofilep -> name );
213822Speter 	}
214822Speter #	ifdef DEBUG
215822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
216822Speter 		    , ofilep -> name , numsyms );
217822Speter #	endif DEBUG
218822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
219822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
220822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
221822Speter 	    } else {
222822Speter 		nlp[ sym ].n_un.n_name = "";
223822Speter 	    }
224822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
225822Speter 	}
226822Speter 	if ( nlp ) {
227822Speter 	    free( nlp );
228822Speter 	}
229822Speter 	if ( stringp ) {
230822Speter 	    free( stringp );
231822Speter 	}
232822Speter     }
233822Speter 
234822Speter     /*
235822Speter      *	check a symbol.
236822Speter      *	look it up in the hashed symbol table,
237822Speter      *	entering it if necessary.
238822Speter      *	this maintains a state of which .p and .i files
239822Speter      *	it is currently in the midst from the nlist entries
240822Speter      *	for source and included files.
241822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
242822Speter      */
243822Speter checksymbol( nlp , ofilep )
244822Speter     struct nlist	*nlp;
245822Speter     struct fileinfo	*ofilep;
246822Speter     {
247822Speter 	static struct symbol	*pfilep = NIL;
248822Speter 	static struct symbol	*ifilep = NIL;
249822Speter 	register struct symbol	*symbolp;
250822Speter 
251822Speter #	ifdef DEBUG
252822Speter 	    if ( pfilep && ifilep ) {
253822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
254822Speter 			, pfilep -> name , ifilep -> name );
255822Speter 	    }
256822Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_type %x (%s)\n"
257822Speter 		    , nlp -> n_un.n_name , nlp -> n_type
258822Speter 		    , classify( nlp -> n_type ) );
259822Speter #	endif DEBUG
260822Speter 	switch ( nlp -> n_type ) {
261822Speter 	    case N_PGLAB:
262822Speter 	    case N_PGCON:
263822Speter 	    case N_PGTYP:
264822Speter 	    case N_PGVAR:
265822Speter 	    case N_PGFUN:
266822Speter 	    case N_PGPRC:
267822Speter 	    case N_PEFUN:
268822Speter 	    case N_PEPRC:
269822Speter 	    case N_PSO:
270822Speter 	    case N_PSOL:
271822Speter 		    symbolp = entersymbol( nlp -> n_un.n_name );
272822Speter 		    break;
273822Speter 	    default:
274822Speter 			/* don't care about the others */
275822Speter 		    return;
276822Speter 	}
277822Speter 	if ( symbolp -> lookup == NEW ) {
278822Speter #	    ifdef DEBUG
279822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
280822Speter 			, symbolp -> name );
281822Speter #	    endif DEBUG
282822Speter 	    symbolp -> type = nlp -> n_type;
283822Speter 	    switch ( symbolp -> type ) {
284822Speter 		case N_PGLAB:
285822Speter 		case N_PGCON:
286822Speter 		case N_PGTYP:
287822Speter 		case N_PGVAR:
288822Speter 		case N_PGFUN:
289822Speter 		case N_PGPRC:
290*831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
291*831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
292*831Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
293*831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
294*831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
295*831Speter 			return;
296822Speter 		case N_PEFUN:
297822Speter 		case N_PEPRC:
298*831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
299*831Speter 			symbolp -> sym_un.sym_str.rline = 0;
300*831Speter 			    /*
301*831Speter 			     *	functions can only be declared external
302*831Speter 			     *	in included files.
303*831Speter 			     */
304*831Speter 			if ( pfilep == ifilep ) {
305*831Speter 			    error( WARNING
306*831Speter 				    , "%s, line %d: %s %s must be declared in included file"
307*831Speter 				    , pfilep -> name , nlp -> n_value
308*831Speter 				    , classify( symbolp -> type )
309*831Speter 				    , symbolp -> name );
310*831Speter 			}
311822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
312822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
313822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
314822Speter 			return;
315822Speter 		case N_PSO:
316822Speter 			pfilep = symbolp;
317822Speter 			/* and fall through */
318822Speter 		case N_PSOL:
319822Speter 			ifilep = symbolp;
320822Speter 			symbolp -> sym_un.modtime = mtime( symbolp -> name );
321822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
322822Speter 			    error( WARNING , "%s is out of date with %s"
323822Speter 				    , ofilep -> name , symbolp -> name );
324822Speter 			}
325822Speter 			return;
326822Speter 	    }
327822Speter 	} else {
328822Speter #	    ifdef DEBUG
329822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
330822Speter 			, symbolp -> name );
331822Speter #	    endif DEBUG
332822Speter 	    switch ( symbolp -> type ) {
333822Speter 		case N_PSO:
334822Speter 			    /*
335822Speter 			     *	finding a file again means you are back
336822Speter 			     *	in it after finishing an include file.
337822Speter 			     */
338822Speter 			pfilep = symbolp;
339822Speter 			/* and fall through */
340822Speter 		case N_PSOL:
341822Speter 			    /*
342822Speter 			     *	include files can be seen more than once,
343822Speter 			     *	but they still have to be timechecked.
344822Speter 			     *	(this will complain twice for out of date
345822Speter 			     *	include files which include other files.
346822Speter 			     *	sigh.)
347822Speter 			     */
348822Speter 			ifilep = symbolp;
349822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
350822Speter 			    error( WARNING , "%s is out of date with %s"
351822Speter 				    , ofilep -> name , symbolp -> name );
352822Speter 			}
353822Speter 			return;
354822Speter 		case N_PEFUN:
355822Speter 		case N_PEPRC:
356822Speter 			    /*
357822Speter 			     *	we may see any number of external declarations,
358822Speter 			     *	but they all have to come
359822Speter 			     *	from the same include file.
360822Speter 			     */
361822Speter 			if (   nlp -> n_type == N_PEFUN
362822Speter 			    || nlp -> n_type == N_PEPRC ) {
363822Speter 			    goto included;
364822Speter 			}
365822Speter 			    /*
366822Speter 			     *	an external function can be resolved by
367822Speter 			     *	the resolution of the function
368822Speter 			     *	if the resolving file
369822Speter 			     *	included the external declaration.
370822Speter 			     */
371822Speter 			if (    (  symbolp -> type == N_PEFUN
372822Speter 				&& nlp -> n_type != N_PGFUN )
373822Speter 			    ||  (  symbolp -> type == N_PEPRC
374822Speter 				&& nlp -> n_type != N_PGPRC )
375822Speter 			    || symbolp -> sym_un.sym_str.fromp != pfilep ) {
376822Speter 			    break;
377822Speter 			}
378822Speter 			    /*
379822Speter 			     *	an external function can only be resolved once.
380822Speter 			     */
381822Speter 			if ( symbolp -> sym_un.sym_str.rfilep != NIL ) {
382822Speter 			    break;
383822Speter 			}
384822Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
385822Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
386822Speter 			return;
387822Speter 		case N_PGFUN:
388822Speter 		case N_PGPRC:
389822Speter 			    /*
390822Speter 			     *	functions may not be seen more than once.
391822Speter 			     *	the loader will complain about
392822Speter 			     *	`multiply defined', but we can, too.
393822Speter 			     */
394822Speter 			break;
395822Speter 		case N_PGLAB:
396822Speter 		case N_PGCON:
397822Speter 		case N_PGTYP:
398822Speter 		case N_PGVAR:
399822Speter 			    /*
400822Speter 			     *	labels, constants, types, variables
401822Speter 			     *	and external declarations
402822Speter 			     *	may be seen as many times as they want,
403822Speter 			     *	as long as they come from the same include file.
404822Speter 			     *	make it look like they come from this .p file.
405822Speter 			     */
406822Speter included:
407822Speter 			if (  nlp -> n_type != symbolp -> type
408822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
409822Speter 			    break;
410822Speter 			}
411822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
412822Speter 			return;
413822Speter 	    }
414822Speter 		/*
415822Speter 		 *	this is the breaks
416822Speter 		 */
417822Speter 	    error( WARNING , "%s, line %d: %s already defined (%s, line %d)."
418822Speter 		    , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
419822Speter 		    , symbolp -> sym_un.sym_str.rfilep -> name
420822Speter 		    , symbolp -> sym_un.sym_str.rline );
421822Speter 	}
422822Speter     }
423822Speter 
424822Speter     /*
425822Speter      *	quadratically hashed symbol table.
426822Speter      *	things are never deleted from the hash symbol table.
427822Speter      *	as more hash table is needed,
428822Speter      *	a new one is alloc'ed and chained to the end.
429822Speter      *	search is by rehashing within each table,
430822Speter      *	traversing chains to next table if unsuccessful.
431822Speter      */
432822Speter struct symbol *
433822Speter entersymbol( name )
434822Speter     char	*name;
435822Speter     {
436822Speter 	static struct symboltableinfo	*symboltable = NIL;
437822Speter 	char				*enteredname;
438822Speter 	long				hashindex;
439822Speter 	register struct symboltableinfo	*tablep;
440822Speter 	register struct symbol		**herep;
441822Speter 	register struct symbol		**limitp;
442822Speter 	register long			increment;
443822Speter 
444822Speter 	enteredname = enterstring( name );
445822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
446822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
447822Speter 	    if ( tablep == NIL ) {
448822Speter #		ifdef DEBUG
449822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
450822Speter #		endif DEBUG
451822Speter 		tablep = ( struct symboltableinfo * )
452822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
453822Speter 		if ( tablep == NIL ) {
454822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
455822Speter 		}
456822Speter 		if ( symboltable == NIL ) {
457822Speter 		    symboltable = tablep;
458822Speter 		}
459822Speter 	    }
460822Speter 	    herep = &( tablep -> entry[ hashindex ] );
461822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
462822Speter 	    increment = 1;
463822Speter 	    do {
464822Speter #		ifdef DEBUG
465822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
466822Speter 			    , increment );
467822Speter #		endif DEBUG
468822Speter 		if ( *herep == NIL ) {
469822Speter 			/* empty */
470822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
471822Speter 			    /* too full, break for next table */
472822Speter 			break;
473822Speter 		    }
474822Speter 		    tablep -> used++;
475822Speter 		    *herep = symbolalloc();
476822Speter 		    ( *herep ) -> name = enteredname;
477822Speter 		    ( *herep ) -> lookup = NEW;
478822Speter #		    ifdef DEBUG
479822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
480822Speter 				, enteredname );
481822Speter #		    endif DEBUG
482822Speter 		    return *herep;
483822Speter 		}
484822Speter 		    /* a find? */
485822Speter 		if ( ( *herep ) -> name == enteredname ) {
486822Speter 		    ( *herep ) -> lookup = OLD;
487822Speter #		    ifdef DEBUG
488822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
489822Speter 				, enteredname );
490822Speter #		    endif DEBUG
491822Speter 		    return *herep;
492822Speter 		}
493822Speter 		herep += increment;
494822Speter 		if ( herep >= limitp ) {
495822Speter 		    herep -= SYMBOLPRIME;
496822Speter 		}
497822Speter 		increment += 2;
498822Speter 	    } while ( increment < SYMBOLPRIME );
499822Speter 	}
500822Speter     }
501822Speter 
502822Speter     /*
503822Speter      *	allocate a symbol from the dynamically allocated symbol table.
504822Speter      */
505822Speter struct symbol *
506822Speter symbolalloc()
507822Speter     {
508822Speter 	static struct symbol	*nextsymbol = NIL;
509822Speter 	static long		symbolsleft = 0;
510822Speter 	struct symbol		*newsymbol;
511822Speter 
512822Speter 	if ( symbolsleft <= 0 ) {
513822Speter #	    ifdef DEBUG
514822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
515822Speter #	    endif DEBUG
516822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
517822Speter 	    if ( nextsymbol == 0 ) {
518822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
519822Speter 	    }
520822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
521822Speter 	}
522822Speter 	newsymbol = nextsymbol;
523822Speter 	nextsymbol++;
524822Speter 	symbolsleft--;
525822Speter 	return newsymbol;
526822Speter     }
527822Speter 
528822Speter     /*
529822Speter      *	hash a string based on all of its characters.
530822Speter      */
531822Speter long
532822Speter hashstring( string )
533822Speter     char	*string;
534822Speter     {
535822Speter 	register char	*cp;
536822Speter 	register long	value;
537822Speter 
538822Speter 	value = 0;
539822Speter 	for ( cp = string ; *cp ; cp++ ) {
540822Speter 	    value = ( value * 2 ) + *cp;
541822Speter 	}
542822Speter 	return value;
543822Speter     }
544822Speter 
545822Speter     /*
546822Speter      *	quadratically hashed string table.
547822Speter      *	things are never deleted from the hash string table.
548822Speter      *	as more hash table is needed,
549822Speter      *	a new one is alloc'ed and chained to the end.
550822Speter      *	search is by rehashing within each table,
551822Speter      *	traversing chains to next table if unsuccessful.
552822Speter      */
553822Speter char *
554822Speter enterstring( string )
555822Speter     char	*string;
556822Speter     {
557822Speter 	static struct stringtableinfo	*stringtable = NIL;
558822Speter 	long				hashindex;
559822Speter 	register struct stringtableinfo	*tablep;
560822Speter 	register char			**herep;
561822Speter 	register char			**limitp;
562822Speter 	register long			increment;
563822Speter 
564822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
565822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
566822Speter 	    if ( tablep == NIL ) {
567822Speter #		ifdef DEBUG
568822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
569822Speter #		endif DEBUG
570822Speter 		tablep = ( struct stringtableinfo * )
571822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
572822Speter 		if ( tablep == NIL ) {
573822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
574822Speter 		}
575822Speter 		if ( stringtable == NIL ) {
576822Speter 		    stringtable = tablep;
577822Speter 		}
578822Speter 	    }
579822Speter 	    herep = &( tablep -> entry[ hashindex ] );
580822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
581822Speter 	    increment = 1;
582822Speter 	    do {
583822Speter #		ifdef DEBUG
584822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
585822Speter 			    , increment );
586822Speter #		endif DEBUG
587822Speter 		if ( *herep == NIL ) {
588822Speter 			/* empty */
589822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
590822Speter 			    /* too full, break for next table */
591822Speter 			break;
592822Speter 		    }
593822Speter 		    tablep -> used++;
594822Speter 		    *herep = charalloc( strlen( string ) );
595822Speter 		    strcpy( *herep , string );
596822Speter #		    ifdef DEBUG
597822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
598822Speter 				, *herep );
599822Speter #		    endif DEBUG
600822Speter 		    return *herep;
601822Speter 		}
602822Speter 		    /* quick, check the first chars and then the rest */
603822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
604822Speter #		    ifdef DEBUG
605822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
606822Speter 				, *herep );
607822Speter #		    endif DEBUG
608822Speter 		    return *herep;
609822Speter 		}
610822Speter 		herep += increment;
611822Speter 		if ( herep >= limitp ) {
612822Speter 		    herep -= STRINGPRIME;
613822Speter 		}
614822Speter 		increment += 2;
615822Speter 	    } while ( increment < STRINGPRIME );
616822Speter 	}
617822Speter     }
618822Speter 
619822Speter     /*
620822Speter      *	copy a string to the dynamically allocated character table.
621822Speter      */
622822Speter char *
623822Speter charalloc( length )
624822Speter     register long	length;
625822Speter     {
626822Speter 	static char	*nextchar = NIL;
627822Speter 	static long	charsleft = 0;
628822Speter 	register long	lengthplus1 = length + 1;
629822Speter 	register long	askfor;
630822Speter 	char		*newstring;
631822Speter 
632822Speter 	if ( charsleft < lengthplus1 ) {
633822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
634822Speter #	    ifdef DEBUG
635822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
636822Speter 			, askfor );
637822Speter #	    endif DEBUG
638822Speter 	    nextchar = ( char * ) malloc( askfor );
639822Speter 	    if ( nextchar == 0 ) {
640822Speter 		error( FATAL , "no room for %d characters" , askfor );
641822Speter 	    }
642822Speter 	    charsleft = askfor;
643822Speter 	}
644822Speter 	newstring = nextchar;
645822Speter 	nextchar += lengthplus1;
646822Speter 	charsleft -= lengthplus1;
647822Speter 	return newstring;
648822Speter     }
649822Speter 
650822Speter     /*
651822Speter      *	read an archive header for the next element
652822Speter      *	and find the offset of the one after this.
653822Speter      */
654822Speter BOOL
655822Speter nextelement( ofilep )
656822Speter     struct fileinfo	*ofilep;
657822Speter     {
658822Speter 	register char	*cp;
659822Speter 	register long	red;
660822Speter 	register off_t	arsize;
661822Speter 	struct ar_hdr	archdr;
662822Speter 
663822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
664822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
665822Speter 	if ( red != sizeof archdr ) {
666822Speter 	    return FALSE;
667822Speter 	}
668822Speter 	    /* null terminate the blank-padded name */
669822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
670822Speter 	*cp = '\0';
671822Speter 	while ( *--cp == ' ' ) {
672822Speter 	    *cp = '\0';
673822Speter 	}
674822Speter 	    /* set up the address of the beginning of next element */
675822Speter 	arsize = atol( archdr.ar_size );
676822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
677822Speter 	if ( arsize & 1 ) {
678822Speter 	    arsize += 1;
679822Speter 	}
680822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
681822Speter 	    /* say we had one */
682822Speter 	return TRUE;
683822Speter     }
684822Speter 
685822Speter     /*
686822Speter      *	variable number of arguments to error, like printf.
687822Speter      */
688822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
689822Speter     int		fatal;
690822Speter     char	*message;
691822Speter     {
692822Speter 	fprintf( stderr , "%s: " , program );
693822Speter 	fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 );
694822Speter 	fprintf( stderr , "\n" );
695822Speter 	if ( fatal == FATAL ) {
696822Speter 	    exit( 2 );
697822Speter 	}
698822Speter 	errors = 1;
699822Speter     }
700822Speter 
701822Speter     /*
702822Speter      *	find the last modify time of a file.
703822Speter      *	on error, return the current time.
704822Speter      */
705822Speter time_t
706822Speter mtime( filename )
707822Speter     char	*filename;
708822Speter     {
709822Speter 	struct stat	filestat;
710822Speter 
711822Speter #	ifdef DEBUG
712822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
713822Speter 		    , filename );
714822Speter #	endif DEBUG
715829Speter 	if ( stat( filename , &filestat ) != 0 ) {
716822Speter 	    error( WARNING , "%s: cannot open" , filename );
717822Speter 	    return ( (time_t) time( 0 ) );
718822Speter 	}
719822Speter 	return filestat.st_mtime;
720822Speter     }
721822Speter 
722822Speter char *
723822Speter classify( type )
724822Speter     unsigned char	type;
725822Speter     {
726822Speter 	switch ( type ) {
727822Speter 	    case N_PSO:
728822Speter 		return "source file";
729822Speter 	    case N_PSOL:
730822Speter 		return "include file";
731822Speter 	    case N_PGLAB:
732822Speter 		return "label";
733822Speter 	    case N_PGCON:
734822Speter 		return "constant";
735822Speter 	    case N_PGTYP:
736822Speter 		return "type";
737822Speter 	    case N_PGVAR:
738822Speter 		return "variable";
739822Speter 	    case N_PGFUN:
740822Speter 		return "function";
741822Speter 	    case N_PGPRC:
742822Speter 		return "procedure";
743822Speter 	    case N_PEFUN:
744822Speter 		return "external function";
745822Speter 	    case N_PEPRC:
746822Speter 		return "external procedure";
747822Speter 	    default:
748822Speter 		return "unknown symbol";
749822Speter 	}
750822Speter     }
751