xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 829)
1822Speter     /* Copyright (c) 1980 Regents of the University of California */
2822Speter 
3*829Speter static	char sccsid[] = "@(#)pc3.c 1.2 09/02/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;
31822Speter      *	   - a type specifier;
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 
64822Speter char	program[] = "pc3";
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>
74822Speter #include "/usr/src/new/pc0/p.a.out.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 
88822Speter 	argc--;
89822Speter 	argv++;
90822Speter 	while ( argc-- ) {
91822Speter #	    ifdef DEBUG
92822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
93822Speter #	    endif DEBUG
94822Speter 	    ofile.name = *argv;
95822Speter 	    checkfile( &ofile );
96822Speter 	    argv++;
97822Speter 	}
98822Speter 	exit( errors );
99822Speter     }
100822Speter 
101822Speter     /*
102822Speter      *	check the namelist of a file, or all namelists of an archive.
103822Speter      */
104822Speter checkfile( ofilep )
105822Speter     struct fileinfo	*ofilep;
106822Speter     {
107822Speter 	union {
108822Speter 	    char	mag_armag[ SARMAG + 1 ];
109822Speter 	    struct exec	mag_exec;
110822Speter 	}		mag_un;
111822Speter 	int		red;
112822Speter 	struct stat	filestat;
113822Speter 
114822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
115822Speter 	if ( ofilep -> file == NULL ) {
116822Speter 	    error( WARNING , "cannot open: %s" , ofilep -> name );
117822Speter 	    return;
118822Speter 	}
119822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
120822Speter 	ofilep -> modtime = filestat.st_mtime;
121822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
122822Speter 	if ( red != sizeof mag_un ) {
123822Speter 	    error( WARNING , "cannot read header: %s" , ofilep -> name );
124822Speter 	    return;
125822Speter 	}
126822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
127822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
128822Speter 	    return;
129822Speter 	}
130822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
131822Speter 		/* archive, iterate through elements */
132822Speter #	    ifdef DEBUG
133822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
134822Speter #	    endif DEBUG
135822Speter 	    ofilep -> nextoffset = SARMAG;
136822Speter 	    while ( nextelement( ofilep ) ) {
137822Speter 		checknl( ofilep );
138822Speter 	    }
139822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
140822Speter 		/* not a file.o */
141822Speter 	    error( WARNING , "bad format: %s" , ofilep -> name );
142822Speter 	    return;
143822Speter 	} else {
144822Speter 		/* a file.o */
145822Speter #	    ifdef DEBUG
146822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
147822Speter #	    endif DEBUG
148822Speter 	    fseek( ofilep -> file , 0L , 0 );
149822Speter 	    ofilep -> nextoffset = filestat.st_size;
150822Speter 	    checknl( ofilep );
151822Speter 	}
152822Speter 	fclose( ofilep -> file );
153822Speter     }
154822Speter 
155822Speter     /*
156822Speter      *	check the namelist of this file for conflicts with
157822Speter      *	previously entered symbols.
158822Speter      */
159822Speter checknl( ofilep )
160822Speter     register struct fileinfo	*ofilep;
161822Speter     {
162822Speter 
163822Speter 	long			red;
164822Speter 	struct exec		aexec;
165822Speter 	off_t			symoff;
166822Speter 	long			numsyms;
167822Speter 	register struct nlist	*nlp;
168822Speter 	register char		*stringp;
169822Speter 	long			strsize;
170822Speter 	long			sym;
171822Speter 
172822Speter 	red = fread( (char *) &aexec , 1 , sizeof aexec , ofilep -> file );
173822Speter 	if ( red != sizeof aexec ) {
174822Speter 	    error( WARNING , "error reading struct exec: %s"
175822Speter 		    , ofilep -> name );
176822Speter 	    return;
177822Speter 	}
178822Speter 	if ( N_BADMAG( aexec ) ) {
179822Speter 	    return;
180822Speter 	}
181822Speter 	symoff = N_SYMOFF( aexec ) - sizeof aexec;
182822Speter 	fseek( ofilep -> file , symoff , 1 );
183822Speter 	numsyms = aexec.a_syms / sizeof ( struct nlist );
184822Speter 	if ( numsyms == 0 ) {
185822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
186822Speter 	    return;
187822Speter 	}
188822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
189822Speter 	if ( nlp == 0 ) {
190822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
191822Speter 	}
192822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
193822Speter 		    , ofilep -> file );
194822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
195822Speter 	    >= ofilep -> nextoffset ) {
196822Speter 	    error( WARNING , "no string table (old format .o?)"
197822Speter 		    , ofilep -> name );
198822Speter 	    return;
199822Speter 	}
200822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
201822Speter 		    , ofilep -> file );
202822Speter 	if ( red != 1 ) {
203822Speter 	    error( WARNING , "no string table (old format .o?)"
204822Speter 		    , ofilep -> name );
205822Speter 	    return;
206822Speter 	}
207822Speter 	stringp  = ( char * ) malloc( strsize );
208822Speter 	if ( stringp == 0 ) {
209822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
210822Speter 	}
211822Speter 	red = fread( stringp + sizeof strsize
212822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
213822Speter 	if ( red != 1 ) {
214822Speter 	    error( WARNING , "error reading string table: %s"
215822Speter 		    , ofilep -> name );
216822Speter 	}
217822Speter #	ifdef DEBUG
218822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
219822Speter 		    , ofilep -> name , numsyms );
220822Speter #	endif DEBUG
221822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
222822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
223822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
224822Speter 	    } else {
225822Speter 		nlp[ sym ].n_un.n_name = "";
226822Speter 	    }
227822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
228822Speter 	}
229822Speter 	if ( nlp ) {
230822Speter 	    free( nlp );
231822Speter 	}
232822Speter 	if ( stringp ) {
233822Speter 	    free( stringp );
234822Speter 	}
235822Speter     }
236822Speter 
237822Speter     /*
238822Speter      *	check a symbol.
239822Speter      *	look it up in the hashed symbol table,
240822Speter      *	entering it if necessary.
241822Speter      *	this maintains a state of which .p and .i files
242822Speter      *	it is currently in the midst from the nlist entries
243822Speter      *	for source and included files.
244822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
245822Speter      */
246822Speter checksymbol( nlp , ofilep )
247822Speter     struct nlist	*nlp;
248822Speter     struct fileinfo	*ofilep;
249822Speter     {
250822Speter 	static struct symbol	*pfilep = NIL;
251822Speter 	static struct symbol	*ifilep = NIL;
252822Speter 	register struct symbol	*symbolp;
253822Speter 
254822Speter #	ifdef DEBUG
255822Speter 	    if ( pfilep && ifilep ) {
256822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
257822Speter 			, pfilep -> name , ifilep -> name );
258822Speter 	    }
259822Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_type %x (%s)\n"
260822Speter 		    , nlp -> n_un.n_name , nlp -> n_type
261822Speter 		    , classify( nlp -> n_type ) );
262822Speter #	endif DEBUG
263822Speter 	switch ( nlp -> n_type ) {
264822Speter 	    case N_PGLAB:
265822Speter 	    case N_PGCON:
266822Speter 	    case N_PGTYP:
267822Speter 	    case N_PGVAR:
268822Speter 	    case N_PGFUN:
269822Speter 	    case N_PGPRC:
270822Speter 	    case N_PEFUN:
271822Speter 	    case N_PEPRC:
272822Speter 	    case N_PSO:
273822Speter 	    case N_PSOL:
274822Speter 		    symbolp = entersymbol( nlp -> n_un.n_name );
275822Speter 		    break;
276822Speter 	    default:
277822Speter 			/* don't care about the others */
278822Speter 		    return;
279822Speter 	}
280822Speter 	if ( symbolp -> lookup == NEW ) {
281822Speter #	    ifdef DEBUG
282822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
283822Speter 			, symbolp -> name );
284822Speter #	    endif DEBUG
285822Speter 	    symbolp -> type = nlp -> n_type;
286822Speter 	    switch ( symbolp -> type ) {
287822Speter 		case N_PGLAB:
288822Speter 		case N_PGCON:
289822Speter 		case N_PGTYP:
290822Speter 		case N_PGVAR:
291822Speter 		case N_PGFUN:
292822Speter 		case N_PGPRC:
293822Speter 			/* and fall through */
294822Speter 		case N_PEFUN:
295822Speter 		case N_PEPRC:
296822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
297822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
298822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
299822Speter 			if (  symbolp -> type != N_PEFUN
300822Speter 			   && symbolp -> type != N_PEPRC ) {
301822Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
302822Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
303822Speter 			} else {
304822Speter 			    symbolp -> sym_un.sym_str.rfilep = NIL;
305822Speter 			    symbolp -> sym_un.sym_str.rline = 0;
306822Speter 				/*
307822Speter 				 *	functions can only be declared external
308822Speter 				 *	in included files.
309822Speter 				 */
310822Speter 			    if ( pfilep == ifilep ) {
311822Speter 				error( WARNING
312822Speter 					, "%s, line %d: %s %s must be declared in included file"
313822Speter 					, pfilep -> name , nlp -> n_value
314822Speter 					, classify( symbolp -> type )
315822Speter 					, symbolp -> name );
316822Speter 			    }
317822Speter 			}
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
336822Speter 	    switch ( symbolp -> type ) {
337822Speter 		case N_PSO:
338822Speter 			    /*
339822Speter 			     *	finding a file again means you are back
340822Speter 			     *	in it after finishing an include file.
341822Speter 			     */
342822Speter 			pfilep = symbolp;
343822Speter 			/* and fall through */
344822Speter 		case N_PSOL:
345822Speter 			    /*
346822Speter 			     *	include files can be seen more than once,
347822Speter 			     *	but they still have to be timechecked.
348822Speter 			     *	(this will complain twice for out of date
349822Speter 			     *	include files which include other files.
350822Speter 			     *	sigh.)
351822Speter 			     */
352822Speter 			ifilep = symbolp;
353822Speter 			if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
354822Speter 			    error( WARNING , "%s is out of date with %s"
355822Speter 				    , ofilep -> name , symbolp -> name );
356822Speter 			}
357822Speter 			return;
358822Speter 		case N_PEFUN:
359822Speter 		case N_PEPRC:
360822Speter 			    /*
361822Speter 			     *	we may see any number of external declarations,
362822Speter 			     *	but they all have to come
363822Speter 			     *	from the same include file.
364822Speter 			     */
365822Speter 			if (   nlp -> n_type == N_PEFUN
366822Speter 			    || nlp -> n_type == N_PEPRC ) {
367822Speter 			    goto included;
368822Speter 			}
369822Speter 			    /*
370822Speter 			     *	an external function can be resolved by
371822Speter 			     *	the resolution of the function
372822Speter 			     *	if the resolving file
373822Speter 			     *	included the external declaration.
374822Speter 			     */
375822Speter 			if (    (  symbolp -> type == N_PEFUN
376822Speter 				&& nlp -> n_type != N_PGFUN )
377822Speter 			    ||  (  symbolp -> type == N_PEPRC
378822Speter 				&& nlp -> n_type != N_PGPRC )
379822Speter 			    || symbolp -> sym_un.sym_str.fromp != pfilep ) {
380822Speter 			    break;
381822Speter 			}
382822Speter 			    /*
383822Speter 			     *	an external function can only be resolved once.
384822Speter 			     */
385822Speter 			if ( symbolp -> sym_un.sym_str.rfilep != NIL ) {
386822Speter 			    break;
387822Speter 			}
388822Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
389822Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
390822Speter 			return;
391822Speter 		case N_PGFUN:
392822Speter 		case N_PGPRC:
393822Speter 			    /*
394822Speter 			     *	functions may not be seen more than once.
395822Speter 			     *	the loader will complain about
396822Speter 			     *	`multiply defined', but we can, too.
397822Speter 			     */
398822Speter 			break;
399822Speter 		case N_PGLAB:
400822Speter 		case N_PGCON:
401822Speter 		case N_PGTYP:
402822Speter 		case N_PGVAR:
403822Speter 			    /*
404822Speter 			     *	labels, constants, types, variables
405822Speter 			     *	and external declarations
406822Speter 			     *	may be seen as many times as they want,
407822Speter 			     *	as long as they come from the same include file.
408822Speter 			     *	make it look like they come from this .p file.
409822Speter 			     */
410822Speter included:
411822Speter 			if (  nlp -> n_type != symbolp -> type
412822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
413822Speter 			    break;
414822Speter 			}
415822Speter 			symbolp -> sym_un.sym_str.fromp = pfilep;
416822Speter 			return;
417822Speter 	    }
418822Speter 		/*
419822Speter 		 *	this is the breaks
420822Speter 		 */
421822Speter 	    error( WARNING , "%s, line %d: %s already defined (%s, line %d)."
422822Speter 		    , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
423822Speter 		    , symbolp -> sym_un.sym_str.rfilep -> name
424822Speter 		    , symbolp -> sym_un.sym_str.rline );
425822Speter 	}
426822Speter     }
427822Speter 
428822Speter     /*
429822Speter      *	quadratically hashed symbol table.
430822Speter      *	things are never deleted from the hash symbol table.
431822Speter      *	as more hash table is needed,
432822Speter      *	a new one is alloc'ed and chained to the end.
433822Speter      *	search is by rehashing within each table,
434822Speter      *	traversing chains to next table if unsuccessful.
435822Speter      */
436822Speter 
437822Speter struct symbol *
438822Speter entersymbol( name )
439822Speter     char	*name;
440822Speter     {
441822Speter 	static struct symboltableinfo	*symboltable = NIL;
442822Speter 	char				*enteredname;
443822Speter 	long				hashindex;
444822Speter 	register struct symboltableinfo	*tablep;
445822Speter 	register struct symbol		**herep;
446822Speter 	register struct symbol		**limitp;
447822Speter 	register long			increment;
448822Speter 
449822Speter 	enteredname = enterstring( name );
450822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
451822Speter 	for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
452822Speter 	    if ( tablep == NIL ) {
453822Speter #		ifdef DEBUG
454822Speter 		    fprintf( stderr , "[entersymbol] calloc\n" );
455822Speter #		endif DEBUG
456822Speter 		tablep = ( struct symboltableinfo * )
457822Speter 			    calloc( sizeof ( struct symboltableinfo ) , 1 );
458822Speter 		if ( tablep == NIL ) {
459822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
460822Speter 		}
461822Speter 		if ( symboltable == NIL ) {
462822Speter 		    symboltable = tablep;
463822Speter 		}
464822Speter 	    }
465822Speter 	    herep = &( tablep -> entry[ hashindex ] );
466822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
467822Speter 	    increment = 1;
468822Speter 	    do {
469822Speter #		ifdef DEBUG
470822Speter 		    fprintf( stderr , "[entersymbol] increment %d\n"
471822Speter 			    , increment );
472822Speter #		endif DEBUG
473822Speter 		if ( *herep == NIL ) {
474822Speter 			/* empty */
475822Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
476822Speter 			    /* too full, break for next table */
477822Speter 			break;
478822Speter 		    }
479822Speter 		    tablep -> used++;
480822Speter 		    *herep = symbolalloc();
481822Speter 		    ( *herep ) -> name = enteredname;
482822Speter 		    ( *herep ) -> lookup = NEW;
483822Speter #		    ifdef DEBUG
484822Speter 			fprintf( stderr , "[entersymbol] name %s NEW\n"
485822Speter 				, enteredname );
486822Speter #		    endif DEBUG
487822Speter 		    return *herep;
488822Speter 		}
489822Speter 		    /* a find? */
490822Speter 		if ( ( *herep ) -> name == enteredname ) {
491822Speter 		    ( *herep ) -> lookup = OLD;
492822Speter #		    ifdef DEBUG
493822Speter 			fprintf( stderr , "[entersymbol] name %s OLD\n"
494822Speter 				, enteredname );
495822Speter #		    endif DEBUG
496822Speter 		    return *herep;
497822Speter 		}
498822Speter 		herep += increment;
499822Speter 		if ( herep >= limitp ) {
500822Speter 		    herep -= SYMBOLPRIME;
501822Speter 		}
502822Speter 		increment += 2;
503822Speter 	    } while ( increment < SYMBOLPRIME );
504822Speter 	}
505822Speter     }
506822Speter 
507822Speter     /*
508822Speter      *	allocate a symbol from the dynamically allocated symbol table.
509822Speter      */
510822Speter 
511822Speter struct symbol *
512822Speter symbolalloc()
513822Speter     {
514822Speter 	static struct symbol	*nextsymbol = NIL;
515822Speter 	static long		symbolsleft = 0;
516822Speter 	struct symbol		*newsymbol;
517822Speter 
518822Speter 	if ( symbolsleft <= 0 ) {
519822Speter #	    ifdef DEBUG
520822Speter 		fprintf( stderr , "[symbolalloc] malloc\n" );
521822Speter #	    endif DEBUG
522822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
523822Speter 	    if ( nextsymbol == 0 ) {
524822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
525822Speter 	    }
526822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
527822Speter 	}
528822Speter 	newsymbol = nextsymbol;
529822Speter 	nextsymbol++;
530822Speter 	symbolsleft--;
531822Speter 	return newsymbol;
532822Speter     }
533822Speter 
534822Speter     /*
535822Speter      *	hash a string based on all of its characters.
536822Speter      */
537822Speter long
538822Speter hashstring( string )
539822Speter     char	*string;
540822Speter     {
541822Speter 	register char	*cp;
542822Speter 	register long	value;
543822Speter 
544822Speter 	value = 0;
545822Speter 	for ( cp = string ; *cp ; cp++ ) {
546822Speter 	    value = ( value * 2 ) + *cp;
547822Speter 	}
548822Speter 	return value;
549822Speter     }
550822Speter 
551822Speter     /*
552822Speter      *	quadratically hashed string table.
553822Speter      *	things are never deleted from the hash string table.
554822Speter      *	as more hash table is needed,
555822Speter      *	a new one is alloc'ed and chained to the end.
556822Speter      *	search is by rehashing within each table,
557822Speter      *	traversing chains to next table if unsuccessful.
558822Speter      */
559822Speter 
560822Speter char *
561822Speter enterstring( string )
562822Speter     char	*string;
563822Speter     {
564822Speter 	static struct stringtableinfo	*stringtable = NIL;
565822Speter 	long				hashindex;
566822Speter 	register struct stringtableinfo	*tablep;
567822Speter 	register char			**herep;
568822Speter 	register char			**limitp;
569822Speter 	register long			increment;
570822Speter 
571822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
572822Speter 	for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
573822Speter 	    if ( tablep == NIL ) {
574822Speter #		ifdef DEBUG
575822Speter 		    fprintf( stderr , "[enterstring] calloc\n" );
576822Speter #		endif DEBUG
577822Speter 		tablep = ( struct stringtableinfo * )
578822Speter 			    calloc( sizeof ( struct stringtableinfo ) , 1 );
579822Speter 		if ( tablep == NIL ) {
580822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
581822Speter 		}
582822Speter 		if ( stringtable == NIL ) {
583822Speter 		    stringtable = tablep;
584822Speter 		}
585822Speter 	    }
586822Speter 	    herep = &( tablep -> entry[ hashindex ] );
587822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
588822Speter 	    increment = 1;
589822Speter 	    do {
590822Speter #		ifdef DEBUG
591822Speter 		    fprintf( stderr , "[enterstring] increment %d\n"
592822Speter 			    , increment );
593822Speter #		endif DEBUG
594822Speter 		if ( *herep == NIL ) {
595822Speter 			/* empty */
596822Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
597822Speter 			    /* too full, break for next table */
598822Speter 			break;
599822Speter 		    }
600822Speter 		    tablep -> used++;
601822Speter 		    *herep = charalloc( strlen( string ) );
602822Speter 		    strcpy( *herep , string );
603822Speter #		    ifdef DEBUG
604822Speter 			fprintf( stderr , "[enterstring] string %s copied\n"
605822Speter 				, *herep );
606822Speter #		    endif DEBUG
607822Speter 		    return *herep;
608822Speter 		}
609822Speter 		    /* quick, check the first chars and then the rest */
610822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
611822Speter #		    ifdef DEBUG
612822Speter 			fprintf( stderr , "[enterstring] string %s found\n"
613822Speter 				, *herep );
614822Speter #		    endif DEBUG
615822Speter 		    return *herep;
616822Speter 		}
617822Speter 		herep += increment;
618822Speter 		if ( herep >= limitp ) {
619822Speter 		    herep -= STRINGPRIME;
620822Speter 		}
621822Speter 		increment += 2;
622822Speter 	    } while ( increment < STRINGPRIME );
623822Speter 	}
624822Speter     }
625822Speter 
626822Speter     /*
627822Speter      *	copy a string to the dynamically allocated character table.
628822Speter      */
629822Speter 
630822Speter char *
631822Speter charalloc( length )
632822Speter     register long	length;
633822Speter     {
634822Speter 	static char	*nextchar = NIL;
635822Speter 	static long	charsleft = 0;
636822Speter 	register long	lengthplus1 = length + 1;
637822Speter 	register long	askfor;
638822Speter 	char		*newstring;
639822Speter 
640822Speter 	if ( charsleft < lengthplus1 ) {
641822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
642822Speter #	    ifdef DEBUG
643822Speter 		fprintf( stderr , "[charalloc] malloc( %d )\n"
644822Speter 			, askfor );
645822Speter #	    endif DEBUG
646822Speter 	    nextchar = ( char * ) malloc( askfor );
647822Speter 	    if ( nextchar == 0 ) {
648822Speter 		error( FATAL , "no room for %d characters" , askfor );
649822Speter 	    }
650822Speter 	    charsleft = askfor;
651822Speter 	}
652822Speter 	newstring = nextchar;
653822Speter 	nextchar += lengthplus1;
654822Speter 	charsleft -= lengthplus1;
655822Speter 	return newstring;
656822Speter     }
657822Speter 
658822Speter     /*
659822Speter      *	read an archive header for the next element
660822Speter      *	and find the offset of the one after this.
661822Speter      */
662822Speter BOOL
663822Speter nextelement( ofilep )
664822Speter     struct fileinfo	*ofilep;
665822Speter     {
666822Speter 	register char	*cp;
667822Speter 	register long	red;
668822Speter 	register off_t	arsize;
669822Speter 	struct ar_hdr	archdr;
670822Speter 
671822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
672822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
673822Speter 	if ( red != sizeof archdr ) {
674822Speter 	    return FALSE;
675822Speter 	}
676822Speter 	    /* null terminate the blank-padded name */
677822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
678822Speter 	*cp = '\0';
679822Speter 	while ( *--cp == ' ' ) {
680822Speter 	    *cp = '\0';
681822Speter 	}
682822Speter 	    /* set up the address of the beginning of next element */
683822Speter 	arsize = atol( archdr.ar_size );
684822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
685822Speter 	if ( arsize & 1 ) {
686822Speter 	    arsize += 1;
687822Speter 	}
688822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
689822Speter 	    /* say we had one */
690822Speter 	return TRUE;
691822Speter     }
692822Speter 
693822Speter     /*
694822Speter      *	variable number of arguments to error, like printf.
695822Speter      */
696822Speter error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
697822Speter     int		fatal;
698822Speter     char	*message;
699822Speter     {
700822Speter 	fprintf( stderr , "%s: " , program );
701822Speter 	fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 );
702822Speter 	fprintf( stderr , "\n" );
703822Speter 	if ( fatal == FATAL ) {
704822Speter 	    exit( 2 );
705822Speter 	}
706822Speter 	errors = 1;
707822Speter     }
708822Speter 
709822Speter     /*
710822Speter      *	find the last modify time of a file.
711822Speter      *	on error, return the current time.
712822Speter      */
713822Speter time_t
714822Speter mtime( filename )
715822Speter     char	*filename;
716822Speter     {
717822Speter 	struct stat	filestat;
718822Speter 
719822Speter #	ifdef DEBUG
720822Speter 	    fprintf( stderr , "[mtime] filename %s\n"
721822Speter 		    , filename );
722822Speter #	endif DEBUG
723*829Speter 	if ( stat( filename , &filestat ) != 0 ) {
724822Speter 	    error( WARNING , "%s: cannot open" , filename );
725822Speter 	    return ( (time_t) time( 0 ) );
726822Speter 	}
727822Speter 	return filestat.st_mtime;
728822Speter     }
729822Speter 
730822Speter char *
731822Speter classify( type )
732822Speter     unsigned char	type;
733822Speter     {
734822Speter 	switch ( type ) {
735822Speter 	    case N_PSO:
736822Speter 		return "source file";
737822Speter 	    case N_PSOL:
738822Speter 		return "include file";
739822Speter 	    case N_PGLAB:
740822Speter 		return "label";
741822Speter 	    case N_PGCON:
742822Speter 		return "constant";
743822Speter 	    case N_PGTYP:
744822Speter 		return "type";
745822Speter 	    case N_PGVAR:
746822Speter 		return "variable";
747822Speter 	    case N_PGFUN:
748822Speter 		return "function";
749822Speter 	    case N_PGPRC:
750822Speter 		return "procedure";
751822Speter 	    case N_PEFUN:
752822Speter 		return "external function";
753822Speter 	    case N_PEPRC:
754822Speter 		return "external procedure";
755822Speter 	    default:
756822Speter 		return "unknown symbol";
757822Speter 	}
758822Speter     }
759