xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 14129)
113617Ssam #ifndef lint
2*14129Speter static	char sccsid[] = "@(#)pc3.c	1.13 (Berkeley) 07/26/83";
313617Ssam #endif
4822Speter     /* Copyright (c) 1980 Regents of the University of California */
5822Speter 
6822Speter     /*
7822Speter      *	     Pc3 is a pass in the Berkeley Pascal compilation
8822Speter      *	process that is performed just prior to linking Pascal
9822Speter      *	object files.  Its purpose is to enforce the rules of
10822Speter      *	separate compilation for Berkeley Pascal.  Pc3 is called
11822Speter      *	with the same argument list of object files that is sent to
12822Speter      *	the loader.  These checks are performed by pc3 by examining
13822Speter      *	the symbol tables of the object files:
14*14129Speter      *	(1)  All .o files must be up to date with respect to the
15*14129Speter      *	     runtime libraries.
16822Speter      *	(2)  Each global Pascal symbol (label, constant, type,
17822Speter      *	     variable, procedure, or function name) must be uniquely
18822Speter      *	     declared, i.e. declared in only one included file or
19822Speter      *	     source file.
20822Speter      *	(3)  Each external function (or procedure) may be resolved
21822Speter      *	     at most once in a source file which included the
22822Speter      *	     external declaration of the function.
23822Speter      *
24822Speter      *	     The symbol table of each object file is scanned and
25822Speter      *	each global Pascal symbol is placed in a hashed symbol
26822Speter      *	table.  The Pascal compiler has been modified to emit all
27822Speter      *	Pascal global symbols to the object file symbol table.  The
28822Speter      *	information stored in the symbol table for each such symbol
29822Speter      *	is:
30822Speter      *
31822Speter      *	   - the name of the symbol;
32844Speter      *	   - a subtype descriptor;
33822Speter      *	   - the file which logically contains the declaration of
34*14129Speter      *	     the symbol or which caused the inclusion of an include file.
35*14129Speter      *	   - for included files:
36*14129Speter      *		- a checksum;
37*14129Speter      *	   - for symbols:
38*14129Speter      *	   	- the file which textually contains the declaration of
39*14129Speter      *	   	  the symbol (possibly an include file);
40*14129Speter      *	   	- the line number at which the symbol is declared;
41*14129Speter      *	   	- the file which contains the resolution of the symbol.
42*14129Speter      *	   	- the line number at which the symbol is resolved;
43822Speter      *
44822Speter      *	     If a symbol has been previously entered into the symbol
45822Speter      *	table, a check is made that the current declaration is of
46822Speter      *	the same type and from the same include file as the previous
47822Speter      *	one.  Except for files and functions and procedures, it is
48822Speter      *	an error for a symbol declaration to be encountered more
49822Speter      *	than once, unless the re-declarations come from the same
50822Speter      *	included file as the original.
51822Speter      *
52822Speter      *	     As an include file symbol is encountered in a source
53822Speter      *	file, the symbol table entry of each symbol declared in that
54822Speter      *	include file is modified to reflect its new logical
55822Speter      *	inclusion in the source file.  File symbols are also
56822Speter      *	encountered as an included file ends, signaling the
57822Speter      *	continuation of the enclosing file.
58822Speter      *
59822Speter      *	     Functions and procedures which have been declared
60822Speter      *	external may be resolved by declarations from source files
61822Speter      *	which included the external declaration of the function.
62822Speter      *	Functions and procedures may be resolved at most once across
63822Speter      *	a set of object files.  The loader will complain if a
64822Speter      *	function is not resolved at least once.
65822Speter      */
66822Speter 
67832Speter char	program[] = "pc";
68822Speter 
69822Speter #include <sys/types.h>
7013617Ssam #include <sys/stat.h>
71822Speter #include <ar.h>
72822Speter #include <stdio.h>
73822Speter #include <ctype.h>
74822Speter #include <a.out.h>
75822Speter #include <stab.h>
76858Speter #include "pstab.h"
77822Speter #include "pc3.h"
78822Speter 
797598Speter int	errors = NONE;
807598Speter BOOL	wflag = FALSE;
81822Speter 
82822Speter     /*
83822Speter      *	check each of the argument .o files (or archives of .o files).
84822Speter      */
85822Speter main( argc , argv )
86822Speter     int		argc;
87822Speter     char	**argv;
88822Speter     {
89822Speter 	struct fileinfo	ofile;
90822Speter 
917598Speter 	for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) {
927598Speter 	    (*argv)++;
937598Speter 	    switch ( **argv ) {
947598Speter 		default:
957598Speter 		    error( FATAL , "pc3: bad flag -%c\n" , **argv );
967598Speter 		case 'w':
977598Speter 		    wflag = TRUE;
987598Speter 		    break;
997598Speter 	    }
1007598Speter 	}
1017598Speter 	for ( /* void */ ; *argv != 0 ; argv++ ) {
102822Speter #	    ifdef DEBUG
103822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
104822Speter #	    endif DEBUG
105822Speter 	    ofile.name = *argv;
106822Speter 	    checkfile( &ofile );
107822Speter 	}
108822Speter 	exit( errors );
109822Speter     }
110822Speter 
111822Speter     /*
112822Speter      *	check the namelist of a file, or all namelists of an archive.
113822Speter      */
114822Speter checkfile( ofilep )
115822Speter     struct fileinfo	*ofilep;
116822Speter     {
117822Speter 	union {
118822Speter 	    char	mag_armag[ SARMAG + 1 ];
119822Speter 	    struct exec	mag_exec;
120822Speter 	}		mag_un;
121822Speter 	int		red;
122822Speter 	struct stat	filestat;
123822Speter 
124822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
125822Speter 	if ( ofilep -> file == NULL ) {
1267598Speter 	    error( ERROR , "cannot open: %s" , ofilep -> name );
127822Speter 	    return;
128822Speter 	}
129822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
130822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
131822Speter 	if ( red != sizeof mag_un ) {
1327598Speter 	    error( ERROR , "cannot read header: %s" , ofilep -> name );
133822Speter 	    return;
134822Speter 	}
135822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
136822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
137822Speter 	    return;
138822Speter 	}
139822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
140822Speter 		/* archive, iterate through elements */
141822Speter #	    ifdef DEBUG
142822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
143822Speter #	    endif DEBUG
144822Speter 	    ofilep -> nextoffset = SARMAG;
145822Speter 	    while ( nextelement( ofilep ) ) {
146822Speter 		checknl( ofilep );
147822Speter 	    }
148822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
149822Speter 		/* not a file.o */
1507598Speter 	    error( ERROR , "bad format: %s" , ofilep -> name );
151822Speter 	    return;
152822Speter 	} else {
153822Speter 		/* a file.o */
154822Speter #	    ifdef DEBUG
155822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
156822Speter #	    endif DEBUG
157822Speter 	    fseek( ofilep -> file , 0L , 0 );
158822Speter 	    ofilep -> nextoffset = filestat.st_size;
159822Speter 	    checknl( ofilep );
160822Speter 	}
161822Speter 	fclose( ofilep -> file );
162822Speter     }
163822Speter 
164822Speter     /*
165822Speter      *	check the namelist of this file for conflicts with
166822Speter      *	previously entered symbols.
167822Speter      */
168822Speter checknl( ofilep )
169822Speter     register struct fileinfo	*ofilep;
170822Speter     {
171822Speter 
172822Speter 	long			red;
173831Speter 	struct exec		oexec;
174822Speter 	off_t			symoff;
175822Speter 	long			numsyms;
176822Speter 	register struct nlist	*nlp;
177822Speter 	register char		*stringp;
178822Speter 	long			strsize;
179822Speter 	long			sym;
180822Speter 
181831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
182831Speter 	if ( red != sizeof oexec ) {
1837598Speter 	    error( ERROR , "error reading struct exec: %s"
184822Speter 		    , ofilep -> name );
185822Speter 	    return;
186822Speter 	}
187831Speter 	if ( N_BADMAG( oexec ) ) {
188822Speter 	    return;
189822Speter 	}
190831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
191822Speter 	fseek( ofilep -> file , symoff , 1 );
192831Speter 	numsyms = oexec.a_syms / sizeof ( struct nlist );
193822Speter 	if ( numsyms == 0 ) {
194822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
195822Speter 	    return;
196822Speter 	}
197822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
198822Speter 	if ( nlp == 0 ) {
199822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
200822Speter 	}
201822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
202822Speter 		    , ofilep -> file );
203822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
204822Speter 	    >= ofilep -> nextoffset ) {
205822Speter 	    error( WARNING , "no string table (old format .o?)"
206822Speter 		    , ofilep -> name );
207822Speter 	    return;
208822Speter 	}
209822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
210822Speter 		    , ofilep -> file );
211822Speter 	if ( red != 1 ) {
212822Speter 	    error( WARNING , "no string table (old format .o?)"
213822Speter 		    , ofilep -> name );
214822Speter 	    return;
215822Speter 	}
216822Speter 	stringp  = ( char * ) malloc( strsize );
217822Speter 	if ( stringp == 0 ) {
218822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
219822Speter 	}
220822Speter 	red = fread( stringp + sizeof strsize
221822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
222822Speter 	if ( red != 1 ) {
223822Speter 	    error( WARNING , "error reading string table: %s"
224822Speter 		    , ofilep -> name );
225822Speter 	}
226822Speter #	ifdef DEBUG
227822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
228822Speter 		    , ofilep -> name , numsyms );
229822Speter #	endif DEBUG
230822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
231822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
232822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
233822Speter 	    } else {
234822Speter 		nlp[ sym ].n_un.n_name = "";
235822Speter 	    }
236822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
237822Speter 	}
238822Speter 	if ( nlp ) {
239822Speter 	    free( nlp );
240822Speter 	}
241822Speter 	if ( stringp ) {
242822Speter 	    free( stringp );
243822Speter 	}
244822Speter     }
245822Speter 
246822Speter     /*
247822Speter      *	check a symbol.
248822Speter      *	look it up in the hashed symbol table,
249822Speter      *	entering it if necessary.
250822Speter      *	this maintains a state of which .p and .i files
251822Speter      *	it is currently in the midst from the nlist entries
252822Speter      *	for source and included files.
253822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
254822Speter      */
255822Speter checksymbol( nlp , ofilep )
256822Speter     struct nlist	*nlp;
257822Speter     struct fileinfo	*ofilep;
258822Speter     {
259822Speter 	static struct symbol	*pfilep = NIL;
260822Speter 	static struct symbol	*ifilep = NIL;
261822Speter 	register struct symbol	*symbolp;
2627601Speter 	int			errtype;
263822Speter 
264822Speter #	ifdef DEBUG
265822Speter 	    if ( pfilep && ifilep ) {
266822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
267822Speter 			, pfilep -> name , ifilep -> name );
268822Speter 	    }
269844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
270844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
271844Speter 		    , classify( nlp -> n_desc ) );
272822Speter #	endif DEBUG
273844Speter 	if ( nlp -> n_type != N_PC ) {
274844Speter 		/* don't care about the others */
275844Speter 	    return;
276822Speter 	}
277844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
278822Speter 	if ( symbolp -> lookup == NEW ) {
279822Speter #	    ifdef DEBUG
280822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
281822Speter 			, symbolp -> name );
282822Speter #	    endif DEBUG
283844Speter 	    symbolp -> desc = nlp -> n_desc;
284*14129Speter 	    symbolp -> fromp = pfilep;
285844Speter 	    switch ( symbolp -> desc ) {
2867550Speter 		default:
2877550Speter 			error( FATAL , "panic: [checksymbol] NEW" );
288844Speter 		case N_PGLABEL:
289844Speter 		case N_PGCONST:
290844Speter 		case N_PGTYPE:
291822Speter 		case N_PGVAR:
292844Speter 		case N_PGFUNC:
293844Speter 		case N_PGPROC:
2947601Speter 		case N_PLDATA:
2957601Speter 		case N_PLTEXT:
296831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
297831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
298831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
299831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
300831Speter 			return;
301844Speter 		case N_PEFUNC:
302844Speter 		case N_PEPROC:
303831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
304831Speter 			symbolp -> sym_un.sym_str.rline = 0;
305831Speter 			    /*
306831Speter 			     *	functions can only be declared external
307831Speter 			     *	in included files.
308831Speter 			     */
309831Speter 			if ( pfilep == ifilep ) {
310831Speter 			    error( WARNING
311831Speter 				    , "%s, line %d: %s %s must be declared in included file"
312831Speter 				    , pfilep -> name , nlp -> n_value
313844Speter 				    , classify( symbolp -> desc )
314831Speter 				    , symbolp -> name );
315831Speter 			}
316822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
317822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
318822Speter 			return;
319822Speter 		case N_PSO:
320*14129Speter 			if ( nlp -> n_value < N_FLAGCHECKSUM ) {
321*14129Speter 			    error( WARNING,
322*14129Speter 				"%s is out of date and should be recompiled",
323*14129Speter 				ofilep -> name );
324*14129Speter 			}
325822Speter 			pfilep = symbolp;
326*14129Speter 			ifilep = symbolp;
327*14129Speter 			symbolp -> sym_un.checksum = N_FLAGCHECKSUM;
328*14129Speter 			return;
329822Speter 		case N_PSOL:
330822Speter 			ifilep = symbolp;
331*14129Speter 			symbolp -> sym_un.checksum = nlp -> n_value;
332822Speter 			return;
333822Speter 	    }
334822Speter 	} else {
335822Speter #	    ifdef DEBUG
336822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
337822Speter 			, symbolp -> name );
338822Speter #	    endif DEBUG
3397601Speter 	    errtype = ERROR;
340844Speter 	    switch ( symbolp -> desc ) {
3417550Speter 		default:
3427550Speter 			error( FATAL , "panic [checksymbol] OLD" );
343*14129Speter 			return;
344822Speter 		case N_PSO:
345822Speter 			    /*
346822Speter 			     *	finding a file again means you are back
347822Speter 			     *	in it after finishing an include file.
348822Speter 			     */
349*14129Speter 			if ( symbolp -> desc != nlp -> n_desc ) {
350*14129Speter 			    error( FATAL , "panic [checksymbol] PSO" );
351*14129Speter 			    return;
352*14129Speter 			}
353822Speter 			pfilep = symbolp;
354*14129Speter 			ifilep = symbolp;
355*14129Speter 			return;
356822Speter 		case N_PSOL:
357822Speter 			    /*
358822Speter 			     *	include files can be seen more than once,
359*14129Speter 			     *	but their checksums are checked if they are
360*14129Speter 			     *	greater than N_FLAGCHECKSUM.
361*14129Speter 			     *	PSOL's are seen with checksums as the
362*14129Speter 			     *	include file is entered, and with
363*14129Speter 			     *	N_FLAGCHECKSUM as we are back in an
364*14129Speter 			     *	included file from a nested include.
365822Speter 			     */
366*14129Speter 			if ( symbolp -> desc != nlp -> n_desc ) {
367*14129Speter 			    error( FATAL , "panic [checksymbol] PSOL" );
368*14129Speter 			    return;
369*14129Speter 			}
370*14129Speter 			if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM
371*14129Speter 			   && (unsigned) nlp -> n_value > N_FLAGCHECKSUM
372*14129Speter 			   && symbolp -> sym_un.checksum != nlp -> n_value ) {
373*14129Speter 			    error( ERROR,
374*14129Speter 			    "%s included in %s differs from %s included in %s",
375*14129Speter 				symbolp -> name, pfilep -> name,
376*14129Speter 				symbolp -> name, symbolp -> fromp -> name );
377*14129Speter 			}
378822Speter 			ifilep = symbolp;
379822Speter 			return;
380844Speter 		case N_PEFUNC:
381844Speter 		case N_PEPROC:
382822Speter 			    /*
3837550Speter 			     *	this might be the resolution of the external
3847550Speter 			     *	has to match func/proc of external
3857550Speter 			     *	and has to have included external
3867550Speter 			     *	and has to not have been previously resolved.
387822Speter 			     */
3887550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
3897550Speter 			         && nlp -> n_desc == N_PGFUNC )
3907550Speter 			      || ( symbolp -> desc == N_PEPROC
3917550Speter 				 && nlp -> n_desc == N_PGPROC ) )
392*14129Speter 			   && ( symbolp -> fromp == pfilep )
3937550Speter 			   && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
3947550Speter 				/*
3957550Speter 				 *	resolve external
3967550Speter 				 */
3977550Speter #			    ifdef DEBUG
3987550Speter 				fprintf( stderr , "[checksymbol] resolving external\n" );
3997550Speter #			    endif DEBUG
4007550Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
4017550Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
4027550Speter 			    return;
403822Speter 			}
404822Speter 			    /*
4057550Speter 			     *	otherwise, it might be another external,
4067550Speter 			     *	which is okay if it's
4077550Speter 			     *	the same type and from the same include file
408822Speter 			     */
4097550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
4107550Speter 			         && nlp -> n_desc == N_PEFUNC )
4117550Speter 			      || ( symbolp -> desc == N_PEPROC
4127550Speter 				 && nlp -> n_desc == N_PEPROC ) )
4137550Speter 			   && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
4147550Speter 				/*
4157550Speter 				 *	just another pretty external
4167550Speter 				 *	make it look like it comes from here.
4177550Speter 				 */
4187550Speter #			    ifdef DEBUG
4197550Speter 				fprintf( stderr , "[checksymbol] just another pretty external\n" );
4207550Speter #			    endif DEBUG
421*14129Speter 			    symbolp -> fromp = pfilep;
4227550Speter 			    return;
423822Speter 			}
424822Speter 			    /*
4257550Speter 			     *	something is wrong
4267598Speter 			     *	if it's not resolved, use the header file
4277598Speter 			     *	otherwise, it's just a regular error
428822Speter 			     */
4297598Speter 			if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
4307598Speter 			    error( ERROR ,
4317601Speter 		    "%s, line %d: %s is already defined\n\t(%s, line %d)." ,
4327598Speter 				ifilep -> name , nlp -> n_value ,
4337598Speter 				nlp -> n_un.n_name ,
4347598Speter 				symbolp -> sym_un.sym_str.fromi -> name ,
4357598Speter 				symbolp -> sym_un.sym_str.iline );
4367598Speter 			    return;
4377598Speter 			}
4387598Speter 			break;
439844Speter 		case N_PGFUNC:
440844Speter 		case N_PGPROC:
441822Speter 			    /*
442822Speter 			     *	functions may not be seen more than once.
443822Speter 			     *	the loader will complain about
444822Speter 			     *	`multiply defined', but we can, too.
445822Speter 			     */
446822Speter 			break;
447844Speter 		case N_PGLABEL:
448844Speter 		case N_PGCONST:
449844Speter 		case N_PGTYPE:
450822Speter 		case N_PGVAR:
451822Speter 			    /*
452822Speter 			     *	labels, constants, types, variables
453822Speter 			     *	and external declarations
454822Speter 			     *	may be seen as many times as they want,
455822Speter 			     *	as long as they come from the same include file.
456822Speter 			     *	make it look like they come from this .p file.
457822Speter 			     */
458822Speter included:
459844Speter 			if (  nlp -> n_desc != symbolp -> desc
460822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
461822Speter 			    break;
462822Speter 			}
463*14129Speter 			symbolp -> fromp = pfilep;
464822Speter 			return;
4657601Speter 		case N_PLDATA:
4667601Speter 		case N_PLTEXT:
4677601Speter 			switch ( nlp -> n_desc ) {
4687601Speter 			    default:
4697601Speter 				error( FATAL , "pc3: unknown stab 0x%x"
4707601Speter 					, nlp -> n_desc );
4717601Speter 				return;
4727601Speter 			    case N_PSO:
4737601Speter 			    case N_PSOL:
4747601Speter 			    case N_PGCONST:
4757601Speter 			    case N_PGTYPE:
4767601Speter 				/* these won't conflict with library */
4777601Speter 				return;
4787601Speter 			    case N_PGLABEL:
4797601Speter 			    case N_PGVAR:
4807601Speter 			    case N_PGFUNC:
4817601Speter 			    case N_PGPROC:
4827601Speter 			    case N_PEFUNC:
4837601Speter 			    case N_PEPROC:
4847601Speter 			    case N_PLDATA:
4857601Speter 			    case N_PLTEXT:
4867601Speter 				errtype = WARNING;
4877601Speter 				break;
4887601Speter 			}
4897601Speter 			break;
490822Speter 	    }
491822Speter 		/*
492822Speter 		 *	this is the breaks
493822Speter 		 */
4947601Speter 	    error( errtype
4957601Speter 		, "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)."
4967601Speter 		, ifilep -> name
4977601Speter 		, nlp -> n_value
4987601Speter 		, classify( nlp -> n_desc )
4997601Speter 		, nlp -> n_un.n_name
5007601Speter 		, ( symbolp -> desc == nlp -> n_desc ? "" : " as " )
5017601Speter 		, ( symbolp -> desc == nlp -> n_desc
5027601Speter 			? "" : article( symbolp -> desc ) )
5037601Speter 		, symbolp -> sym_un.sym_str.rfilep -> name
5047601Speter 		, symbolp -> sym_un.sym_str.rline );
505822Speter 	}
506822Speter     }
507822Speter 
508822Speter     /*
509822Speter      *	quadratically hashed symbol table.
510822Speter      *	things are never deleted from the hash symbol table.
511822Speter      *	as more hash table is needed,
512822Speter      *	a new one is alloc'ed and chained to the end.
513822Speter      *	search is by rehashing within each table,
514822Speter      *	traversing chains to next table if unsuccessful.
515822Speter      */
516822Speter struct symbol *
517822Speter entersymbol( name )
518822Speter     char	*name;
519822Speter     {
5209572Speter 	static struct symboltableinfo	symboltable;
521822Speter 	char				*enteredname;
522822Speter 	long				hashindex;
523822Speter 	register struct symboltableinfo	*tablep;
524822Speter 	register struct symbol		**herep;
525822Speter 	register struct symbol		**limitp;
526822Speter 	register long			increment;
527822Speter 
528822Speter 	enteredname = enterstring( name );
529822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
5309572Speter 	for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) {
531822Speter 	    if ( tablep == NIL ) {
5329572Speter #		ifdef SPACEDEBUG
5339572Speter 		    fprintf( stderr ,
5349572Speter 			    "[entersymbol] calloc'ing table for %d symbols\n" ,
5359572Speter 			    SYMBOLPRIME );
5369572Speter #		endif SPACEDEBUG
5379572Speter 		for ( tablep = &symboltable
5389572Speter 		    ; tablep->chain != NIL
5399572Speter 		    ; tablep = tablep->chain ) {
5409572Speter 			continue;
5419572Speter 		}
5429572Speter 		tablep->chain = ( struct symboltableinfo * )
5439572Speter 			    calloc( 1 , sizeof ( struct symboltableinfo ) );
5449572Speter 		if ( tablep->chain == NIL ) {
545822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
546822Speter 		}
5479572Speter 		tablep = tablep->chain;
548822Speter 	    }
549822Speter 	    herep = &( tablep -> entry[ hashindex ] );
550822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
551822Speter 	    increment = 1;
552822Speter 	    do {
553822Speter 		if ( *herep == NIL ) {
554822Speter 			/* empty */
5559572Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) {
556822Speter 			    /* too full, break for next table */
557822Speter 			break;
558822Speter 		    }
559822Speter 		    tablep -> used++;
560822Speter 		    *herep = symbolalloc();
561822Speter 		    ( *herep ) -> name = enteredname;
562822Speter 		    ( *herep ) -> lookup = NEW;
5639572Speter #		    ifdef HASHDEBUG
5649572Speter 			fprintf( stderr ,
5659572Speter 				"[entersymbol] name %s NEW after %d\n" ,
5669572Speter 				enteredname , increment / 2 );
5679572Speter #		    endif HASHDEBUG
568822Speter 		    return *herep;
569822Speter 		}
570822Speter 		    /* a find? */
571822Speter 		if ( ( *herep ) -> name == enteredname ) {
572822Speter 		    ( *herep ) -> lookup = OLD;
5739572Speter #		    ifdef HASHDEBUG
5749572Speter 			fprintf( stderr , "[entersymbol] name %s OLD at %d\n" ,
5759572Speter 				enteredname , increment / 2 );
5769572Speter #		    endif HASHDEBUG
577822Speter 		    return *herep;
578822Speter 		}
579822Speter 		herep += increment;
580822Speter 		if ( herep >= limitp ) {
581822Speter 		    herep -= SYMBOLPRIME;
582822Speter 		}
583822Speter 		increment += 2;
584822Speter 	    } while ( increment < SYMBOLPRIME );
5859572Speter #	    ifdef HASHDEBUG
5869572Speter 		fprintf( stderr , "[entersymbol] next symboltable\n" );
5879572Speter #	    endif HASHDEBUG
588822Speter 	}
589822Speter     }
590822Speter 
591822Speter     /*
592822Speter      *	allocate a symbol from the dynamically allocated symbol table.
593822Speter      */
594822Speter struct symbol *
595822Speter symbolalloc()
596822Speter     {
597822Speter 	static struct symbol	*nextsymbol = NIL;
598822Speter 	static long		symbolsleft = 0;
599822Speter 	struct symbol		*newsymbol;
600822Speter 
601822Speter 	if ( symbolsleft <= 0 ) {
6029572Speter #	    ifdef SPACEDEBUG
6039572Speter 		fprintf( stderr ,
6049572Speter 			"[symbolalloc] malloc space for %d symbols\n" ,
6059572Speter 			SYMBOLALLOC / sizeof( struct symbol ) );
6069572Speter #	    endif SPACEDEBUG
607822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
608822Speter 	    if ( nextsymbol == 0 ) {
609822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
610822Speter 	    }
611822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
612822Speter 	}
613822Speter 	newsymbol = nextsymbol;
614822Speter 	nextsymbol++;
615822Speter 	symbolsleft--;
616822Speter 	return newsymbol;
617822Speter     }
618822Speter 
619822Speter     /*
620822Speter      *	hash a string based on all of its characters.
621822Speter      */
622822Speter long
623822Speter hashstring( string )
624822Speter     char	*string;
625822Speter     {
626822Speter 	register char	*cp;
627822Speter 	register long	value;
628822Speter 
629822Speter 	value = 0;
630822Speter 	for ( cp = string ; *cp ; cp++ ) {
631822Speter 	    value = ( value * 2 ) + *cp;
632822Speter 	}
633822Speter 	return value;
634822Speter     }
635822Speter 
636822Speter     /*
637822Speter      *	quadratically hashed string table.
638822Speter      *	things are never deleted from the hash string table.
639822Speter      *	as more hash table is needed,
640822Speter      *	a new one is alloc'ed and chained to the end.
641822Speter      *	search is by rehashing within each table,
642822Speter      *	traversing chains to next table if unsuccessful.
643822Speter      */
644822Speter char *
645822Speter enterstring( string )
646822Speter     char	*string;
647822Speter     {
6489572Speter 	static struct stringtableinfo	stringtable;
649822Speter 	long				hashindex;
650822Speter 	register struct stringtableinfo	*tablep;
651822Speter 	register char			**herep;
652822Speter 	register char			**limitp;
653822Speter 	register long			increment;
654822Speter 
655822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
6569572Speter 	for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) {
657822Speter 	    if ( tablep == NIL ) {
6589572Speter #		ifdef SPACEDEBUG
6599572Speter 		    fprintf( stderr ,
6609572Speter 			    "[enterstring] calloc space for %d strings\n" ,
6619572Speter 			    STRINGPRIME );
6629572Speter #		endif SPACEDEBUG
6639572Speter 		for ( tablep = &stringtable
6649572Speter 		    ; tablep->chain != NIL
6659572Speter 		    ; tablep = tablep->chain ) {
6669572Speter 			continue;
6679572Speter 		}
6689572Speter 		tablep->chain = ( struct stringtableinfo * )
6699572Speter 			    calloc( 1 , sizeof ( struct stringtableinfo ) );
6709572Speter 		if ( tablep->chain == NIL ) {
671822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
672822Speter 		}
6739572Speter 		tablep = tablep->chain;
674822Speter 	    }
675822Speter 	    herep = &( tablep -> entry[ hashindex ] );
676822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
677822Speter 	    increment = 1;
678822Speter 	    do {
679822Speter 		if ( *herep == NIL ) {
680822Speter 			/* empty */
6819572Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) {
682822Speter 			    /* too full, break for next table */
683822Speter 			break;
684822Speter 		    }
685822Speter 		    tablep -> used++;
686822Speter 		    *herep = charalloc( strlen( string ) );
687822Speter 		    strcpy( *herep , string );
6889572Speter #		    ifdef HASHDEBUG
6899572Speter 			fprintf( stderr ,
6909572Speter 				"[enterstring] string %s copied after %d\n" ,
6919572Speter 				*herep , increment / 2 );
6929572Speter #		    endif HASHDEBUG
693822Speter 		    return *herep;
694822Speter 		}
695822Speter 		    /* quick, check the first chars and then the rest */
696822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
6979572Speter #		    ifdef HASHDEBUG
6989572Speter 			fprintf( stderr ,
6999572Speter 				"[enterstring] string %s found after %d\n" ,
7009572Speter 				*herep , increment / 2 );
7019572Speter #		    endif HASHDEBUG
702822Speter 		    return *herep;
703822Speter 		}
704822Speter 		herep += increment;
705822Speter 		if ( herep >= limitp ) {
706822Speter 		    herep -= STRINGPRIME;
707822Speter 		}
708822Speter 		increment += 2;
709822Speter 	    } while ( increment < STRINGPRIME );
7109572Speter #	    ifdef HASHDEBUG
7119572Speter 		fprintf( stderr , "[enterstring] next stringtable\n" );
7129572Speter #	    endif HASHDEBUG
713822Speter 	}
714822Speter     }
715822Speter 
716822Speter     /*
717822Speter      *	copy a string to the dynamically allocated character table.
718822Speter      */
719822Speter char *
720822Speter charalloc( length )
721822Speter     register long	length;
722822Speter     {
723822Speter 	static char	*nextchar = NIL;
724822Speter 	static long	charsleft = 0;
725822Speter 	register long	lengthplus1 = length + 1;
726822Speter 	register long	askfor;
727822Speter 	char		*newstring;
728822Speter 
729822Speter 	if ( charsleft < lengthplus1 ) {
730822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
7319572Speter #	    ifdef SPACEDEBUG
7329572Speter 		fprintf( stderr , "[charalloc] malloc space for %d chars\n"
733822Speter 			, askfor );
7349572Speter #	    endif SPACEDEBUG
735822Speter 	    nextchar = ( char * ) malloc( askfor );
736822Speter 	    if ( nextchar == 0 ) {
737822Speter 		error( FATAL , "no room for %d characters" , askfor );
738822Speter 	    }
739822Speter 	    charsleft = askfor;
740822Speter 	}
741822Speter 	newstring = nextchar;
742822Speter 	nextchar += lengthplus1;
743822Speter 	charsleft -= lengthplus1;
744822Speter 	return newstring;
745822Speter     }
746822Speter 
747822Speter     /*
748822Speter      *	read an archive header for the next element
749822Speter      *	and find the offset of the one after this.
750822Speter      */
751822Speter BOOL
752822Speter nextelement( ofilep )
753822Speter     struct fileinfo	*ofilep;
754822Speter     {
755822Speter 	register char	*cp;
756822Speter 	register long	red;
757822Speter 	register off_t	arsize;
758822Speter 	struct ar_hdr	archdr;
759822Speter 
760822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
761822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
762822Speter 	if ( red != sizeof archdr ) {
763822Speter 	    return FALSE;
764822Speter 	}
765822Speter 	    /* null terminate the blank-padded name */
766822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
767822Speter 	*cp = '\0';
768822Speter 	while ( *--cp == ' ' ) {
769822Speter 	    *cp = '\0';
770822Speter 	}
771822Speter 	    /* set up the address of the beginning of next element */
772822Speter 	arsize = atol( archdr.ar_size );
773822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
774822Speter 	if ( arsize & 1 ) {
775822Speter 	    arsize += 1;
776822Speter 	}
777822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
778822Speter 	    /* say we had one */
779822Speter 	return TRUE;
780822Speter     }
781822Speter 
782822Speter     /*
783822Speter      *	variable number of arguments to error, like printf.
784822Speter      */
7857601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 )
7867598Speter     int		type;
787822Speter     char	*message;
788822Speter     {
7897598Speter 	errors = type > errors ? type : errors;
7907598Speter 	if ( wflag && type == WARNING ) {
7917598Speter 	    return;
7927598Speter 	}
793822Speter 	fprintf( stderr , "%s: " , program );
7947598Speter 	switch ( type ) {
7957598Speter 	    case WARNING:
7967598Speter 		    fprintf( stderr , "Warning: " );
7977598Speter 		    break;
7987598Speter 	    case ERROR:
7997598Speter 		    fprintf( stderr , "Error: " );
8007598Speter 		    break;
8017598Speter 	    case FATAL:
8027598Speter 		    fprintf( stderr , "Fatal: " );
8037598Speter 		    break;
8047598Speter 	    default:
8057598Speter 		    fprintf( stderr , "Ooops: " );
8067598Speter 		    break;
8077598Speter 	}
8087601Speter 	fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 );
809822Speter 	fprintf( stderr , "\n" );
8107598Speter 	if ( type == FATAL ) {
8117598Speter 	    exit( FATAL );
812822Speter 	}
813822Speter     }
814822Speter 
815822Speter char *
816822Speter classify( type )
817822Speter     unsigned char	type;
818822Speter     {
819822Speter 	switch ( type ) {
820822Speter 	    case N_PSO:
821822Speter 		return "source file";
822822Speter 	    case N_PSOL:
823822Speter 		return "include file";
824844Speter 	    case N_PGLABEL:
825822Speter 		return "label";
826844Speter 	    case N_PGCONST:
827822Speter 		return "constant";
828844Speter 	    case N_PGTYPE:
829822Speter 		return "type";
830822Speter 	    case N_PGVAR:
831822Speter 		return "variable";
832844Speter 	    case N_PGFUNC:
833822Speter 		return "function";
834844Speter 	    case N_PGPROC:
835822Speter 		return "procedure";
836844Speter 	    case N_PEFUNC:
837822Speter 		return "external function";
838844Speter 	    case N_PEPROC:
839822Speter 		return "external procedure";
8407601Speter 	    case N_PLDATA:
8417601Speter 		return "library variable";
8427601Speter 	    case N_PLTEXT:
8437601Speter 		return "library routine";
844822Speter 	    default:
845822Speter 		return "unknown symbol";
846822Speter 	}
847822Speter     }
8487601Speter 
8497601Speter char *
8507601Speter article( type )
8517601Speter     unsigned char	type;
8527601Speter     {
8537601Speter 	switch ( type ) {
8547601Speter 	    case N_PSO:
8557601Speter 		return "a source file";
8567601Speter 	    case N_PSOL:
8577601Speter 		return "an include file";
8587601Speter 	    case N_PGLABEL:
8597601Speter 		return "a label";
8607601Speter 	    case N_PGCONST:
8617601Speter 		return "a constant";
8627601Speter 	    case N_PGTYPE:
8637601Speter 		return "a type";
8647601Speter 	    case N_PGVAR:
8657601Speter 		return "a variable";
8667601Speter 	    case N_PGFUNC:
8677601Speter 		return "a function";
8687601Speter 	    case N_PGPROC:
8697601Speter 		return "a procedure";
8707601Speter 	    case N_PEFUNC:
8717601Speter 		return "an external function";
8727601Speter 	    case N_PEPROC:
8737601Speter 		return "an external procedure";
8747601Speter 	    case N_PLDATA:
8757601Speter 		return "a library variable";
8767601Speter 	    case N_PLTEXT:
8777601Speter 		return "a library routine";
8787601Speter 	    default:
8797601Speter 		return "an unknown symbol";
8807601Speter 	}
8817601Speter     }
882