xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 7601)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*7601Speter static	char sccsid[] = "@(#)pc3.c 1.9 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 
777598Speter int	errors = NONE;
787598Speter 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 
897598Speter 	for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) {
907598Speter 	    (*argv)++;
917598Speter 	    switch ( **argv ) {
927598Speter 		default:
937598Speter 		    error( FATAL , "pc3: bad flag -%c\n" , **argv );
947598Speter 		case 'w':
957598Speter 		    wflag = TRUE;
967598Speter 		    break;
977598Speter 	    }
987598Speter 	}
997598Speter 	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 ) {
1247598Speter 	    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 ) {
1317598Speter 	    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 */
1497598Speter 	    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 ) {
1827598Speter 	    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;
261*7601Speter 	int			errtype;
262822Speter 
263822Speter #	ifdef DEBUG
264822Speter 	    if ( pfilep && ifilep ) {
265822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
266822Speter 			, pfilep -> name , ifilep -> name );
267822Speter 	    }
268844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
269844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
270844Speter 		    , classify( nlp -> n_desc ) );
271822Speter #	endif DEBUG
272844Speter 	if ( nlp -> n_type != N_PC ) {
273844Speter 		/* don't care about the others */
274844Speter 	    return;
275822Speter 	}
276844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
277822Speter 	if ( symbolp -> lookup == NEW ) {
278822Speter #	    ifdef DEBUG
279822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
280822Speter 			, symbolp -> name );
281822Speter #	    endif DEBUG
282844Speter 	    symbolp -> desc = nlp -> n_desc;
283844Speter 	    switch ( symbolp -> desc ) {
2847550Speter 		default:
2857550Speter 			error( FATAL , "panic: [checksymbol] NEW" );
286844Speter 		case N_PGLABEL:
287844Speter 		case N_PGCONST:
288844Speter 		case N_PGTYPE:
289822Speter 		case N_PGVAR:
290844Speter 		case N_PGFUNC:
291844Speter 		case N_PGPROC:
292*7601Speter 		case N_PLDATA:
293*7601Speter 		case N_PLTEXT:
294831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
295831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
296831Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
297831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
298831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
299831Speter 			return;
300844Speter 		case N_PEFUNC:
301844Speter 		case N_PEPROC:
302831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
303831Speter 			symbolp -> sym_un.sym_str.rline = 0;
304831Speter 			    /*
305831Speter 			     *	functions can only be declared external
306831Speter 			     *	in included files.
307831Speter 			     */
308831Speter 			if ( pfilep == ifilep ) {
309831Speter 			    error( WARNING
310831Speter 				    , "%s, line %d: %s %s must be declared in included file"
311831Speter 				    , pfilep -> name , nlp -> n_value
312844Speter 				    , classify( symbolp -> desc )
313831Speter 				    , symbolp -> name );
314831Speter 			}
315822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
316822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
317822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
318822Speter 			return;
319822Speter 		case N_PSO:
320822Speter 			pfilep = symbolp;
321822Speter 			/* and fall through */
322822Speter 		case N_PSOL:
323822Speter 			ifilep = symbolp;
324822Speter 			symbolp -> sym_un.modtime = mtime( symbolp -> name );
325822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
326822Speter 			    error( WARNING , "%s is out of date with %s"
327822Speter 				    , ofilep -> name , symbolp -> name );
328822Speter 			}
329822Speter 			return;
330822Speter 	    }
331822Speter 	} else {
332822Speter #	    ifdef DEBUG
333822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
334822Speter 			, symbolp -> name );
335822Speter #	    endif DEBUG
336*7601Speter 	    errtype = ERROR;
337844Speter 	    switch ( symbolp -> desc ) {
3387550Speter 		default:
3397550Speter 			error( FATAL , "panic [checksymbol] OLD" );
340822Speter 		case N_PSO:
341822Speter 			    /*
342822Speter 			     *	finding a file again means you are back
343822Speter 			     *	in it after finishing an include file.
344822Speter 			     */
345822Speter 			pfilep = symbolp;
346822Speter 			/* and fall through */
347822Speter 		case N_PSOL:
348822Speter 			    /*
349822Speter 			     *	include files can be seen more than once,
350822Speter 			     *	but they still have to be timechecked.
351822Speter 			     *	(this will complain twice for out of date
352822Speter 			     *	include files which include other files.
353822Speter 			     *	sigh.)
354822Speter 			     */
355822Speter 			ifilep = symbolp;
356822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
357822Speter 			    error( WARNING , "%s is out of date with %s"
358822Speter 				    , ofilep -> name , symbolp -> name );
359822Speter 			}
360822Speter 			return;
361844Speter 		case N_PEFUNC:
362844Speter 		case N_PEPROC:
363822Speter 			    /*
3647550Speter 			     *	this might be the resolution of the external
3657550Speter 			     *	has to match func/proc of external
3667550Speter 			     *	and has to have included external
3677550Speter 			     *	and has to not have been previously resolved.
368822Speter 			     */
3697550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
3707550Speter 			         && nlp -> n_desc == N_PGFUNC )
3717550Speter 			      || ( symbolp -> desc == N_PEPROC
3727550Speter 				 && nlp -> n_desc == N_PGPROC ) )
3737550Speter 			   && ( symbolp -> sym_un.sym_str.fromp == pfilep )
3747550Speter 			   && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
3757550Speter 				/*
3767550Speter 				 *	resolve external
3777550Speter 				 */
3787550Speter #			    ifdef DEBUG
3797550Speter 				fprintf( stderr , "[checksymbol] resolving external\n" );
3807550Speter #			    endif DEBUG
3817550Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
3827550Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
3837550Speter 			    return;
384822Speter 			}
385822Speter 			    /*
3867550Speter 			     *	otherwise, it might be another external,
3877550Speter 			     *	which is okay if it's
3887550Speter 			     *	the same type and from the same include file
389822Speter 			     */
3907550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
3917550Speter 			         && nlp -> n_desc == N_PEFUNC )
3927550Speter 			      || ( symbolp -> desc == N_PEPROC
3937550Speter 				 && nlp -> n_desc == N_PEPROC ) )
3947550Speter 			   && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
3957550Speter 				/*
3967550Speter 				 *	just another pretty external
3977550Speter 				 *	make it look like it comes from here.
3987550Speter 				 */
3997550Speter #			    ifdef DEBUG
4007550Speter 				fprintf( stderr , "[checksymbol] just another pretty external\n" );
4017550Speter #			    endif DEBUG
4027550Speter 			    symbolp -> sym_un.sym_str.fromp = pfilep;
4037550Speter 			    return;
404822Speter 			}
405822Speter 			    /*
4067550Speter 			     *	something is wrong
4077598Speter 			     *	if it's not resolved, use the header file
4087598Speter 			     *	otherwise, it's just a regular error
409822Speter 			     */
4107598Speter 			if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
4117598Speter 			    error( ERROR ,
412*7601Speter 		    "%s, line %d: %s is already defined\n\t(%s, line %d)." ,
4137598Speter 				ifilep -> name , nlp -> n_value ,
4147598Speter 				nlp -> n_un.n_name ,
4157598Speter 				symbolp -> sym_un.sym_str.fromi -> name ,
4167598Speter 				symbolp -> sym_un.sym_str.iline );
4177598Speter 			    return;
4187598Speter 			}
4197598Speter 			break;
420844Speter 		case N_PGFUNC:
421844Speter 		case N_PGPROC:
422822Speter 			    /*
423822Speter 			     *	functions may not be seen more than once.
424822Speter 			     *	the loader will complain about
425822Speter 			     *	`multiply defined', but we can, too.
426822Speter 			     */
427822Speter 			break;
428844Speter 		case N_PGLABEL:
429844Speter 		case N_PGCONST:
430844Speter 		case N_PGTYPE:
431822Speter 		case N_PGVAR:
432822Speter 			    /*
433822Speter 			     *	labels, constants, types, variables
434822Speter 			     *	and external declarations
435822Speter 			     *	may be seen as many times as they want,
436822Speter 			     *	as long as they come from the same include file.
437822Speter 			     *	make it look like they come from this .p file.
438822Speter 			     */
439822Speter included:
440844Speter 			if (  nlp -> n_desc != symbolp -> desc
441822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
442822Speter 			    break;
443822Speter 			}
444822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
445822Speter 			return;
446*7601Speter 		case N_PLDATA:
447*7601Speter 		case N_PLTEXT:
448*7601Speter 			switch ( nlp -> n_desc ) {
449*7601Speter 			    default:
450*7601Speter 				error( FATAL , "pc3: unknown stab 0x%x"
451*7601Speter 					, nlp -> n_desc );
452*7601Speter 				return;
453*7601Speter 			    case N_PSO:
454*7601Speter 			    case N_PSOL:
455*7601Speter 			    case N_PGCONST:
456*7601Speter 			    case N_PGTYPE:
457*7601Speter 				/* these won't conflict with library */
458*7601Speter 				return;
459*7601Speter 			    case N_PGLABEL:
460*7601Speter 			    case N_PGVAR:
461*7601Speter 			    case N_PGFUNC:
462*7601Speter 			    case N_PGPROC:
463*7601Speter 			    case N_PEFUNC:
464*7601Speter 			    case N_PEPROC:
465*7601Speter 			    case N_PLDATA:
466*7601Speter 			    case N_PLTEXT:
467*7601Speter 				errtype = WARNING;
468*7601Speter 				break;
469*7601Speter 			}
470*7601Speter 			break;
471822Speter 	    }
472822Speter 		/*
473822Speter 		 *	this is the breaks
474822Speter 		 */
475*7601Speter 	    error( errtype
476*7601Speter 		, "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)."
477*7601Speter 		, ifilep -> name
478*7601Speter 		, nlp -> n_value
479*7601Speter 		, classify( nlp -> n_desc )
480*7601Speter 		, nlp -> n_un.n_name
481*7601Speter 		, ( symbolp -> desc == nlp -> n_desc ? "" : " as " )
482*7601Speter 		, ( symbolp -> desc == nlp -> n_desc
483*7601Speter 			? "" : article( symbolp -> desc ) )
484*7601Speter 		, symbolp -> sym_un.sym_str.rfilep -> name
485*7601Speter 		, symbolp -> sym_un.sym_str.rline );
486822Speter 	}
487822Speter     }
488822Speter 
489822Speter     /*
490822Speter      *	quadratically hashed symbol table.
491822Speter      *	things are never deleted from the hash symbol table.
492822Speter      *	as more hash table is needed,
493822Speter      *	a new one is alloc'ed and chained to the end.
494822Speter      *	search is by rehashing within each table,
495822Speter      *	traversing chains to next table if unsuccessful.
496822Speter      */
497822Speter struct symbol *
498822Speter entersymbol( name )
499822Speter     char	*name;
500822Speter     {
501822Speter 	static struct symboltableinfo	*symboltable = NIL;
502822Speter 	char				*enteredname;
503822Speter 	long				hashindex;
504822Speter 	register struct symboltableinfo	*tablep;
505822Speter 	register struct symbol		**herep;
506822Speter 	register struct symbol		**limitp;
507822Speter 	register long			increment;
508822Speter 
509822Speter 	enteredname = enterstring( name );
510822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
511822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
512822Speter 	    if ( tablep == NIL ) {
513822Speter #		ifdef DEBUG
514822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
515822Speter #		endif DEBUG
516822Speter 		tablep = ( struct symboltableinfo * )
517822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
518822Speter 		if ( tablep == NIL ) {
519822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
520822Speter 		}
521822Speter 		if ( symboltable == NIL ) {
522822Speter 		    symboltable = tablep;
523822Speter 		}
524822Speter 	    }
525822Speter 	    herep = &( tablep -> entry[ hashindex ] );
526822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
527822Speter 	    increment = 1;
528822Speter 	    do {
529822Speter #		ifdef DEBUG
530822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
531822Speter 			    , increment );
532822Speter #		endif DEBUG
533822Speter 		if ( *herep == NIL ) {
534822Speter 			/* empty */
535822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
536822Speter 			    /* too full, break for next table */
537822Speter 			break;
538822Speter 		    }
539822Speter 		    tablep -> used++;
540822Speter 		    *herep = symbolalloc();
541822Speter 		    ( *herep ) -> name = enteredname;
542822Speter 		    ( *herep ) -> lookup = NEW;
543822Speter #		    ifdef DEBUG
544822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
545822Speter 				, enteredname );
546822Speter #		    endif DEBUG
547822Speter 		    return *herep;
548822Speter 		}
549822Speter 		    /* a find? */
550822Speter 		if ( ( *herep ) -> name == enteredname ) {
551822Speter 		    ( *herep ) -> lookup = OLD;
552822Speter #		    ifdef DEBUG
553822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
554822Speter 				, enteredname );
555822Speter #		    endif DEBUG
556822Speter 		    return *herep;
557822Speter 		}
558822Speter 		herep += increment;
559822Speter 		if ( herep >= limitp ) {
560822Speter 		    herep -= SYMBOLPRIME;
561822Speter 		}
562822Speter 		increment += 2;
563822Speter 	    } while ( increment < SYMBOLPRIME );
564822Speter 	}
565822Speter     }
566822Speter 
567822Speter     /*
568822Speter      *	allocate a symbol from the dynamically allocated symbol table.
569822Speter      */
570822Speter struct symbol *
571822Speter symbolalloc()
572822Speter     {
573822Speter 	static struct symbol	*nextsymbol = NIL;
574822Speter 	static long		symbolsleft = 0;
575822Speter 	struct symbol		*newsymbol;
576822Speter 
577822Speter 	if ( symbolsleft <= 0 ) {
578822Speter #	    ifdef DEBUG
579822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
580822Speter #	    endif DEBUG
581822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
582822Speter 	    if ( nextsymbol == 0 ) {
583822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
584822Speter 	    }
585822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
586822Speter 	}
587822Speter 	newsymbol = nextsymbol;
588822Speter 	nextsymbol++;
589822Speter 	symbolsleft--;
590822Speter 	return newsymbol;
591822Speter     }
592822Speter 
593822Speter     /*
594822Speter      *	hash a string based on all of its characters.
595822Speter      */
596822Speter long
597822Speter hashstring( string )
598822Speter     char	*string;
599822Speter     {
600822Speter 	register char	*cp;
601822Speter 	register long	value;
602822Speter 
603822Speter 	value = 0;
604822Speter 	for ( cp = string ; *cp ; cp++ ) {
605822Speter 	    value = ( value * 2 ) + *cp;
606822Speter 	}
607822Speter 	return value;
608822Speter     }
609822Speter 
610822Speter     /*
611822Speter      *	quadratically hashed string table.
612822Speter      *	things are never deleted from the hash string table.
613822Speter      *	as more hash table is needed,
614822Speter      *	a new one is alloc'ed and chained to the end.
615822Speter      *	search is by rehashing within each table,
616822Speter      *	traversing chains to next table if unsuccessful.
617822Speter      */
618822Speter char *
619822Speter enterstring( string )
620822Speter     char	*string;
621822Speter     {
622822Speter 	static struct stringtableinfo	*stringtable = NIL;
623822Speter 	long				hashindex;
624822Speter 	register struct stringtableinfo	*tablep;
625822Speter 	register char			**herep;
626822Speter 	register char			**limitp;
627822Speter 	register long			increment;
628822Speter 
629822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
630822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
631822Speter 	    if ( tablep == NIL ) {
632822Speter #		ifdef DEBUG
633822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
634822Speter #		endif DEBUG
635822Speter 		tablep = ( struct stringtableinfo * )
636822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
637822Speter 		if ( tablep == NIL ) {
638822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
639822Speter 		}
640822Speter 		if ( stringtable == NIL ) {
641822Speter 		    stringtable = tablep;
642822Speter 		}
643822Speter 	    }
644822Speter 	    herep = &( tablep -> entry[ hashindex ] );
645822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
646822Speter 	    increment = 1;
647822Speter 	    do {
648822Speter #		ifdef DEBUG
649822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
650822Speter 			    , increment );
651822Speter #		endif DEBUG
652822Speter 		if ( *herep == NIL ) {
653822Speter 			/* empty */
654822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
655822Speter 			    /* too full, break for next table */
656822Speter 			break;
657822Speter 		    }
658822Speter 		    tablep -> used++;
659822Speter 		    *herep = charalloc( strlen( string ) );
660822Speter 		    strcpy( *herep , string );
661822Speter #		    ifdef DEBUG
662822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
663822Speter 				, *herep );
664822Speter #		    endif DEBUG
665822Speter 		    return *herep;
666822Speter 		}
667822Speter 		    /* quick, check the first chars and then the rest */
668822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
669822Speter #		    ifdef DEBUG
670822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
671822Speter 				, *herep );
672822Speter #		    endif DEBUG
673822Speter 		    return *herep;
674822Speter 		}
675822Speter 		herep += increment;
676822Speter 		if ( herep >= limitp ) {
677822Speter 		    herep -= STRINGPRIME;
678822Speter 		}
679822Speter 		increment += 2;
680822Speter 	    } while ( increment < STRINGPRIME );
681822Speter 	}
682822Speter     }
683822Speter 
684822Speter     /*
685822Speter      *	copy a string to the dynamically allocated character table.
686822Speter      */
687822Speter char *
688822Speter charalloc( length )
689822Speter     register long	length;
690822Speter     {
691822Speter 	static char	*nextchar = NIL;
692822Speter 	static long	charsleft = 0;
693822Speter 	register long	lengthplus1 = length + 1;
694822Speter 	register long	askfor;
695822Speter 	char		*newstring;
696822Speter 
697822Speter 	if ( charsleft < lengthplus1 ) {
698822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
699822Speter #	    ifdef DEBUG
700822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
701822Speter 			, askfor );
702822Speter #	    endif DEBUG
703822Speter 	    nextchar = ( char * ) malloc( askfor );
704822Speter 	    if ( nextchar == 0 ) {
705822Speter 		error( FATAL , "no room for %d characters" , askfor );
706822Speter 	    }
707822Speter 	    charsleft = askfor;
708822Speter 	}
709822Speter 	newstring = nextchar;
710822Speter 	nextchar += lengthplus1;
711822Speter 	charsleft -= lengthplus1;
712822Speter 	return newstring;
713822Speter     }
714822Speter 
715822Speter     /*
716822Speter      *	read an archive header for the next element
717822Speter      *	and find the offset of the one after this.
718822Speter      */
719822Speter BOOL
720822Speter nextelement( ofilep )
721822Speter     struct fileinfo	*ofilep;
722822Speter     {
723822Speter 	register char	*cp;
724822Speter 	register long	red;
725822Speter 	register off_t	arsize;
726822Speter 	struct ar_hdr	archdr;
727822Speter 
728822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
729822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
730822Speter 	if ( red != sizeof archdr ) {
731822Speter 	    return FALSE;
732822Speter 	}
733822Speter 	    /* null terminate the blank-padded name */
734822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
735822Speter 	*cp = '\0';
736822Speter 	while ( *--cp == ' ' ) {
737822Speter 	    *cp = '\0';
738822Speter 	}
739822Speter 	    /* set up the address of the beginning of next element */
740822Speter 	arsize = atol( archdr.ar_size );
741822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
742822Speter 	if ( arsize & 1 ) {
743822Speter 	    arsize += 1;
744822Speter 	}
745822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
746822Speter 	    /* say we had one */
747822Speter 	return TRUE;
748822Speter     }
749822Speter 
750822Speter     /*
751822Speter      *	variable number of arguments to error, like printf.
752822Speter      */
753*7601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 )
7547598Speter     int		type;
755822Speter     char	*message;
756822Speter     {
7577598Speter 	errors = type > errors ? type : errors;
7587598Speter 	if ( wflag && type == WARNING ) {
7597598Speter 	    return;
7607598Speter 	}
761822Speter 	fprintf( stderr , "%s: " , program );
7627598Speter 	switch ( type ) {
7637598Speter 	    case WARNING:
7647598Speter 		    fprintf( stderr , "Warning: " );
7657598Speter 		    break;
7667598Speter 	    case ERROR:
7677598Speter 		    fprintf( stderr , "Error: " );
7687598Speter 		    break;
7697598Speter 	    case FATAL:
7707598Speter 		    fprintf( stderr , "Fatal: " );
7717598Speter 		    break;
7727598Speter 	    default:
7737598Speter 		    fprintf( stderr , "Ooops: " );
7747598Speter 		    break;
7757598Speter 	}
776*7601Speter 	fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 );
777822Speter 	fprintf( stderr , "\n" );
7787598Speter 	if ( type == FATAL ) {
7797598Speter 	    exit( FATAL );
780822Speter 	}
781822Speter     }
782822Speter 
783822Speter     /*
784822Speter      *	find the last modify time of a file.
785822Speter      *	on error, return the current time.
786822Speter      */
787822Speter time_t
788822Speter mtime( filename )
789822Speter     char	*filename;
790822Speter     {
791822Speter 	struct stat	filestat;
792822Speter 
793822Speter #	ifdef DEBUG
794822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
795822Speter 		    , filename );
796822Speter #	endif DEBUG
797829Speter 	if ( stat( filename , &filestat ) != 0 ) {
7987598Speter 	    error( WARNING , "%s: cannot stat" , filename );
799822Speter 	    return ( (time_t) time( 0 ) );
800822Speter 	}
801822Speter 	return filestat.st_mtime;
802822Speter     }
803822Speter 
804822Speter char *
805822Speter classify( type )
806822Speter     unsigned char	type;
807822Speter     {
808822Speter 	switch ( type ) {
809822Speter 	    case N_PSO:
810822Speter 		return "source file";
811822Speter 	    case N_PSOL:
812822Speter 		return "include file";
813844Speter 	    case N_PGLABEL:
814822Speter 		return "label";
815844Speter 	    case N_PGCONST:
816822Speter 		return "constant";
817844Speter 	    case N_PGTYPE:
818822Speter 		return "type";
819822Speter 	    case N_PGVAR:
820822Speter 		return "variable";
821844Speter 	    case N_PGFUNC:
822822Speter 		return "function";
823844Speter 	    case N_PGPROC:
824822Speter 		return "procedure";
825844Speter 	    case N_PEFUNC:
826822Speter 		return "external function";
827844Speter 	    case N_PEPROC:
828822Speter 		return "external procedure";
829*7601Speter 	    case N_PLDATA:
830*7601Speter 		return "library variable";
831*7601Speter 	    case N_PLTEXT:
832*7601Speter 		return "library routine";
833822Speter 	    default:
834822Speter 		return "unknown symbol";
835822Speter 	}
836822Speter     }
837*7601Speter 
838*7601Speter char *
839*7601Speter article( type )
840*7601Speter     unsigned char	type;
841*7601Speter     {
842*7601Speter 	switch ( type ) {
843*7601Speter 	    case N_PSO:
844*7601Speter 		return "a source file";
845*7601Speter 	    case N_PSOL:
846*7601Speter 		return "an include file";
847*7601Speter 	    case N_PGLABEL:
848*7601Speter 		return "a label";
849*7601Speter 	    case N_PGCONST:
850*7601Speter 		return "a constant";
851*7601Speter 	    case N_PGTYPE:
852*7601Speter 		return "a type";
853*7601Speter 	    case N_PGVAR:
854*7601Speter 		return "a variable";
855*7601Speter 	    case N_PGFUNC:
856*7601Speter 		return "a function";
857*7601Speter 	    case N_PGPROC:
858*7601Speter 		return "a procedure";
859*7601Speter 	    case N_PEFUNC:
860*7601Speter 		return "an external function";
861*7601Speter 	    case N_PEPROC:
862*7601Speter 		return "an external procedure";
863*7601Speter 	    case N_PLDATA:
864*7601Speter 		return "a library variable";
865*7601Speter 	    case N_PLTEXT:
866*7601Speter 		return "a library routine";
867*7601Speter 	    default:
868*7601Speter 		return "an unknown symbol";
869*7601Speter 	}
870*7601Speter     }
871