xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 7598)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*7598Speter static	char sccsid[] = "@(#)pc3.c 1.8 07/29/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 
77*7598Speter int	errors = NONE;
78*7598Speter BOOL	wflag = FALSE;
79822Speter 
80822Speter     /*
81822Speter      *	check each of the argument .o files (or archives of .o files).
82822Speter      */
83822Speter main( argc , argv )
84822Speter     int		argc;
85822Speter     char	**argv;
86822Speter     {
87822Speter 	struct fileinfo	ofile;
88822Speter 
89*7598Speter 	for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) {
90*7598Speter 	    (*argv)++;
91*7598Speter 	    switch ( **argv ) {
92*7598Speter 		default:
93*7598Speter 		    error( FATAL , "pc3: bad flag -%c\n" , **argv );
94*7598Speter 		case 'w':
95*7598Speter 		    wflag = TRUE;
96*7598Speter 		    break;
97*7598Speter 	    }
98*7598Speter 	}
99*7598Speter 	for ( /* void */ ; *argv != 0 ; argv++ ) {
100822Speter #	    ifdef DEBUG
101822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
102822Speter #	    endif DEBUG
103822Speter 	    ofile.name = *argv;
104822Speter 	    checkfile( &ofile );
105822Speter 	}
106822Speter 	exit( errors );
107822Speter     }
108822Speter 
109822Speter     /*
110822Speter      *	check the namelist of a file, or all namelists of an archive.
111822Speter      */
112822Speter checkfile( ofilep )
113822Speter     struct fileinfo	*ofilep;
114822Speter     {
115822Speter 	union {
116822Speter 	    char	mag_armag[ SARMAG + 1 ];
117822Speter 	    struct exec	mag_exec;
118822Speter 	}		mag_un;
119822Speter 	int		red;
120822Speter 	struct stat	filestat;
121822Speter 
122822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
123822Speter 	if ( ofilep -> file == NULL ) {
124*7598Speter 	    error( ERROR , "cannot open: %s" , ofilep -> name );
125822Speter 	    return;
126822Speter 	}
127822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
128822Speter 	ofilep -> modtime = filestat.st_mtime;
129822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
130822Speter 	if ( red != sizeof mag_un ) {
131*7598Speter 	    error( ERROR , "cannot read header: %s" , ofilep -> name );
132822Speter 	    return;
133822Speter 	}
134822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
135822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
136822Speter 	    return;
137822Speter 	}
138822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
139822Speter 		/* archive, iterate through elements */
140822Speter #	    ifdef DEBUG
141822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
142822Speter #	    endif DEBUG
143822Speter 	    ofilep -> nextoffset = SARMAG;
144822Speter 	    while ( nextelement( ofilep ) ) {
145822Speter 		checknl( ofilep );
146822Speter 	    }
147822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
148822Speter 		/* not a file.o */
149*7598Speter 	    error( ERROR , "bad format: %s" , ofilep -> name );
150822Speter 	    return;
151822Speter 	} else {
152822Speter 		/* a file.o */
153822Speter #	    ifdef DEBUG
154822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
155822Speter #	    endif DEBUG
156822Speter 	    fseek( ofilep -> file , 0L , 0 );
157822Speter 	    ofilep -> nextoffset = filestat.st_size;
158822Speter 	    checknl( ofilep );
159822Speter 	}
160822Speter 	fclose( ofilep -> file );
161822Speter     }
162822Speter 
163822Speter     /*
164822Speter      *	check the namelist of this file for conflicts with
165822Speter      *	previously entered symbols.
166822Speter      */
167822Speter checknl( ofilep )
168822Speter     register struct fileinfo	*ofilep;
169822Speter     {
170822Speter 
171822Speter 	long			red;
172831Speter 	struct exec		oexec;
173822Speter 	off_t			symoff;
174822Speter 	long			numsyms;
175822Speter 	register struct nlist	*nlp;
176822Speter 	register char		*stringp;
177822Speter 	long			strsize;
178822Speter 	long			sym;
179822Speter 
180831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
181831Speter 	if ( red != sizeof oexec ) {
182*7598Speter 	    error( ERROR , "error reading struct exec: %s"
183822Speter 		    , ofilep -> name );
184822Speter 	    return;
185822Speter 	}
186831Speter 	if ( N_BADMAG( oexec ) ) {
187822Speter 	    return;
188822Speter 	}
189831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
190822Speter 	fseek( ofilep -> file , symoff , 1 );
191831Speter 	numsyms = oexec.a_syms / sizeof ( struct nlist );
192822Speter 	if ( numsyms == 0 ) {
193822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
194822Speter 	    return;
195822Speter 	}
196822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
197822Speter 	if ( nlp == 0 ) {
198822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
199822Speter 	}
200822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
201822Speter 		    , ofilep -> file );
202822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
203822Speter 	    >= ofilep -> nextoffset ) {
204822Speter 	    error( WARNING , "no string table (old format .o?)"
205822Speter 		    , ofilep -> name );
206822Speter 	    return;
207822Speter 	}
208822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
209822Speter 		    , ofilep -> file );
210822Speter 	if ( red != 1 ) {
211822Speter 	    error( WARNING , "no string table (old format .o?)"
212822Speter 		    , ofilep -> name );
213822Speter 	    return;
214822Speter 	}
215822Speter 	stringp  = ( char * ) malloc( strsize );
216822Speter 	if ( stringp == 0 ) {
217822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
218822Speter 	}
219822Speter 	red = fread( stringp + sizeof strsize
220822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
221822Speter 	if ( red != 1 ) {
222822Speter 	    error( WARNING , "error reading string table: %s"
223822Speter 		    , ofilep -> name );
224822Speter 	}
225822Speter #	ifdef DEBUG
226822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
227822Speter 		    , ofilep -> name , numsyms );
228822Speter #	endif DEBUG
229822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
230822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
231822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
232822Speter 	    } else {
233822Speter 		nlp[ sym ].n_un.n_name = "";
234822Speter 	    }
235822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
236822Speter 	}
237822Speter 	if ( nlp ) {
238822Speter 	    free( nlp );
239822Speter 	}
240822Speter 	if ( stringp ) {
241822Speter 	    free( stringp );
242822Speter 	}
243822Speter     }
244822Speter 
245822Speter     /*
246822Speter      *	check a symbol.
247822Speter      *	look it up in the hashed symbol table,
248822Speter      *	entering it if necessary.
249822Speter      *	this maintains a state of which .p and .i files
250822Speter      *	it is currently in the midst from the nlist entries
251822Speter      *	for source and included files.
252822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
253822Speter      */
254822Speter checksymbol( nlp , ofilep )
255822Speter     struct nlist	*nlp;
256822Speter     struct fileinfo	*ofilep;
257822Speter     {
258822Speter 	static struct symbol	*pfilep = NIL;
259822Speter 	static struct symbol	*ifilep = NIL;
260822Speter 	register struct symbol	*symbolp;
261822Speter 
262822Speter #	ifdef DEBUG
263822Speter 	    if ( pfilep && ifilep ) {
264822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
265822Speter 			, pfilep -> name , ifilep -> name );
266822Speter 	    }
267844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
268844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
269844Speter 		    , classify( nlp -> n_desc ) );
270822Speter #	endif DEBUG
271844Speter 	if ( nlp -> n_type != N_PC ) {
272844Speter 		/* don't care about the others */
273844Speter 	    return;
274822Speter 	}
275844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
276822Speter 	if ( symbolp -> lookup == NEW ) {
277822Speter #	    ifdef DEBUG
278822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
279822Speter 			, symbolp -> name );
280822Speter #	    endif DEBUG
281844Speter 	    symbolp -> desc = nlp -> n_desc;
282844Speter 	    switch ( symbolp -> desc ) {
2837550Speter 		default:
2847550Speter 			error( FATAL , "panic: [checksymbol] NEW" );
285844Speter 		case N_PGLABEL:
286844Speter 		case N_PGCONST:
287844Speter 		case N_PGTYPE:
288822Speter 		case N_PGVAR:
289844Speter 		case N_PGFUNC:
290844Speter 		case N_PGPROC:
291831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
292831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
293831Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
294831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
295831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
296831Speter 			return;
297844Speter 		case N_PEFUNC:
298844Speter 		case N_PEPROC:
299831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
300831Speter 			symbolp -> sym_un.sym_str.rline = 0;
301831Speter 			    /*
302831Speter 			     *	functions can only be declared external
303831Speter 			     *	in included files.
304831Speter 			     */
305831Speter 			if ( pfilep == ifilep ) {
306831Speter 			    error( WARNING
307831Speter 				    , "%s, line %d: %s %s must be declared in included file"
308831Speter 				    , pfilep -> name , nlp -> n_value
309844Speter 				    , classify( symbolp -> desc )
310831Speter 				    , symbolp -> name );
311831Speter 			}
312822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
313822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
314822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
315822Speter 			return;
316822Speter 		case N_PSO:
317822Speter 			pfilep = symbolp;
318822Speter 			/* and fall through */
319822Speter 		case N_PSOL:
320822Speter 			ifilep = symbolp;
321822Speter 			symbolp -> sym_un.modtime = mtime( symbolp -> name );
322822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
323822Speter 			    error( WARNING , "%s is out of date with %s"
324822Speter 				    , ofilep -> name , symbolp -> name );
325822Speter 			}
326822Speter 			return;
327822Speter 	    }
328822Speter 	} else {
329822Speter #	    ifdef DEBUG
330822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
331822Speter 			, symbolp -> name );
332822Speter #	    endif DEBUG
333844Speter 	    switch ( symbolp -> desc ) {
3347550Speter 		default:
3357550Speter 			error( FATAL , "panic [checksymbol] OLD" );
336822Speter 		case N_PSO:
337822Speter 			    /*
338822Speter 			     *	finding a file again means you are back
339822Speter 			     *	in it after finishing an include file.
340822Speter 			     */
341822Speter 			pfilep = symbolp;
342822Speter 			/* and fall through */
343822Speter 		case N_PSOL:
344822Speter 			    /*
345822Speter 			     *	include files can be seen more than once,
346822Speter 			     *	but they still have to be timechecked.
347822Speter 			     *	(this will complain twice for out of date
348822Speter 			     *	include files which include other files.
349822Speter 			     *	sigh.)
350822Speter 			     */
351822Speter 			ifilep = symbolp;
352822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
353822Speter 			    error( WARNING , "%s is out of date with %s"
354822Speter 				    , ofilep -> name , symbolp -> name );
355822Speter 			}
356822Speter 			return;
357844Speter 		case N_PEFUNC:
358844Speter 		case N_PEPROC:
359822Speter 			    /*
3607550Speter 			     *	this might be the resolution of the external
3617550Speter 			     *	has to match func/proc of external
3627550Speter 			     *	and has to have included external
3637550Speter 			     *	and has to not have been previously resolved.
364822Speter 			     */
3657550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
3667550Speter 			         && nlp -> n_desc == N_PGFUNC )
3677550Speter 			      || ( symbolp -> desc == N_PEPROC
3687550Speter 				 && nlp -> n_desc == N_PGPROC ) )
3697550Speter 			   && ( symbolp -> sym_un.sym_str.fromp == pfilep )
3707550Speter 			   && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
3717550Speter 				/*
3727550Speter 				 *	resolve external
3737550Speter 				 */
3747550Speter #			    ifdef DEBUG
3757550Speter 				fprintf( stderr , "[checksymbol] resolving external\n" );
3767550Speter #			    endif DEBUG
3777550Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
3787550Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
3797550Speter 			    return;
380822Speter 			}
381822Speter 			    /*
3827550Speter 			     *	otherwise, it might be another external,
3837550Speter 			     *	which is okay if it's
3847550Speter 			     *	the same type and from the same include file
385822Speter 			     */
3867550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
3877550Speter 			         && nlp -> n_desc == N_PEFUNC )
3887550Speter 			      || ( symbolp -> desc == N_PEPROC
3897550Speter 				 && nlp -> n_desc == N_PEPROC ) )
3907550Speter 			   && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
3917550Speter 				/*
3927550Speter 				 *	just another pretty external
3937550Speter 				 *	make it look like it comes from here.
3947550Speter 				 */
3957550Speter #			    ifdef DEBUG
3967550Speter 				fprintf( stderr , "[checksymbol] just another pretty external\n" );
3977550Speter #			    endif DEBUG
3987550Speter 			    symbolp -> sym_un.sym_str.fromp = pfilep;
3997550Speter 			    return;
400822Speter 			}
401822Speter 			    /*
4027550Speter 			     *	something is wrong
403*7598Speter 			     *	if it's not resolved, use the header file
404*7598Speter 			     *	otherwise, it's just a regular error
405822Speter 			     */
406*7598Speter 			if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
407*7598Speter 			    error( ERROR ,
4087550Speter 			    "%s, line %d: %s already defined (%s, line %d)." ,
409*7598Speter 				ifilep -> name , nlp -> n_value ,
410*7598Speter 				nlp -> n_un.n_name ,
411*7598Speter 				symbolp -> sym_un.sym_str.fromi -> name ,
412*7598Speter 				symbolp -> sym_un.sym_str.iline );
413*7598Speter 			    return;
414*7598Speter 			}
415*7598Speter 			break;
416844Speter 		case N_PGFUNC:
417844Speter 		case N_PGPROC:
418822Speter 			    /*
419822Speter 			     *	functions may not be seen more than once.
420822Speter 			     *	the loader will complain about
421822Speter 			     *	`multiply defined', but we can, too.
422822Speter 			     */
423822Speter 			break;
424844Speter 		case N_PGLABEL:
425844Speter 		case N_PGCONST:
426844Speter 		case N_PGTYPE:
427822Speter 		case N_PGVAR:
428822Speter 			    /*
429822Speter 			     *	labels, constants, types, variables
430822Speter 			     *	and external declarations
431822Speter 			     *	may be seen as many times as they want,
432822Speter 			     *	as long as they come from the same include file.
433822Speter 			     *	make it look like they come from this .p file.
434822Speter 			     */
435822Speter included:
436844Speter 			if (  nlp -> n_desc != symbolp -> desc
437822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
438822Speter 			    break;
439822Speter 			}
440822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
441822Speter 			return;
442822Speter 	    }
443822Speter 		/*
444822Speter 		 *	this is the breaks
445822Speter 		 */
446*7598Speter 	    error( ERROR , "%s, line %d: %s already defined (%s, line %d)."
447822Speter 		    , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
448822Speter 		    , symbolp -> sym_un.sym_str.rfilep -> name
449822Speter 		    , symbolp -> sym_un.sym_str.rline );
450822Speter 	}
451822Speter     }
452822Speter 
453822Speter     /*
454822Speter      *	quadratically hashed symbol table.
455822Speter      *	things are never deleted from the hash symbol table.
456822Speter      *	as more hash table is needed,
457822Speter      *	a new one is alloc'ed and chained to the end.
458822Speter      *	search is by rehashing within each table,
459822Speter      *	traversing chains to next table if unsuccessful.
460822Speter      */
461822Speter struct symbol *
462822Speter entersymbol( name )
463822Speter     char	*name;
464822Speter     {
465822Speter 	static struct symboltableinfo	*symboltable = NIL;
466822Speter 	char				*enteredname;
467822Speter 	long				hashindex;
468822Speter 	register struct symboltableinfo	*tablep;
469822Speter 	register struct symbol		**herep;
470822Speter 	register struct symbol		**limitp;
471822Speter 	register long			increment;
472822Speter 
473822Speter 	enteredname = enterstring( name );
474822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
475822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
476822Speter 	    if ( tablep == NIL ) {
477822Speter #		ifdef DEBUG
478822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
479822Speter #		endif DEBUG
480822Speter 		tablep = ( struct symboltableinfo * )
481822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
482822Speter 		if ( tablep == NIL ) {
483822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
484822Speter 		}
485822Speter 		if ( symboltable == NIL ) {
486822Speter 		    symboltable = tablep;
487822Speter 		}
488822Speter 	    }
489822Speter 	    herep = &( tablep -> entry[ hashindex ] );
490822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
491822Speter 	    increment = 1;
492822Speter 	    do {
493822Speter #		ifdef DEBUG
494822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
495822Speter 			    , increment );
496822Speter #		endif DEBUG
497822Speter 		if ( *herep == NIL ) {
498822Speter 			/* empty */
499822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
500822Speter 			    /* too full, break for next table */
501822Speter 			break;
502822Speter 		    }
503822Speter 		    tablep -> used++;
504822Speter 		    *herep = symbolalloc();
505822Speter 		    ( *herep ) -> name = enteredname;
506822Speter 		    ( *herep ) -> lookup = NEW;
507822Speter #		    ifdef DEBUG
508822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
509822Speter 				, enteredname );
510822Speter #		    endif DEBUG
511822Speter 		    return *herep;
512822Speter 		}
513822Speter 		    /* a find? */
514822Speter 		if ( ( *herep ) -> name == enteredname ) {
515822Speter 		    ( *herep ) -> lookup = OLD;
516822Speter #		    ifdef DEBUG
517822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
518822Speter 				, enteredname );
519822Speter #		    endif DEBUG
520822Speter 		    return *herep;
521822Speter 		}
522822Speter 		herep += increment;
523822Speter 		if ( herep >= limitp ) {
524822Speter 		    herep -= SYMBOLPRIME;
525822Speter 		}
526822Speter 		increment += 2;
527822Speter 	    } while ( increment < SYMBOLPRIME );
528822Speter 	}
529822Speter     }
530822Speter 
531822Speter     /*
532822Speter      *	allocate a symbol from the dynamically allocated symbol table.
533822Speter      */
534822Speter struct symbol *
535822Speter symbolalloc()
536822Speter     {
537822Speter 	static struct symbol	*nextsymbol = NIL;
538822Speter 	static long		symbolsleft = 0;
539822Speter 	struct symbol		*newsymbol;
540822Speter 
541822Speter 	if ( symbolsleft <= 0 ) {
542822Speter #	    ifdef DEBUG
543822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
544822Speter #	    endif DEBUG
545822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
546822Speter 	    if ( nextsymbol == 0 ) {
547822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
548822Speter 	    }
549822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
550822Speter 	}
551822Speter 	newsymbol = nextsymbol;
552822Speter 	nextsymbol++;
553822Speter 	symbolsleft--;
554822Speter 	return newsymbol;
555822Speter     }
556822Speter 
557822Speter     /*
558822Speter      *	hash a string based on all of its characters.
559822Speter      */
560822Speter long
561822Speter hashstring( string )
562822Speter     char	*string;
563822Speter     {
564822Speter 	register char	*cp;
565822Speter 	register long	value;
566822Speter 
567822Speter 	value = 0;
568822Speter 	for ( cp = string ; *cp ; cp++ ) {
569822Speter 	    value = ( value * 2 ) + *cp;
570822Speter 	}
571822Speter 	return value;
572822Speter     }
573822Speter 
574822Speter     /*
575822Speter      *	quadratically hashed string table.
576822Speter      *	things are never deleted from the hash string table.
577822Speter      *	as more hash table is needed,
578822Speter      *	a new one is alloc'ed and chained to the end.
579822Speter      *	search is by rehashing within each table,
580822Speter      *	traversing chains to next table if unsuccessful.
581822Speter      */
582822Speter char *
583822Speter enterstring( string )
584822Speter     char	*string;
585822Speter     {
586822Speter 	static struct stringtableinfo	*stringtable = NIL;
587822Speter 	long				hashindex;
588822Speter 	register struct stringtableinfo	*tablep;
589822Speter 	register char			**herep;
590822Speter 	register char			**limitp;
591822Speter 	register long			increment;
592822Speter 
593822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
594822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
595822Speter 	    if ( tablep == NIL ) {
596822Speter #		ifdef DEBUG
597822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
598822Speter #		endif DEBUG
599822Speter 		tablep = ( struct stringtableinfo * )
600822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
601822Speter 		if ( tablep == NIL ) {
602822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
603822Speter 		}
604822Speter 		if ( stringtable == NIL ) {
605822Speter 		    stringtable = tablep;
606822Speter 		}
607822Speter 	    }
608822Speter 	    herep = &( tablep -> entry[ hashindex ] );
609822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
610822Speter 	    increment = 1;
611822Speter 	    do {
612822Speter #		ifdef DEBUG
613822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
614822Speter 			    , increment );
615822Speter #		endif DEBUG
616822Speter 		if ( *herep == NIL ) {
617822Speter 			/* empty */
618822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
619822Speter 			    /* too full, break for next table */
620822Speter 			break;
621822Speter 		    }
622822Speter 		    tablep -> used++;
623822Speter 		    *herep = charalloc( strlen( string ) );
624822Speter 		    strcpy( *herep , string );
625822Speter #		    ifdef DEBUG
626822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
627822Speter 				, *herep );
628822Speter #		    endif DEBUG
629822Speter 		    return *herep;
630822Speter 		}
631822Speter 		    /* quick, check the first chars and then the rest */
632822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
633822Speter #		    ifdef DEBUG
634822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
635822Speter 				, *herep );
636822Speter #		    endif DEBUG
637822Speter 		    return *herep;
638822Speter 		}
639822Speter 		herep += increment;
640822Speter 		if ( herep >= limitp ) {
641822Speter 		    herep -= STRINGPRIME;
642822Speter 		}
643822Speter 		increment += 2;
644822Speter 	    } while ( increment < STRINGPRIME );
645822Speter 	}
646822Speter     }
647822Speter 
648822Speter     /*
649822Speter      *	copy a string to the dynamically allocated character table.
650822Speter      */
651822Speter char *
652822Speter charalloc( length )
653822Speter     register long	length;
654822Speter     {
655822Speter 	static char	*nextchar = NIL;
656822Speter 	static long	charsleft = 0;
657822Speter 	register long	lengthplus1 = length + 1;
658822Speter 	register long	askfor;
659822Speter 	char		*newstring;
660822Speter 
661822Speter 	if ( charsleft < lengthplus1 ) {
662822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
663822Speter #	    ifdef DEBUG
664822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
665822Speter 			, askfor );
666822Speter #	    endif DEBUG
667822Speter 	    nextchar = ( char * ) malloc( askfor );
668822Speter 	    if ( nextchar == 0 ) {
669822Speter 		error( FATAL , "no room for %d characters" , askfor );
670822Speter 	    }
671822Speter 	    charsleft = askfor;
672822Speter 	}
673822Speter 	newstring = nextchar;
674822Speter 	nextchar += lengthplus1;
675822Speter 	charsleft -= lengthplus1;
676822Speter 	return newstring;
677822Speter     }
678822Speter 
679822Speter     /*
680822Speter      *	read an archive header for the next element
681822Speter      *	and find the offset of the one after this.
682822Speter      */
683822Speter BOOL
684822Speter nextelement( ofilep )
685822Speter     struct fileinfo	*ofilep;
686822Speter     {
687822Speter 	register char	*cp;
688822Speter 	register long	red;
689822Speter 	register off_t	arsize;
690822Speter 	struct ar_hdr	archdr;
691822Speter 
692822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
693822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
694822Speter 	if ( red != sizeof archdr ) {
695822Speter 	    return FALSE;
696822Speter 	}
697822Speter 	    /* null terminate the blank-padded name */
698822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
699822Speter 	*cp = '\0';
700822Speter 	while ( *--cp == ' ' ) {
701822Speter 	    *cp = '\0';
702822Speter 	}
703822Speter 	    /* set up the address of the beginning of next element */
704822Speter 	arsize = atol( archdr.ar_size );
705822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
706822Speter 	if ( arsize & 1 ) {
707822Speter 	    arsize += 1;
708822Speter 	}
709822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
710822Speter 	    /* say we had one */
711822Speter 	return TRUE;
712822Speter     }
713822Speter 
714822Speter     /*
715822Speter      *	variable number of arguments to error, like printf.
716822Speter      */
717*7598Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
718*7598Speter     int		type;
719822Speter     char	*message;
720822Speter     {
721*7598Speter 	errors = type > errors ? type : errors;
722*7598Speter 	if ( wflag && type == WARNING ) {
723*7598Speter 	    return;
724*7598Speter 	}
725822Speter 	fprintf( stderr , "%s: " , program );
726*7598Speter 	switch ( type ) {
727*7598Speter 	    case WARNING:
728*7598Speter 		    fprintf( stderr , "Warning: " );
729*7598Speter 		    break;
730*7598Speter 	    case ERROR:
731*7598Speter 		    fprintf( stderr , "Error: " );
732*7598Speter 		    break;
733*7598Speter 	    case FATAL:
734*7598Speter 		    fprintf( stderr , "Fatal: " );
735*7598Speter 		    break;
736*7598Speter 	    default:
737*7598Speter 		    fprintf( stderr , "Ooops: " );
738*7598Speter 		    break;
739*7598Speter 	}
740*7598Speter 	fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6 );
741822Speter 	fprintf( stderr , "\n" );
742*7598Speter 	if ( type == FATAL ) {
743*7598Speter 	    exit( FATAL );
744822Speter 	}
745822Speter     }
746822Speter 
747822Speter     /*
748822Speter      *	find the last modify time of a file.
749822Speter      *	on error, return the current time.
750822Speter      */
751822Speter time_t
752822Speter mtime( filename )
753822Speter     char	*filename;
754822Speter     {
755822Speter 	struct stat	filestat;
756822Speter 
757822Speter #	ifdef DEBUG
758822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
759822Speter 		    , filename );
760822Speter #	endif DEBUG
761829Speter 	if ( stat( filename , &filestat ) != 0 ) {
762*7598Speter 	    error( WARNING , "%s: cannot stat" , filename );
763822Speter 	    return ( (time_t) time( 0 ) );
764822Speter 	}
765822Speter 	return filestat.st_mtime;
766822Speter     }
767822Speter 
768822Speter char *
769822Speter classify( type )
770822Speter     unsigned char	type;
771822Speter     {
772822Speter 	switch ( type ) {
773822Speter 	    case N_PSO:
774822Speter 		return "source file";
775822Speter 	    case N_PSOL:
776822Speter 		return "include file";
777844Speter 	    case N_PGLABEL:
778822Speter 		return "label";
779844Speter 	    case N_PGCONST:
780822Speter 		return "constant";
781844Speter 	    case N_PGTYPE:
782822Speter 		return "type";
783822Speter 	    case N_PGVAR:
784822Speter 		return "variable";
785844Speter 	    case N_PGFUNC:
786822Speter 		return "function";
787844Speter 	    case N_PGPROC:
788822Speter 		return "procedure";
789844Speter 	    case N_PEFUNC:
790822Speter 		return "external function";
791844Speter 	    case N_PEPROC:
792822Speter 		return "external procedure";
793822Speter 	    default:
794822Speter 		return "unknown symbol";
795822Speter 	}
796822Speter     }
797