xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 7550)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*7550Speter static	char sccsid[] = "@(#)pc3.c 1.7 07/26/82";
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;
31844Speter      *	   - a subtype descriptor;
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 
64832Speter char	program[] = "pc";
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>
74858Speter #include "pstab.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 
88831Speter 	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;
161831Speter 	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 
169831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
170831Speter 	if ( red != sizeof oexec ) {
171822Speter 	    error( WARNING , "error reading struct exec: %s"
172822Speter 		    , ofilep -> name );
173822Speter 	    return;
174822Speter 	}
175831Speter 	if ( N_BADMAG( oexec ) ) {
176822Speter 	    return;
177822Speter 	}
178831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
179822Speter 	fseek( ofilep -> file , symoff , 1 );
180831Speter 	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 	    }
256844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
257844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
258844Speter 		    , classify( nlp -> n_desc ) );
259822Speter #	endif DEBUG
260844Speter 	if ( nlp -> n_type != N_PC ) {
261844Speter 		/* don't care about the others */
262844Speter 	    return;
263822Speter 	}
264844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
265822Speter 	if ( symbolp -> lookup == NEW ) {
266822Speter #	    ifdef DEBUG
267822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
268822Speter 			, symbolp -> name );
269822Speter #	    endif DEBUG
270844Speter 	    symbolp -> desc = nlp -> n_desc;
271844Speter 	    switch ( symbolp -> desc ) {
272*7550Speter 		default:
273*7550Speter 			error( FATAL , "panic: [checksymbol] NEW" );
274844Speter 		case N_PGLABEL:
275844Speter 		case N_PGCONST:
276844Speter 		case N_PGTYPE:
277822Speter 		case N_PGVAR:
278844Speter 		case N_PGFUNC:
279844Speter 		case N_PGPROC:
280831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
281831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
282831Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
283831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
284831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
285831Speter 			return;
286844Speter 		case N_PEFUNC:
287844Speter 		case N_PEPROC:
288831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
289831Speter 			symbolp -> sym_un.sym_str.rline = 0;
290831Speter 			    /*
291831Speter 			     *	functions can only be declared external
292831Speter 			     *	in included files.
293831Speter 			     */
294831Speter 			if ( pfilep == ifilep ) {
295831Speter 			    error( WARNING
296831Speter 				    , "%s, line %d: %s %s must be declared in included file"
297831Speter 				    , pfilep -> name , nlp -> n_value
298844Speter 				    , classify( symbolp -> desc )
299831Speter 				    , symbolp -> name );
300831Speter 			}
301822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
302822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
303822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
304822Speter 			return;
305822Speter 		case N_PSO:
306822Speter 			pfilep = symbolp;
307822Speter 			/* and fall through */
308822Speter 		case N_PSOL:
309822Speter 			ifilep = symbolp;
310822Speter 			symbolp -> sym_un.modtime = mtime( symbolp -> name );
311822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
312822Speter 			    error( WARNING , "%s is out of date with %s"
313822Speter 				    , ofilep -> name , symbolp -> name );
314822Speter 			}
315822Speter 			return;
316822Speter 	    }
317822Speter 	} else {
318822Speter #	    ifdef DEBUG
319822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
320822Speter 			, symbolp -> name );
321822Speter #	    endif DEBUG
322844Speter 	    switch ( symbolp -> desc ) {
323*7550Speter 		default:
324*7550Speter 			error( FATAL , "panic [checksymbol] OLD" );
325822Speter 		case N_PSO:
326822Speter 			    /*
327822Speter 			     *	finding a file again means you are back
328822Speter 			     *	in it after finishing an include file.
329822Speter 			     */
330822Speter 			pfilep = symbolp;
331822Speter 			/* and fall through */
332822Speter 		case N_PSOL:
333822Speter 			    /*
334822Speter 			     *	include files can be seen more than once,
335822Speter 			     *	but they still have to be timechecked.
336822Speter 			     *	(this will complain twice for out of date
337822Speter 			     *	include files which include other files.
338822Speter 			     *	sigh.)
339822Speter 			     */
340822Speter 			ifilep = symbolp;
341822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
342822Speter 			    error( WARNING , "%s is out of date with %s"
343822Speter 				    , ofilep -> name , symbolp -> name );
344822Speter 			}
345822Speter 			return;
346844Speter 		case N_PEFUNC:
347844Speter 		case N_PEPROC:
348822Speter 			    /*
349*7550Speter 			     *	this might be the resolution of the external
350*7550Speter 			     *	has to match func/proc of external
351*7550Speter 			     *	and has to have included external
352*7550Speter 			     *	and has to not have been previously resolved.
353822Speter 			     */
354*7550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
355*7550Speter 			         && nlp -> n_desc == N_PGFUNC )
356*7550Speter 			      || ( symbolp -> desc == N_PEPROC
357*7550Speter 				 && nlp -> n_desc == N_PGPROC ) )
358*7550Speter 			   && ( symbolp -> sym_un.sym_str.fromp == pfilep )
359*7550Speter 			   && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
360*7550Speter 				/*
361*7550Speter 				 *	resolve external
362*7550Speter 				 */
363*7550Speter #			    ifdef DEBUG
364*7550Speter 				fprintf( stderr , "[checksymbol] resolving external\n" );
365*7550Speter #			    endif DEBUG
366*7550Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
367*7550Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
368*7550Speter 			    return;
369822Speter 			}
370822Speter 			    /*
371*7550Speter 			     *	otherwise, it might be another external,
372*7550Speter 			     *	which is okay if it's
373*7550Speter 			     *	the same type and from the same include file
374822Speter 			     */
375*7550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
376*7550Speter 			         && nlp -> n_desc == N_PEFUNC )
377*7550Speter 			      || ( symbolp -> desc == N_PEPROC
378*7550Speter 				 && nlp -> n_desc == N_PEPROC ) )
379*7550Speter 			   && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
380*7550Speter 				/*
381*7550Speter 				 *	just another pretty external
382*7550Speter 				 *	make it look like it comes from here.
383*7550Speter 				 */
384*7550Speter #			    ifdef DEBUG
385*7550Speter 				fprintf( stderr , "[checksymbol] just another pretty external\n" );
386*7550Speter #			    endif DEBUG
387*7550Speter 			    symbolp -> sym_un.sym_str.fromp = pfilep;
388*7550Speter 			    return;
389822Speter 			}
390822Speter 			    /*
391*7550Speter 			     *	something is wrong
392822Speter 			     */
393*7550Speter 			error( WARNING ,
394*7550Speter 			    "%s, line %d: %s already defined (%s, line %d)." ,
395*7550Speter 			    ifilep -> name , nlp -> n_value ,
396*7550Speter 			    nlp -> n_un.n_name ,
397*7550Speter 			    symbolp -> sym_un.sym_str.fromi -> name ,
398*7550Speter 			    symbolp -> sym_un.sym_str.iline );
399822Speter 			return;
400844Speter 		case N_PGFUNC:
401844Speter 		case N_PGPROC:
402822Speter 			    /*
403822Speter 			     *	functions may not be seen more than once.
404822Speter 			     *	the loader will complain about
405822Speter 			     *	`multiply defined', but we can, too.
406822Speter 			     */
407822Speter 			break;
408844Speter 		case N_PGLABEL:
409844Speter 		case N_PGCONST:
410844Speter 		case N_PGTYPE:
411822Speter 		case N_PGVAR:
412822Speter 			    /*
413822Speter 			     *	labels, constants, types, variables
414822Speter 			     *	and external declarations
415822Speter 			     *	may be seen as many times as they want,
416822Speter 			     *	as long as they come from the same include file.
417822Speter 			     *	make it look like they come from this .p file.
418822Speter 			     */
419822Speter included:
420844Speter 			if (  nlp -> n_desc != symbolp -> desc
421822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
422822Speter 			    break;
423822Speter 			}
424822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
425822Speter 			return;
426822Speter 	    }
427822Speter 		/*
428822Speter 		 *	this is the breaks
429822Speter 		 */
430822Speter 	    error( WARNING , "%s, line %d: %s already defined (%s, line %d)."
431822Speter 		    , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
432822Speter 		    , symbolp -> sym_un.sym_str.rfilep -> name
433822Speter 		    , symbolp -> sym_un.sym_str.rline );
434822Speter 	}
435822Speter     }
436822Speter 
437822Speter     /*
438822Speter      *	quadratically hashed symbol table.
439822Speter      *	things are never deleted from the hash symbol table.
440822Speter      *	as more hash table is needed,
441822Speter      *	a new one is alloc'ed and chained to the end.
442822Speter      *	search is by rehashing within each table,
443822Speter      *	traversing chains to next table if unsuccessful.
444822Speter      */
445822Speter struct symbol *
446822Speter entersymbol( name )
447822Speter     char	*name;
448822Speter     {
449822Speter 	static struct symboltableinfo	*symboltable = NIL;
450822Speter 	char				*enteredname;
451822Speter 	long				hashindex;
452822Speter 	register struct symboltableinfo	*tablep;
453822Speter 	register struct symbol		**herep;
454822Speter 	register struct symbol		**limitp;
455822Speter 	register long			increment;
456822Speter 
457822Speter 	enteredname = enterstring( name );
458822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
459822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
460822Speter 	    if ( tablep == NIL ) {
461822Speter #		ifdef DEBUG
462822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
463822Speter #		endif DEBUG
464822Speter 		tablep = ( struct symboltableinfo * )
465822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
466822Speter 		if ( tablep == NIL ) {
467822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
468822Speter 		}
469822Speter 		if ( symboltable == NIL ) {
470822Speter 		    symboltable = tablep;
471822Speter 		}
472822Speter 	    }
473822Speter 	    herep = &( tablep -> entry[ hashindex ] );
474822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
475822Speter 	    increment = 1;
476822Speter 	    do {
477822Speter #		ifdef DEBUG
478822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
479822Speter 			    , increment );
480822Speter #		endif DEBUG
481822Speter 		if ( *herep == NIL ) {
482822Speter 			/* empty */
483822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
484822Speter 			    /* too full, break for next table */
485822Speter 			break;
486822Speter 		    }
487822Speter 		    tablep -> used++;
488822Speter 		    *herep = symbolalloc();
489822Speter 		    ( *herep ) -> name = enteredname;
490822Speter 		    ( *herep ) -> lookup = NEW;
491822Speter #		    ifdef DEBUG
492822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
493822Speter 				, enteredname );
494822Speter #		    endif DEBUG
495822Speter 		    return *herep;
496822Speter 		}
497822Speter 		    /* a find? */
498822Speter 		if ( ( *herep ) -> name == enteredname ) {
499822Speter 		    ( *herep ) -> lookup = OLD;
500822Speter #		    ifdef DEBUG
501822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
502822Speter 				, enteredname );
503822Speter #		    endif DEBUG
504822Speter 		    return *herep;
505822Speter 		}
506822Speter 		herep += increment;
507822Speter 		if ( herep >= limitp ) {
508822Speter 		    herep -= SYMBOLPRIME;
509822Speter 		}
510822Speter 		increment += 2;
511822Speter 	    } while ( increment < SYMBOLPRIME );
512822Speter 	}
513822Speter     }
514822Speter 
515822Speter     /*
516822Speter      *	allocate a symbol from the dynamically allocated symbol table.
517822Speter      */
518822Speter struct symbol *
519822Speter symbolalloc()
520822Speter     {
521822Speter 	static struct symbol	*nextsymbol = NIL;
522822Speter 	static long		symbolsleft = 0;
523822Speter 	struct symbol		*newsymbol;
524822Speter 
525822Speter 	if ( symbolsleft <= 0 ) {
526822Speter #	    ifdef DEBUG
527822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
528822Speter #	    endif DEBUG
529822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
530822Speter 	    if ( nextsymbol == 0 ) {
531822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
532822Speter 	    }
533822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
534822Speter 	}
535822Speter 	newsymbol = nextsymbol;
536822Speter 	nextsymbol++;
537822Speter 	symbolsleft--;
538822Speter 	return newsymbol;
539822Speter     }
540822Speter 
541822Speter     /*
542822Speter      *	hash a string based on all of its characters.
543822Speter      */
544822Speter long
545822Speter hashstring( string )
546822Speter     char	*string;
547822Speter     {
548822Speter 	register char	*cp;
549822Speter 	register long	value;
550822Speter 
551822Speter 	value = 0;
552822Speter 	for ( cp = string ; *cp ; cp++ ) {
553822Speter 	    value = ( value * 2 ) + *cp;
554822Speter 	}
555822Speter 	return value;
556822Speter     }
557822Speter 
558822Speter     /*
559822Speter      *	quadratically hashed string table.
560822Speter      *	things are never deleted from the hash string table.
561822Speter      *	as more hash table is needed,
562822Speter      *	a new one is alloc'ed and chained to the end.
563822Speter      *	search is by rehashing within each table,
564822Speter      *	traversing chains to next table if unsuccessful.
565822Speter      */
566822Speter char *
567822Speter enterstring( string )
568822Speter     char	*string;
569822Speter     {
570822Speter 	static struct stringtableinfo	*stringtable = NIL;
571822Speter 	long				hashindex;
572822Speter 	register struct stringtableinfo	*tablep;
573822Speter 	register char			**herep;
574822Speter 	register char			**limitp;
575822Speter 	register long			increment;
576822Speter 
577822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
578822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
579822Speter 	    if ( tablep == NIL ) {
580822Speter #		ifdef DEBUG
581822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
582822Speter #		endif DEBUG
583822Speter 		tablep = ( struct stringtableinfo * )
584822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
585822Speter 		if ( tablep == NIL ) {
586822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
587822Speter 		}
588822Speter 		if ( stringtable == NIL ) {
589822Speter 		    stringtable = tablep;
590822Speter 		}
591822Speter 	    }
592822Speter 	    herep = &( tablep -> entry[ hashindex ] );
593822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
594822Speter 	    increment = 1;
595822Speter 	    do {
596822Speter #		ifdef DEBUG
597822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
598822Speter 			    , increment );
599822Speter #		endif DEBUG
600822Speter 		if ( *herep == NIL ) {
601822Speter 			/* empty */
602822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
603822Speter 			    /* too full, break for next table */
604822Speter 			break;
605822Speter 		    }
606822Speter 		    tablep -> used++;
607822Speter 		    *herep = charalloc( strlen( string ) );
608822Speter 		    strcpy( *herep , string );
609822Speter #		    ifdef DEBUG
610822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
611822Speter 				, *herep );
612822Speter #		    endif DEBUG
613822Speter 		    return *herep;
614822Speter 		}
615822Speter 		    /* quick, check the first chars and then the rest */
616822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
617822Speter #		    ifdef DEBUG
618822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
619822Speter 				, *herep );
620822Speter #		    endif DEBUG
621822Speter 		    return *herep;
622822Speter 		}
623822Speter 		herep += increment;
624822Speter 		if ( herep >= limitp ) {
625822Speter 		    herep -= STRINGPRIME;
626822Speter 		}
627822Speter 		increment += 2;
628822Speter 	    } while ( increment < STRINGPRIME );
629822Speter 	}
630822Speter     }
631822Speter 
632822Speter     /*
633822Speter      *	copy a string to the dynamically allocated character table.
634822Speter      */
635822Speter char *
636822Speter charalloc( length )
637822Speter     register long	length;
638822Speter     {
639822Speter 	static char	*nextchar = NIL;
640822Speter 	static long	charsleft = 0;
641822Speter 	register long	lengthplus1 = length + 1;
642822Speter 	register long	askfor;
643822Speter 	char		*newstring;
644822Speter 
645822Speter 	if ( charsleft < lengthplus1 ) {
646822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
647822Speter #	    ifdef DEBUG
648822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
649822Speter 			, askfor );
650822Speter #	    endif DEBUG
651822Speter 	    nextchar = ( char * ) malloc( askfor );
652822Speter 	    if ( nextchar == 0 ) {
653822Speter 		error( FATAL , "no room for %d characters" , askfor );
654822Speter 	    }
655822Speter 	    charsleft = askfor;
656822Speter 	}
657822Speter 	newstring = nextchar;
658822Speter 	nextchar += lengthplus1;
659822Speter 	charsleft -= lengthplus1;
660822Speter 	return newstring;
661822Speter     }
662822Speter 
663822Speter     /*
664822Speter      *	read an archive header for the next element
665822Speter      *	and find the offset of the one after this.
666822Speter      */
667822Speter BOOL
668822Speter nextelement( ofilep )
669822Speter     struct fileinfo	*ofilep;
670822Speter     {
671822Speter 	register char	*cp;
672822Speter 	register long	red;
673822Speter 	register off_t	arsize;
674822Speter 	struct ar_hdr	archdr;
675822Speter 
676822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
677822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
678822Speter 	if ( red != sizeof archdr ) {
679822Speter 	    return FALSE;
680822Speter 	}
681822Speter 	    /* null terminate the blank-padded name */
682822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
683822Speter 	*cp = '\0';
684822Speter 	while ( *--cp == ' ' ) {
685822Speter 	    *cp = '\0';
686822Speter 	}
687822Speter 	    /* set up the address of the beginning of next element */
688822Speter 	arsize = atol( archdr.ar_size );
689822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
690822Speter 	if ( arsize & 1 ) {
691822Speter 	    arsize += 1;
692822Speter 	}
693822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
694822Speter 	    /* say we had one */
695822Speter 	return TRUE;
696822Speter     }
697822Speter 
698822Speter     /*
699822Speter      *	variable number of arguments to error, like printf.
700822Speter      */
701822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
702822Speter     int		fatal;
703822Speter     char	*message;
704822Speter     {
705822Speter 	fprintf( stderr , "%s: " , program );
706822Speter 	fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 );
707822Speter 	fprintf( stderr , "\n" );
708822Speter 	if ( fatal == FATAL ) {
709822Speter 	    exit( 2 );
710822Speter 	}
711822Speter 	errors = 1;
712822Speter     }
713822Speter 
714822Speter     /*
715822Speter      *	find the last modify time of a file.
716822Speter      *	on error, return the current time.
717822Speter      */
718822Speter time_t
719822Speter mtime( filename )
720822Speter     char	*filename;
721822Speter     {
722822Speter 	struct stat	filestat;
723822Speter 
724822Speter #	ifdef DEBUG
725822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
726822Speter 		    , filename );
727822Speter #	endif DEBUG
728829Speter 	if ( stat( filename , &filestat ) != 0 ) {
729822Speter 	    error( WARNING , "%s: cannot open" , filename );
730822Speter 	    return ( (time_t) time( 0 ) );
731822Speter 	}
732822Speter 	return filestat.st_mtime;
733822Speter     }
734822Speter 
735822Speter char *
736822Speter classify( type )
737822Speter     unsigned char	type;
738822Speter     {
739822Speter 	switch ( type ) {
740822Speter 	    case N_PSO:
741822Speter 		return "source file";
742822Speter 	    case N_PSOL:
743822Speter 		return "include file";
744844Speter 	    case N_PGLABEL:
745822Speter 		return "label";
746844Speter 	    case N_PGCONST:
747822Speter 		return "constant";
748844Speter 	    case N_PGTYPE:
749822Speter 		return "type";
750822Speter 	    case N_PGVAR:
751822Speter 		return "variable";
752844Speter 	    case N_PGFUNC:
753822Speter 		return "function";
754844Speter 	    case N_PGPROC:
755822Speter 		return "procedure";
756844Speter 	    case N_PEFUNC:
757822Speter 		return "external function";
758844Speter 	    case N_PEPROC:
759822Speter 		return "external procedure";
760822Speter 	    default:
761822Speter 		return "unknown symbol";
762822Speter 	}
763822Speter     }
764