xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 858)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*858Speter static	char sccsid[] = "@(#)pc3.c 1.6 09/09/80";
4822Speter 
5822Speter     /*
6822Speter      *	     Pc3 is a pass in the Berkeley Pascal compilation
7822Speter      *	process that is performed just prior to linking Pascal
8822Speter      *	object files.  Its purpose is to enforce the rules of
9822Speter      *	separate compilation for Berkeley Pascal.  Pc3 is called
10822Speter      *	with the same argument list of object files that is sent to
11822Speter      *	the loader.  These checks are performed by pc3 by examining
12822Speter      *	the symbol tables of the object files:
13822Speter      *	(1)  All source and included files must be "up-to-date" with
14822Speter      *	     the object files of which they are components.
15822Speter      *	(2)  Each global Pascal symbol (label, constant, type,
16822Speter      *	     variable, procedure, or function name) must be uniquely
17822Speter      *	     declared, i.e. declared in only one included file or
18822Speter      *	     source file.
19822Speter      *	(3)  Each external function (or procedure) may be resolved
20822Speter      *	     at most once in a source file which included the
21822Speter      *	     external declaration of the function.
22822Speter      *
23822Speter      *	     The symbol table of each object file is scanned and
24822Speter      *	each global Pascal symbol is placed in a hashed symbol
25822Speter      *	table.  The Pascal compiler has been modified to emit all
26822Speter      *	Pascal global symbols to the object file symbol table.  The
27822Speter      *	information stored in the symbol table for each such symbol
28822Speter      *	is:
29822Speter      *
30822Speter      *	   - the name of the symbol;
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>
74*858Speter #include "pstab.h"
75822Speter #include "pc3.h"
76822Speter 
77822Speter int	errors = 0;
78822Speter 
79822Speter     /*
80822Speter      *	check each of the argument .o files (or archives of .o files).
81822Speter      */
82822Speter main( argc , argv )
83822Speter     int		argc;
84822Speter     char	**argv;
85822Speter     {
86822Speter 	struct fileinfo	ofile;
87822Speter 
88831Speter 	while ( ++argv , --argc ) {
89822Speter #	    ifdef DEBUG
90822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
91822Speter #	    endif DEBUG
92822Speter 	    ofile.name = *argv;
93822Speter 	    checkfile( &ofile );
94822Speter 	}
95822Speter 	exit( errors );
96822Speter     }
97822Speter 
98822Speter     /*
99822Speter      *	check the namelist of a file, or all namelists of an archive.
100822Speter      */
101822Speter checkfile( ofilep )
102822Speter     struct fileinfo	*ofilep;
103822Speter     {
104822Speter 	union {
105822Speter 	    char	mag_armag[ SARMAG + 1 ];
106822Speter 	    struct exec	mag_exec;
107822Speter 	}		mag_un;
108822Speter 	int		red;
109822Speter 	struct stat	filestat;
110822Speter 
111822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
112822Speter 	if ( ofilep -> file == NULL ) {
113822Speter 	    error( WARNING , "cannot open: %s" , ofilep -> name );
114822Speter 	    return;
115822Speter 	}
116822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
117822Speter 	ofilep -> modtime = filestat.st_mtime;
118822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
119822Speter 	if ( red != sizeof mag_un ) {
120822Speter 	    error( WARNING , "cannot read header: %s" , ofilep -> name );
121822Speter 	    return;
122822Speter 	}
123822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
124822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
125822Speter 	    return;
126822Speter 	}
127822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
128822Speter 		/* archive, iterate through elements */
129822Speter #	    ifdef DEBUG
130822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
131822Speter #	    endif DEBUG
132822Speter 	    ofilep -> nextoffset = SARMAG;
133822Speter 	    while ( nextelement( ofilep ) ) {
134822Speter 		checknl( ofilep );
135822Speter 	    }
136822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
137822Speter 		/* not a file.o */
138822Speter 	    error( WARNING , "bad format: %s" , ofilep -> name );
139822Speter 	    return;
140822Speter 	} else {
141822Speter 		/* a file.o */
142822Speter #	    ifdef DEBUG
143822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
144822Speter #	    endif DEBUG
145822Speter 	    fseek( ofilep -> file , 0L , 0 );
146822Speter 	    ofilep -> nextoffset = filestat.st_size;
147822Speter 	    checknl( ofilep );
148822Speter 	}
149822Speter 	fclose( ofilep -> file );
150822Speter     }
151822Speter 
152822Speter     /*
153822Speter      *	check the namelist of this file for conflicts with
154822Speter      *	previously entered symbols.
155822Speter      */
156822Speter checknl( ofilep )
157822Speter     register struct fileinfo	*ofilep;
158822Speter     {
159822Speter 
160822Speter 	long			red;
161831Speter 	struct exec		oexec;
162822Speter 	off_t			symoff;
163822Speter 	long			numsyms;
164822Speter 	register struct nlist	*nlp;
165822Speter 	register char		*stringp;
166822Speter 	long			strsize;
167822Speter 	long			sym;
168822Speter 
169831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
170831Speter 	if ( red != sizeof oexec ) {
171822Speter 	    error( WARNING , "error reading struct exec: %s"
172822Speter 		    , ofilep -> name );
173822Speter 	    return;
174822Speter 	}
175831Speter 	if ( N_BADMAG( oexec ) ) {
176822Speter 	    return;
177822Speter 	}
178831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
179822Speter 	fseek( ofilep -> file , symoff , 1 );
180831Speter 	numsyms = oexec.a_syms / sizeof ( struct nlist );
181822Speter 	if ( numsyms == 0 ) {
182822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
183822Speter 	    return;
184822Speter 	}
185822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
186822Speter 	if ( nlp == 0 ) {
187822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
188822Speter 	}
189822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
190822Speter 		    , ofilep -> file );
191822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
192822Speter 	    >= ofilep -> nextoffset ) {
193822Speter 	    error( WARNING , "no string table (old format .o?)"
194822Speter 		    , ofilep -> name );
195822Speter 	    return;
196822Speter 	}
197822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
198822Speter 		    , ofilep -> file );
199822Speter 	if ( red != 1 ) {
200822Speter 	    error( WARNING , "no string table (old format .o?)"
201822Speter 		    , ofilep -> name );
202822Speter 	    return;
203822Speter 	}
204822Speter 	stringp  = ( char * ) malloc( strsize );
205822Speter 	if ( stringp == 0 ) {
206822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
207822Speter 	}
208822Speter 	red = fread( stringp + sizeof strsize
209822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
210822Speter 	if ( red != 1 ) {
211822Speter 	    error( WARNING , "error reading string table: %s"
212822Speter 		    , ofilep -> name );
213822Speter 	}
214822Speter #	ifdef DEBUG
215822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
216822Speter 		    , ofilep -> name , numsyms );
217822Speter #	endif DEBUG
218822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
219822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
220822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
221822Speter 	    } else {
222822Speter 		nlp[ sym ].n_un.n_name = "";
223822Speter 	    }
224822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
225822Speter 	}
226822Speter 	if ( nlp ) {
227822Speter 	    free( nlp );
228822Speter 	}
229822Speter 	if ( stringp ) {
230822Speter 	    free( stringp );
231822Speter 	}
232822Speter     }
233822Speter 
234822Speter     /*
235822Speter      *	check a symbol.
236822Speter      *	look it up in the hashed symbol table,
237822Speter      *	entering it if necessary.
238822Speter      *	this maintains a state of which .p and .i files
239822Speter      *	it is currently in the midst from the nlist entries
240822Speter      *	for source and included files.
241822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
242822Speter      */
243822Speter checksymbol( nlp , ofilep )
244822Speter     struct nlist	*nlp;
245822Speter     struct fileinfo	*ofilep;
246822Speter     {
247822Speter 	static struct symbol	*pfilep = NIL;
248822Speter 	static struct symbol	*ifilep = NIL;
249822Speter 	register struct symbol	*symbolp;
250822Speter 
251822Speter #	ifdef DEBUG
252822Speter 	    if ( pfilep && ifilep ) {
253822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
254822Speter 			, pfilep -> name , ifilep -> name );
255822Speter 	    }
256844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
257844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
258844Speter 		    , classify( nlp -> n_desc ) );
259822Speter #	endif DEBUG
260844Speter 	if ( nlp -> n_type != N_PC ) {
261844Speter 		/* don't care about the others */
262844Speter 	    return;
263822Speter 	}
264844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
265822Speter 	if ( symbolp -> lookup == NEW ) {
266822Speter #	    ifdef DEBUG
267822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
268822Speter 			, symbolp -> name );
269822Speter #	    endif DEBUG
270844Speter 	    symbolp -> desc = nlp -> n_desc;
271844Speter 	    switch ( symbolp -> desc ) {
272844Speter 		case N_PGLABEL:
273844Speter 		case N_PGCONST:
274844Speter 		case N_PGTYPE:
275822Speter 		case N_PGVAR:
276844Speter 		case N_PGFUNC:
277844Speter 		case N_PGPROC:
278831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
279831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
280831Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
281831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
282831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
283831Speter 			return;
284844Speter 		case N_PEFUNC:
285844Speter 		case N_PEPROC:
286831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
287831Speter 			symbolp -> sym_un.sym_str.rline = 0;
288831Speter 			    /*
289831Speter 			     *	functions can only be declared external
290831Speter 			     *	in included files.
291831Speter 			     */
292831Speter 			if ( pfilep == ifilep ) {
293831Speter 			    error( WARNING
294831Speter 				    , "%s, line %d: %s %s must be declared in included file"
295831Speter 				    , pfilep -> name , nlp -> n_value
296844Speter 				    , classify( symbolp -> desc )
297831Speter 				    , symbolp -> name );
298831Speter 			}
299822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
300822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
301822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
302822Speter 			return;
303822Speter 		case N_PSO:
304822Speter 			pfilep = symbolp;
305822Speter 			/* and fall through */
306822Speter 		case N_PSOL:
307822Speter 			ifilep = symbolp;
308822Speter 			symbolp -> sym_un.modtime = mtime( symbolp -> name );
309822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
310822Speter 			    error( WARNING , "%s is out of date with %s"
311822Speter 				    , ofilep -> name , symbolp -> name );
312822Speter 			}
313822Speter 			return;
314822Speter 	    }
315822Speter 	} else {
316822Speter #	    ifdef DEBUG
317822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
318822Speter 			, symbolp -> name );
319822Speter #	    endif DEBUG
320844Speter 	    switch ( symbolp -> desc ) {
321822Speter 		case N_PSO:
322822Speter 			    /*
323822Speter 			     *	finding a file again means you are back
324822Speter 			     *	in it after finishing an include file.
325822Speter 			     */
326822Speter 			pfilep = symbolp;
327822Speter 			/* and fall through */
328822Speter 		case N_PSOL:
329822Speter 			    /*
330822Speter 			     *	include files can be seen more than once,
331822Speter 			     *	but they still have to be timechecked.
332822Speter 			     *	(this will complain twice for out of date
333822Speter 			     *	include files which include other files.
334822Speter 			     *	sigh.)
335822Speter 			     */
336822Speter 			ifilep = symbolp;
337822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
338822Speter 			    error( WARNING , "%s is out of date with %s"
339822Speter 				    , ofilep -> name , symbolp -> name );
340822Speter 			}
341822Speter 			return;
342844Speter 		case N_PEFUNC:
343844Speter 		case N_PEPROC:
344822Speter 			    /*
345822Speter 			     *	we may see any number of external declarations,
346822Speter 			     *	but they all have to come
347822Speter 			     *	from the same include file.
348822Speter 			     */
349844Speter 			if (   nlp -> n_desc == N_PEFUNC
350844Speter 			    || nlp -> n_desc == N_PEPROC ) {
351822Speter 			    goto included;
352822Speter 			}
353822Speter 			    /*
354822Speter 			     *	an external function can be resolved by
355822Speter 			     *	the resolution of the function
356822Speter 			     *	if the resolving file
357822Speter 			     *	included the external declaration.
358822Speter 			     */
359844Speter 			if (    (  symbolp -> desc == N_PEFUNC
360844Speter 				&& nlp -> n_desc != N_PGFUNC )
361844Speter 			    ||  (  symbolp -> desc == N_PEPROC
362844Speter 				&& nlp -> n_desc != N_PGPROC )
363822Speter 			    || symbolp -> sym_un.sym_str.fromp != pfilep ) {
364822Speter 			    break;
365822Speter 			}
366822Speter 			    /*
367822Speter 			     *	an external function can only be resolved once.
368822Speter 			     */
369822Speter 			if ( symbolp -> sym_un.sym_str.rfilep != NIL ) {
370822Speter 			    break;
371822Speter 			}
372822Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
373822Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
374822Speter 			return;
375844Speter 		case N_PGFUNC:
376844Speter 		case N_PGPROC:
377822Speter 			    /*
378822Speter 			     *	functions may not be seen more than once.
379822Speter 			     *	the loader will complain about
380822Speter 			     *	`multiply defined', but we can, too.
381822Speter 			     */
382822Speter 			break;
383844Speter 		case N_PGLABEL:
384844Speter 		case N_PGCONST:
385844Speter 		case N_PGTYPE:
386822Speter 		case N_PGVAR:
387822Speter 			    /*
388822Speter 			     *	labels, constants, types, variables
389822Speter 			     *	and external declarations
390822Speter 			     *	may be seen as many times as they want,
391822Speter 			     *	as long as they come from the same include file.
392822Speter 			     *	make it look like they come from this .p file.
393822Speter 			     */
394822Speter included:
395844Speter 			if (  nlp -> n_desc != symbolp -> desc
396822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
397822Speter 			    break;
398822Speter 			}
399822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
400822Speter 			return;
401822Speter 	    }
402822Speter 		/*
403822Speter 		 *	this is the breaks
404822Speter 		 */
405822Speter 	    error( WARNING , "%s, line %d: %s already defined (%s, line %d)."
406822Speter 		    , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
407822Speter 		    , symbolp -> sym_un.sym_str.rfilep -> name
408822Speter 		    , symbolp -> sym_un.sym_str.rline );
409822Speter 	}
410822Speter     }
411822Speter 
412822Speter     /*
413822Speter      *	quadratically hashed symbol table.
414822Speter      *	things are never deleted from the hash symbol table.
415822Speter      *	as more hash table is needed,
416822Speter      *	a new one is alloc'ed and chained to the end.
417822Speter      *	search is by rehashing within each table,
418822Speter      *	traversing chains to next table if unsuccessful.
419822Speter      */
420822Speter struct symbol *
421822Speter entersymbol( name )
422822Speter     char	*name;
423822Speter     {
424822Speter 	static struct symboltableinfo	*symboltable = NIL;
425822Speter 	char				*enteredname;
426822Speter 	long				hashindex;
427822Speter 	register struct symboltableinfo	*tablep;
428822Speter 	register struct symbol		**herep;
429822Speter 	register struct symbol		**limitp;
430822Speter 	register long			increment;
431822Speter 
432822Speter 	enteredname = enterstring( name );
433822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
434822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
435822Speter 	    if ( tablep == NIL ) {
436822Speter #		ifdef DEBUG
437822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
438822Speter #		endif DEBUG
439822Speter 		tablep = ( struct symboltableinfo * )
440822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
441822Speter 		if ( tablep == NIL ) {
442822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
443822Speter 		}
444822Speter 		if ( symboltable == NIL ) {
445822Speter 		    symboltable = tablep;
446822Speter 		}
447822Speter 	    }
448822Speter 	    herep = &( tablep -> entry[ hashindex ] );
449822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
450822Speter 	    increment = 1;
451822Speter 	    do {
452822Speter #		ifdef DEBUG
453822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
454822Speter 			    , increment );
455822Speter #		endif DEBUG
456822Speter 		if ( *herep == NIL ) {
457822Speter 			/* empty */
458822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
459822Speter 			    /* too full, break for next table */
460822Speter 			break;
461822Speter 		    }
462822Speter 		    tablep -> used++;
463822Speter 		    *herep = symbolalloc();
464822Speter 		    ( *herep ) -> name = enteredname;
465822Speter 		    ( *herep ) -> lookup = NEW;
466822Speter #		    ifdef DEBUG
467822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
468822Speter 				, enteredname );
469822Speter #		    endif DEBUG
470822Speter 		    return *herep;
471822Speter 		}
472822Speter 		    /* a find? */
473822Speter 		if ( ( *herep ) -> name == enteredname ) {
474822Speter 		    ( *herep ) -> lookup = OLD;
475822Speter #		    ifdef DEBUG
476822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
477822Speter 				, enteredname );
478822Speter #		    endif DEBUG
479822Speter 		    return *herep;
480822Speter 		}
481822Speter 		herep += increment;
482822Speter 		if ( herep >= limitp ) {
483822Speter 		    herep -= SYMBOLPRIME;
484822Speter 		}
485822Speter 		increment += 2;
486822Speter 	    } while ( increment < SYMBOLPRIME );
487822Speter 	}
488822Speter     }
489822Speter 
490822Speter     /*
491822Speter      *	allocate a symbol from the dynamically allocated symbol table.
492822Speter      */
493822Speter struct symbol *
494822Speter symbolalloc()
495822Speter     {
496822Speter 	static struct symbol	*nextsymbol = NIL;
497822Speter 	static long		symbolsleft = 0;
498822Speter 	struct symbol		*newsymbol;
499822Speter 
500822Speter 	if ( symbolsleft <= 0 ) {
501822Speter #	    ifdef DEBUG
502822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
503822Speter #	    endif DEBUG
504822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
505822Speter 	    if ( nextsymbol == 0 ) {
506822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
507822Speter 	    }
508822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
509822Speter 	}
510822Speter 	newsymbol = nextsymbol;
511822Speter 	nextsymbol++;
512822Speter 	symbolsleft--;
513822Speter 	return newsymbol;
514822Speter     }
515822Speter 
516822Speter     /*
517822Speter      *	hash a string based on all of its characters.
518822Speter      */
519822Speter long
520822Speter hashstring( string )
521822Speter     char	*string;
522822Speter     {
523822Speter 	register char	*cp;
524822Speter 	register long	value;
525822Speter 
526822Speter 	value = 0;
527822Speter 	for ( cp = string ; *cp ; cp++ ) {
528822Speter 	    value = ( value * 2 ) + *cp;
529822Speter 	}
530822Speter 	return value;
531822Speter     }
532822Speter 
533822Speter     /*
534822Speter      *	quadratically hashed string table.
535822Speter      *	things are never deleted from the hash string table.
536822Speter      *	as more hash table is needed,
537822Speter      *	a new one is alloc'ed and chained to the end.
538822Speter      *	search is by rehashing within each table,
539822Speter      *	traversing chains to next table if unsuccessful.
540822Speter      */
541822Speter char *
542822Speter enterstring( string )
543822Speter     char	*string;
544822Speter     {
545822Speter 	static struct stringtableinfo	*stringtable = NIL;
546822Speter 	long				hashindex;
547822Speter 	register struct stringtableinfo	*tablep;
548822Speter 	register char			**herep;
549822Speter 	register char			**limitp;
550822Speter 	register long			increment;
551822Speter 
552822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
553822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
554822Speter 	    if ( tablep == NIL ) {
555822Speter #		ifdef DEBUG
556822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
557822Speter #		endif DEBUG
558822Speter 		tablep = ( struct stringtableinfo * )
559822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
560822Speter 		if ( tablep == NIL ) {
561822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
562822Speter 		}
563822Speter 		if ( stringtable == NIL ) {
564822Speter 		    stringtable = tablep;
565822Speter 		}
566822Speter 	    }
567822Speter 	    herep = &( tablep -> entry[ hashindex ] );
568822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
569822Speter 	    increment = 1;
570822Speter 	    do {
571822Speter #		ifdef DEBUG
572822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
573822Speter 			    , increment );
574822Speter #		endif DEBUG
575822Speter 		if ( *herep == NIL ) {
576822Speter 			/* empty */
577822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
578822Speter 			    /* too full, break for next table */
579822Speter 			break;
580822Speter 		    }
581822Speter 		    tablep -> used++;
582822Speter 		    *herep = charalloc( strlen( string ) );
583822Speter 		    strcpy( *herep , string );
584822Speter #		    ifdef DEBUG
585822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
586822Speter 				, *herep );
587822Speter #		    endif DEBUG
588822Speter 		    return *herep;
589822Speter 		}
590822Speter 		    /* quick, check the first chars and then the rest */
591822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
592822Speter #		    ifdef DEBUG
593822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
594822Speter 				, *herep );
595822Speter #		    endif DEBUG
596822Speter 		    return *herep;
597822Speter 		}
598822Speter 		herep += increment;
599822Speter 		if ( herep >= limitp ) {
600822Speter 		    herep -= STRINGPRIME;
601822Speter 		}
602822Speter 		increment += 2;
603822Speter 	    } while ( increment < STRINGPRIME );
604822Speter 	}
605822Speter     }
606822Speter 
607822Speter     /*
608822Speter      *	copy a string to the dynamically allocated character table.
609822Speter      */
610822Speter char *
611822Speter charalloc( length )
612822Speter     register long	length;
613822Speter     {
614822Speter 	static char	*nextchar = NIL;
615822Speter 	static long	charsleft = 0;
616822Speter 	register long	lengthplus1 = length + 1;
617822Speter 	register long	askfor;
618822Speter 	char		*newstring;
619822Speter 
620822Speter 	if ( charsleft < lengthplus1 ) {
621822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
622822Speter #	    ifdef DEBUG
623822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
624822Speter 			, askfor );
625822Speter #	    endif DEBUG
626822Speter 	    nextchar = ( char * ) malloc( askfor );
627822Speter 	    if ( nextchar == 0 ) {
628822Speter 		error( FATAL , "no room for %d characters" , askfor );
629822Speter 	    }
630822Speter 	    charsleft = askfor;
631822Speter 	}
632822Speter 	newstring = nextchar;
633822Speter 	nextchar += lengthplus1;
634822Speter 	charsleft -= lengthplus1;
635822Speter 	return newstring;
636822Speter     }
637822Speter 
638822Speter     /*
639822Speter      *	read an archive header for the next element
640822Speter      *	and find the offset of the one after this.
641822Speter      */
642822Speter BOOL
643822Speter nextelement( ofilep )
644822Speter     struct fileinfo	*ofilep;
645822Speter     {
646822Speter 	register char	*cp;
647822Speter 	register long	red;
648822Speter 	register off_t	arsize;
649822Speter 	struct ar_hdr	archdr;
650822Speter 
651822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
652822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
653822Speter 	if ( red != sizeof archdr ) {
654822Speter 	    return FALSE;
655822Speter 	}
656822Speter 	    /* null terminate the blank-padded name */
657822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
658822Speter 	*cp = '\0';
659822Speter 	while ( *--cp == ' ' ) {
660822Speter 	    *cp = '\0';
661822Speter 	}
662822Speter 	    /* set up the address of the beginning of next element */
663822Speter 	arsize = atol( archdr.ar_size );
664822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
665822Speter 	if ( arsize & 1 ) {
666822Speter 	    arsize += 1;
667822Speter 	}
668822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
669822Speter 	    /* say we had one */
670822Speter 	return TRUE;
671822Speter     }
672822Speter 
673822Speter     /*
674822Speter      *	variable number of arguments to error, like printf.
675822Speter      */
676822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
677822Speter     int		fatal;
678822Speter     char	*message;
679822Speter     {
680822Speter 	fprintf( stderr , "%s: " , program );
681822Speter 	fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 );
682822Speter 	fprintf( stderr , "\n" );
683822Speter 	if ( fatal == FATAL ) {
684822Speter 	    exit( 2 );
685822Speter 	}
686822Speter 	errors = 1;
687822Speter     }
688822Speter 
689822Speter     /*
690822Speter      *	find the last modify time of a file.
691822Speter      *	on error, return the current time.
692822Speter      */
693822Speter time_t
694822Speter mtime( filename )
695822Speter     char	*filename;
696822Speter     {
697822Speter 	struct stat	filestat;
698822Speter 
699822Speter #	ifdef DEBUG
700822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
701822Speter 		    , filename );
702822Speter #	endif DEBUG
703829Speter 	if ( stat( filename , &filestat ) != 0 ) {
704822Speter 	    error( WARNING , "%s: cannot open" , filename );
705822Speter 	    return ( (time_t) time( 0 ) );
706822Speter 	}
707822Speter 	return filestat.st_mtime;
708822Speter     }
709822Speter 
710822Speter char *
711822Speter classify( type )
712822Speter     unsigned char	type;
713822Speter     {
714822Speter 	switch ( type ) {
715822Speter 	    case N_PSO:
716822Speter 		return "source file";
717822Speter 	    case N_PSOL:
718822Speter 		return "include file";
719844Speter 	    case N_PGLABEL:
720822Speter 		return "label";
721844Speter 	    case N_PGCONST:
722822Speter 		return "constant";
723844Speter 	    case N_PGTYPE:
724822Speter 		return "type";
725822Speter 	    case N_PGVAR:
726822Speter 		return "variable";
727844Speter 	    case N_PGFUNC:
728822Speter 		return "function";
729844Speter 	    case N_PGPROC:
730822Speter 		return "procedure";
731844Speter 	    case N_PEFUNC:
732822Speter 		return "external function";
733844Speter 	    case N_PEPROC:
734822Speter 		return "external procedure";
735822Speter 	    default:
736822Speter 		return "unknown symbol";
737822Speter 	}
738822Speter     }
739