148061Sbostic /*-
2*62113Sbostic * Copyright (c) 1980, 1982, 1983, 1993
3*62113Sbostic * The Regents of the University of California. All rights reserved.
448061Sbostic *
548061Sbostic * %sccs.include.redist.c%
622261Sdist */
722261Sdist
813617Ssam #ifndef lint
9*62113Sbostic static char copyright[] =
10*62113Sbostic "@(#) Copyright (c) 1980, 1982, 1983, 1993\n\
11*62113Sbostic The Regents of the University of California. All rights reserved.\n";
1248061Sbostic #endif /* not lint */
13822Speter
1422261Sdist #ifndef lint
15*62113Sbostic static char sccsid[] = "@(#)pc3.c 8.1 (Berkeley) 06/06/93";
1648061Sbostic #endif /* not lint */
1722261Sdist
18822Speter /*
19822Speter * Pc3 is a pass in the Berkeley Pascal compilation
20822Speter * process that is performed just prior to linking Pascal
21822Speter * object files. Its purpose is to enforce the rules of
22822Speter * separate compilation for Berkeley Pascal. Pc3 is called
23822Speter * with the same argument list of object files that is sent to
24822Speter * the loader. These checks are performed by pc3 by examining
25822Speter * the symbol tables of the object files:
2614129Speter * (1) All .o files must be up to date with respect to the
2714129Speter * runtime libraries.
28822Speter * (2) Each global Pascal symbol (label, constant, type,
29822Speter * variable, procedure, or function name) must be uniquely
30822Speter * declared, i.e. declared in only one included file or
31822Speter * source file.
32822Speter * (3) Each external function (or procedure) may be resolved
33822Speter * at most once in a source file which included the
34822Speter * external declaration of the function.
35822Speter *
36822Speter * The symbol table of each object file is scanned and
37822Speter * each global Pascal symbol is placed in a hashed symbol
38822Speter * table. The Pascal compiler has been modified to emit all
39822Speter * Pascal global symbols to the object file symbol table. The
40822Speter * information stored in the symbol table for each such symbol
41822Speter * is:
42822Speter *
43822Speter * - the name of the symbol;
44844Speter * - a subtype descriptor;
45822Speter * - the file which logically contains the declaration of
4614129Speter * the symbol or which caused the inclusion of an include file.
4714129Speter * - for included files:
4814129Speter * - a checksum;
4914129Speter * - for symbols:
5014129Speter * - the file which textually contains the declaration of
5114129Speter * the symbol (possibly an include file);
5214129Speter * - the line number at which the symbol is declared;
5314129Speter * - the file which contains the resolution of the symbol.
5414129Speter * - the line number at which the symbol is resolved;
55822Speter *
56822Speter * If a symbol has been previously entered into the symbol
57822Speter * table, a check is made that the current declaration is of
58822Speter * the same type and from the same include file as the previous
59822Speter * one. Except for files and functions and procedures, it is
60822Speter * an error for a symbol declaration to be encountered more
61822Speter * than once, unless the re-declarations come from the same
62822Speter * included file as the original.
63822Speter *
64822Speter * As an include file symbol is encountered in a source
65822Speter * file, the symbol table entry of each symbol declared in that
66822Speter * include file is modified to reflect its new logical
67822Speter * inclusion in the source file. File symbols are also
68822Speter * encountered as an included file ends, signaling the
69822Speter * continuation of the enclosing file.
70822Speter *
71822Speter * Functions and procedures which have been declared
72822Speter * external may be resolved by declarations from source files
73822Speter * which included the external declaration of the function.
74822Speter * Functions and procedures may be resolved at most once across
75822Speter * a set of object files. The loader will complain if a
76822Speter * function is not resolved at least once.
77822Speter */
78822Speter
79832Speter char program[] = "pc";
80822Speter
81822Speter #include <sys/types.h>
8213617Ssam #include <sys/stat.h>
83822Speter #include <ar.h>
84822Speter #include <stdio.h>
85822Speter #include <ctype.h>
86822Speter #include <a.out.h>
87822Speter #include <stab.h>
88858Speter #include "pstab.h"
89822Speter #include "pc3.h"
90822Speter
917598Speter int errors = NONE;
927598Speter BOOL wflag = FALSE;
93822Speter
94822Speter /*
95822Speter * check each of the argument .o files (or archives of .o files).
96822Speter */
main(argc,argv)97822Speter main( argc , argv )
98822Speter int argc;
99822Speter char **argv;
100822Speter {
101822Speter struct fileinfo ofile;
102822Speter
1037598Speter for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) {
1047598Speter (*argv)++;
1057598Speter switch ( **argv ) {
1067598Speter default:
1077598Speter error( FATAL , "pc3: bad flag -%c\n" , **argv );
1087598Speter case 'w':
1097598Speter wflag = TRUE;
1107598Speter break;
1117598Speter }
1127598Speter }
1137598Speter for ( /* void */ ; *argv != 0 ; argv++ ) {
114822Speter # ifdef DEBUG
115822Speter fprintf( stderr , "[main] *argv = %s\n" , *argv );
116822Speter # endif DEBUG
117822Speter ofile.name = *argv;
118822Speter checkfile( &ofile );
119822Speter }
120822Speter exit( errors );
121822Speter }
122822Speter
123822Speter /*
124822Speter * check the namelist of a file, or all namelists of an archive.
125822Speter */
126822Speter checkfile( ofilep )
127822Speter struct fileinfo *ofilep;
128822Speter {
129822Speter union {
130822Speter char mag_armag[ SARMAG + 1 ];
131822Speter struct exec mag_exec;
132822Speter } mag_un;
133822Speter int red;
134822Speter struct stat filestat;
135822Speter
136822Speter ofilep -> file = fopen( ofilep -> name , "r" );
137822Speter if ( ofilep -> file == NULL ) {
1387598Speter error( ERROR , "cannot open: %s" , ofilep -> name );
139822Speter return;
140822Speter }
141822Speter fstat( fileno( ofilep -> file ) , &filestat );
142822Speter red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
143822Speter if ( red != sizeof mag_un ) {
1447598Speter error( ERROR , "cannot read header: %s" , ofilep -> name );
145822Speter return;
146822Speter }
147822Speter if ( mag_un.mag_exec.a_magic == OARMAG ) {
148822Speter error( WARNING , "old archive: %s" , ofilep -> name );
149822Speter return;
150822Speter }
151822Speter if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
152822Speter /* archive, iterate through elements */
153822Speter # ifdef DEBUG
154822Speter fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
155822Speter # endif DEBUG
156822Speter ofilep -> nextoffset = SARMAG;
157822Speter while ( nextelement( ofilep ) ) {
158822Speter checknl( ofilep );
159822Speter }
160822Speter } else if ( N_BADMAG( mag_un.mag_exec ) ) {
161822Speter /* not a file.o */
1627598Speter error( ERROR , "bad format: %s" , ofilep -> name );
163822Speter return;
164822Speter } else {
165822Speter /* a file.o */
166822Speter # ifdef DEBUG
167822Speter fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
168822Speter # endif DEBUG
169822Speter fseek( ofilep -> file , 0L , 0 );
170822Speter ofilep -> nextoffset = filestat.st_size;
171822Speter checknl( ofilep );
172822Speter }
173822Speter fclose( ofilep -> file );
174822Speter }
175822Speter
176822Speter /*
177822Speter * check the namelist of this file for conflicts with
178822Speter * previously entered symbols.
179822Speter */
checknl(ofilep)180822Speter checknl( ofilep )
181822Speter register struct fileinfo *ofilep;
182822Speter {
183822Speter
184822Speter long red;
185831Speter struct exec oexec;
186822Speter off_t symoff;
187822Speter long numsyms;
188822Speter register struct nlist *nlp;
189822Speter register char *stringp;
190822Speter long strsize;
191822Speter long sym;
192822Speter
193831Speter red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
194831Speter if ( red != sizeof oexec ) {
1957598Speter error( ERROR , "error reading struct exec: %s"
196822Speter , ofilep -> name );
197822Speter return;
198822Speter }
199831Speter if ( N_BADMAG( oexec ) ) {
200822Speter return;
201822Speter }
202831Speter symoff = N_SYMOFF( oexec ) - sizeof oexec;
203822Speter fseek( ofilep -> file , symoff , 1 );
204831Speter numsyms = oexec.a_syms / sizeof ( struct nlist );
205822Speter if ( numsyms == 0 ) {
206822Speter error( WARNING , "no name list: %s" , ofilep -> name );
207822Speter return;
208822Speter }
209822Speter nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
210822Speter if ( nlp == 0 ) {
211822Speter error( FATAL , "no room for %d nlists" , numsyms );
212822Speter }
213822Speter red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
214822Speter , ofilep -> file );
215822Speter if ( ftell( ofilep -> file ) + sizeof ( off_t )
216822Speter >= ofilep -> nextoffset ) {
217822Speter error( WARNING , "no string table (old format .o?)"
218822Speter , ofilep -> name );
219822Speter return;
220822Speter }
221822Speter red = fread( (char *) &strsize , sizeof strsize , 1
222822Speter , ofilep -> file );
223822Speter if ( red != 1 ) {
224822Speter error( WARNING , "no string table (old format .o?)"
225822Speter , ofilep -> name );
226822Speter return;
227822Speter }
228822Speter stringp = ( char * ) malloc( strsize );
229822Speter if ( stringp == 0 ) {
230822Speter error( FATAL , "no room for %d bytes of strings" , strsize );
231822Speter }
232822Speter red = fread( stringp + sizeof strsize
233822Speter , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
234822Speter if ( red != 1 ) {
235822Speter error( WARNING , "error reading string table: %s"
236822Speter , ofilep -> name );
237822Speter }
238822Speter # ifdef DEBUG
239822Speter fprintf( stderr , "[checknl] %s: %d symbols\n"
240822Speter , ofilep -> name , numsyms );
241822Speter # endif DEBUG
242822Speter for ( sym = 0 ; sym < numsyms ; sym++) {
243822Speter if ( nlp[ sym ].n_un.n_strx ) {
244822Speter nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
245822Speter } else {
246822Speter nlp[ sym ].n_un.n_name = "";
247822Speter }
248822Speter checksymbol( &nlp[ sym ] , ofilep );
249822Speter }
250822Speter if ( nlp ) {
251822Speter free( nlp );
252822Speter }
253822Speter if ( stringp ) {
254822Speter free( stringp );
255822Speter }
256822Speter }
257822Speter
258822Speter /*
259822Speter * check a symbol.
260822Speter * look it up in the hashed symbol table,
261822Speter * entering it if necessary.
262822Speter * this maintains a state of which .p and .i files
263822Speter * it is currently in the midst from the nlist entries
264822Speter * for source and included files.
265822Speter * if we are inside a .p but not a .i, pfilep == ifilep.
266822Speter */
267822Speter checksymbol( nlp , ofilep )
268822Speter struct nlist *nlp;
269822Speter struct fileinfo *ofilep;
270822Speter {
271822Speter static struct symbol *pfilep = NIL;
272822Speter static struct symbol *ifilep = NIL;
273822Speter register struct symbol *symbolp;
2747601Speter int errtype;
275822Speter
276822Speter # ifdef DEBUG
277822Speter if ( pfilep && ifilep ) {
278822Speter fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
279822Speter , pfilep -> name , ifilep -> name );
280822Speter }
281844Speter fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
282844Speter , nlp -> n_un.n_name , nlp -> n_desc
283844Speter , classify( nlp -> n_desc ) );
284822Speter # endif DEBUG
285844Speter if ( nlp -> n_type != N_PC ) {
286844Speter /* don't care about the others */
287844Speter return;
288822Speter }
289844Speter symbolp = entersymbol( nlp -> n_un.n_name );
290822Speter if ( symbolp -> lookup == NEW ) {
291822Speter # ifdef DEBUG
292822Speter fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
293822Speter , symbolp -> name );
294822Speter # endif DEBUG
295844Speter symbolp -> desc = nlp -> n_desc;
29614129Speter symbolp -> fromp = pfilep;
297844Speter switch ( symbolp -> desc ) {
2987550Speter default:
2997550Speter error( FATAL , "panic: [checksymbol] NEW" );
300844Speter case N_PGLABEL:
301844Speter case N_PGCONST:
302844Speter case N_PGTYPE:
303822Speter case N_PGVAR:
304844Speter case N_PGFUNC:
305844Speter case N_PGPROC:
3067601Speter case N_PLDATA:
3077601Speter case N_PLTEXT:
308831Speter symbolp -> sym_un.sym_str.rfilep = ifilep;
309831Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value;
310831Speter symbolp -> sym_un.sym_str.fromi = ifilep;
311831Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value;
312831Speter return;
313844Speter case N_PEFUNC:
314844Speter case N_PEPROC:
315831Speter symbolp -> sym_un.sym_str.rfilep = NIL;
316831Speter symbolp -> sym_un.sym_str.rline = 0;
317831Speter /*
318831Speter * functions can only be declared external
319831Speter * in included files.
320831Speter */
321831Speter if ( pfilep == ifilep ) {
322831Speter error( WARNING
323831Speter , "%s, line %d: %s %s must be declared in included file"
324831Speter , pfilep -> name , nlp -> n_value
325844Speter , classify( symbolp -> desc )
326831Speter , symbolp -> name );
327831Speter }
328822Speter symbolp -> sym_un.sym_str.fromi = ifilep;
329822Speter symbolp -> sym_un.sym_str.iline = nlp -> n_value;
330822Speter return;
331822Speter case N_PSO:
33214129Speter if ( nlp -> n_value < N_FLAGCHECKSUM ) {
33314129Speter error( WARNING,
33414129Speter "%s is out of date and should be recompiled",
33514129Speter ofilep -> name );
33614129Speter }
337822Speter pfilep = symbolp;
33814129Speter ifilep = symbolp;
33914129Speter symbolp -> sym_un.checksum = N_FLAGCHECKSUM;
34014129Speter return;
341822Speter case N_PSOL:
342822Speter ifilep = symbolp;
34314129Speter symbolp -> sym_un.checksum = nlp -> n_value;
344822Speter return;
345822Speter }
346822Speter } else {
347822Speter # ifdef DEBUG
348822Speter fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
349822Speter , symbolp -> name );
350822Speter # endif DEBUG
3517601Speter errtype = ERROR;
352844Speter switch ( symbolp -> desc ) {
3537550Speter default:
3547550Speter error( FATAL , "panic [checksymbol] OLD" );
35514129Speter return;
356822Speter case N_PSO:
357822Speter /*
358822Speter * finding a file again means you are back
359822Speter * in it after finishing an include file.
360822Speter */
36114129Speter if ( symbolp -> desc != nlp -> n_desc ) {
36214129Speter error( FATAL , "panic [checksymbol] PSO" );
36314129Speter return;
36414129Speter }
365822Speter pfilep = symbolp;
36614129Speter ifilep = symbolp;
36714129Speter return;
368822Speter case N_PSOL:
369822Speter /*
370822Speter * include files can be seen more than once,
37114129Speter * but their checksums are checked if they are
37214129Speter * greater than N_FLAGCHECKSUM.
37314129Speter * PSOL's are seen with checksums as the
37414129Speter * include file is entered, and with
37514129Speter * N_FLAGCHECKSUM as we are back in an
37614129Speter * included file from a nested include.
377822Speter */
37814129Speter if ( symbolp -> desc != nlp -> n_desc ) {
37914129Speter error( FATAL , "panic [checksymbol] PSOL" );
38014129Speter return;
38114129Speter }
38214129Speter if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM
38314129Speter && (unsigned) nlp -> n_value > N_FLAGCHECKSUM
38414129Speter && symbolp -> sym_un.checksum != nlp -> n_value ) {
38514129Speter error( ERROR,
38614129Speter "%s included in %s differs from %s included in %s",
38714129Speter symbolp -> name, pfilep -> name,
38814129Speter symbolp -> name, symbolp -> fromp -> name );
38914129Speter }
390822Speter ifilep = symbolp;
391822Speter return;
392844Speter case N_PEFUNC:
393844Speter case N_PEPROC:
394822Speter /*
3957550Speter * this might be the resolution of the external
3967550Speter * has to match func/proc of external
3977550Speter * and has to have included external
3987550Speter * and has to not have been previously resolved.
399822Speter */
4007550Speter if ( ( ( symbolp -> desc == N_PEFUNC
4017550Speter && nlp -> n_desc == N_PGFUNC )
4027550Speter || ( symbolp -> desc == N_PEPROC
4037550Speter && nlp -> n_desc == N_PGPROC ) )
40414129Speter && ( symbolp -> fromp == pfilep )
4057550Speter && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
4067550Speter /*
4077550Speter * resolve external
4087550Speter */
4097550Speter # ifdef DEBUG
4107550Speter fprintf( stderr , "[checksymbol] resolving external\n" );
4117550Speter # endif DEBUG
4127550Speter symbolp -> sym_un.sym_str.rfilep = ifilep;
4137550Speter symbolp -> sym_un.sym_str.rline = nlp -> n_value;
4147550Speter return;
415822Speter }
416822Speter /*
4177550Speter * otherwise, it might be another external,
4187550Speter * which is okay if it's
4197550Speter * the same type and from the same include file
420822Speter */
4217550Speter if ( ( ( symbolp -> desc == N_PEFUNC
4227550Speter && nlp -> n_desc == N_PEFUNC )
4237550Speter || ( symbolp -> desc == N_PEPROC
4247550Speter && nlp -> n_desc == N_PEPROC ) )
4257550Speter && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
4267550Speter /*
4277550Speter * just another pretty external
4287550Speter * make it look like it comes from here.
4297550Speter */
4307550Speter # ifdef DEBUG
4317550Speter fprintf( stderr , "[checksymbol] just another pretty external\n" );
4327550Speter # endif DEBUG
43314129Speter symbolp -> fromp = pfilep;
4347550Speter return;
435822Speter }
436822Speter /*
4377550Speter * something is wrong
4387598Speter * if it's not resolved, use the header file
4397598Speter * otherwise, it's just a regular error
440822Speter */
4417598Speter if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
4427598Speter error( ERROR ,
4437601Speter "%s, line %d: %s is already defined\n\t(%s, line %d)." ,
4447598Speter ifilep -> name , nlp -> n_value ,
4457598Speter nlp -> n_un.n_name ,
4467598Speter symbolp -> sym_un.sym_str.fromi -> name ,
4477598Speter symbolp -> sym_un.sym_str.iline );
4487598Speter return;
4497598Speter }
4507598Speter break;
451844Speter case N_PGFUNC:
452844Speter case N_PGPROC:
453822Speter /*
454822Speter * functions may not be seen more than once.
455822Speter * the loader will complain about
456822Speter * `multiply defined', but we can, too.
457822Speter */
458822Speter break;
459844Speter case N_PGLABEL:
460844Speter case N_PGCONST:
461844Speter case N_PGTYPE:
462822Speter case N_PGVAR:
463822Speter /*
464822Speter * labels, constants, types, variables
465822Speter * and external declarations
466822Speter * may be seen as many times as they want,
467822Speter * as long as they come from the same include file.
468822Speter * make it look like they come from this .p file.
469822Speter */
470822Speter included:
471844Speter if ( nlp -> n_desc != symbolp -> desc
472822Speter || symbolp -> sym_un.sym_str.fromi != ifilep ) {
473822Speter break;
474822Speter }
47514129Speter symbolp -> fromp = pfilep;
476822Speter return;
4777601Speter case N_PLDATA:
4787601Speter case N_PLTEXT:
4797601Speter switch ( nlp -> n_desc ) {
4807601Speter default:
4817601Speter error( FATAL , "pc3: unknown stab 0x%x"
4827601Speter , nlp -> n_desc );
4837601Speter return;
4847601Speter case N_PSO:
4857601Speter case N_PSOL:
4867601Speter case N_PGCONST:
4877601Speter case N_PGTYPE:
4887601Speter /* these won't conflict with library */
4897601Speter return;
4907601Speter case N_PGLABEL:
4917601Speter case N_PGVAR:
4927601Speter case N_PGFUNC:
4937601Speter case N_PGPROC:
4947601Speter case N_PEFUNC:
4957601Speter case N_PEPROC:
4967601Speter case N_PLDATA:
4977601Speter case N_PLTEXT:
4987601Speter errtype = WARNING;
4997601Speter break;
5007601Speter }
5017601Speter break;
502822Speter }
503822Speter /*
504822Speter * this is the breaks
505822Speter */
5067601Speter error( errtype
5077601Speter , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)."
5087601Speter , ifilep -> name
5097601Speter , nlp -> n_value
5107601Speter , classify( nlp -> n_desc )
5117601Speter , nlp -> n_un.n_name
5127601Speter , ( symbolp -> desc == nlp -> n_desc ? "" : " as " )
5137601Speter , ( symbolp -> desc == nlp -> n_desc
5147601Speter ? "" : article( symbolp -> desc ) )
5157601Speter , symbolp -> sym_un.sym_str.rfilep -> name
5167601Speter , symbolp -> sym_un.sym_str.rline );
517822Speter }
518822Speter }
519822Speter
520822Speter /*
521822Speter * quadratically hashed symbol table.
522822Speter * things are never deleted from the hash symbol table.
523822Speter * as more hash table is needed,
524822Speter * a new one is alloc'ed and chained to the end.
525822Speter * search is by rehashing within each table,
526822Speter * traversing chains to next table if unsuccessful.
527822Speter */
528822Speter struct symbol *
entersymbol(name)529822Speter entersymbol( name )
530822Speter char *name;
531822Speter {
5329572Speter static struct symboltableinfo symboltable;
533822Speter char *enteredname;
534822Speter long hashindex;
535822Speter register struct symboltableinfo *tablep;
536822Speter register struct symbol **herep;
537822Speter register struct symbol **limitp;
538822Speter register long increment;
539822Speter
540822Speter enteredname = enterstring( name );
541822Speter hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
5429572Speter for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) {
543822Speter if ( tablep == NIL ) {
5449572Speter # ifdef SPACEDEBUG
5459572Speter fprintf( stderr ,
5469572Speter "[entersymbol] calloc'ing table for %d symbols\n" ,
5479572Speter SYMBOLPRIME );
5489572Speter # endif SPACEDEBUG
5499572Speter for ( tablep = &symboltable
5509572Speter ; tablep->chain != NIL
5519572Speter ; tablep = tablep->chain ) {
5529572Speter continue;
5539572Speter }
5549572Speter tablep->chain = ( struct symboltableinfo * )
5559572Speter calloc( 1 , sizeof ( struct symboltableinfo ) );
5569572Speter if ( tablep->chain == NIL ) {
557822Speter error( FATAL , "ran out of memory (entersymbol)" );
558822Speter }
5599572Speter tablep = tablep->chain;
560822Speter }
561822Speter herep = &( tablep -> entry[ hashindex ] );
562822Speter limitp = &( tablep -> entry[ SYMBOLPRIME ] );
563822Speter increment = 1;
564822Speter do {
565822Speter if ( *herep == NIL ) {
566822Speter /* empty */
5679572Speter if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) {
568822Speter /* too full, break for next table */
569822Speter break;
570822Speter }
571822Speter tablep -> used++;
572822Speter *herep = symbolalloc();
573822Speter ( *herep ) -> name = enteredname;
574822Speter ( *herep ) -> lookup = NEW;
5759572Speter # ifdef HASHDEBUG
5769572Speter fprintf( stderr ,
5779572Speter "[entersymbol] name %s NEW after %d\n" ,
5789572Speter enteredname , increment / 2 );
5799572Speter # endif HASHDEBUG
580822Speter return *herep;
581822Speter }
582822Speter /* a find? */
583822Speter if ( ( *herep ) -> name == enteredname ) {
584822Speter ( *herep ) -> lookup = OLD;
5859572Speter # ifdef HASHDEBUG
5869572Speter fprintf( stderr , "[entersymbol] name %s OLD at %d\n" ,
5879572Speter enteredname , increment / 2 );
5889572Speter # endif HASHDEBUG
589822Speter return *herep;
590822Speter }
591822Speter herep += increment;
592822Speter if ( herep >= limitp ) {
593822Speter herep -= SYMBOLPRIME;
594822Speter }
595822Speter increment += 2;
596822Speter } while ( increment < SYMBOLPRIME );
5979572Speter # ifdef HASHDEBUG
5989572Speter fprintf( stderr , "[entersymbol] next symboltable\n" );
5999572Speter # endif HASHDEBUG
600822Speter }
601822Speter }
602822Speter
603822Speter /*
604822Speter * allocate a symbol from the dynamically allocated symbol table.
605822Speter */
606822Speter struct symbol *
symbolalloc()607822Speter symbolalloc()
608822Speter {
609822Speter static struct symbol *nextsymbol = NIL;
610822Speter static long symbolsleft = 0;
611822Speter struct symbol *newsymbol;
612822Speter
613822Speter if ( symbolsleft <= 0 ) {
6149572Speter # ifdef SPACEDEBUG
6159572Speter fprintf( stderr ,
6169572Speter "[symbolalloc] malloc space for %d symbols\n" ,
6179572Speter SYMBOLALLOC / sizeof( struct symbol ) );
6189572Speter # endif SPACEDEBUG
619822Speter nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
620822Speter if ( nextsymbol == 0 ) {
621822Speter error( FATAL , "ran out of memory (symbolalloc)" );
622822Speter }
623822Speter symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
624822Speter }
625822Speter newsymbol = nextsymbol;
626822Speter nextsymbol++;
627822Speter symbolsleft--;
628822Speter return newsymbol;
629822Speter }
630822Speter
631822Speter /*
632822Speter * hash a string based on all of its characters.
633822Speter */
634822Speter long
hashstring(string)635822Speter hashstring( string )
636822Speter char *string;
637822Speter {
638822Speter register char *cp;
639822Speter register long value;
640822Speter
641822Speter value = 0;
642822Speter for ( cp = string ; *cp ; cp++ ) {
643822Speter value = ( value * 2 ) + *cp;
644822Speter }
645822Speter return value;
646822Speter }
647822Speter
648822Speter /*
649822Speter * quadratically hashed string table.
650822Speter * things are never deleted from the hash string table.
651822Speter * as more hash table is needed,
652822Speter * a new one is alloc'ed and chained to the end.
653822Speter * search is by rehashing within each table,
654822Speter * traversing chains to next table if unsuccessful.
655822Speter */
656822Speter char *
enterstring(string)657822Speter enterstring( string )
658822Speter char *string;
659822Speter {
6609572Speter static struct stringtableinfo stringtable;
661822Speter long hashindex;
662822Speter register struct stringtableinfo *tablep;
663822Speter register char **herep;
664822Speter register char **limitp;
665822Speter register long increment;
666822Speter
667822Speter hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
6689572Speter for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) {
669822Speter if ( tablep == NIL ) {
6709572Speter # ifdef SPACEDEBUG
6719572Speter fprintf( stderr ,
6729572Speter "[enterstring] calloc space for %d strings\n" ,
6739572Speter STRINGPRIME );
6749572Speter # endif SPACEDEBUG
6759572Speter for ( tablep = &stringtable
6769572Speter ; tablep->chain != NIL
6779572Speter ; tablep = tablep->chain ) {
6789572Speter continue;
6799572Speter }
6809572Speter tablep->chain = ( struct stringtableinfo * )
6819572Speter calloc( 1 , sizeof ( struct stringtableinfo ) );
6829572Speter if ( tablep->chain == NIL ) {
683822Speter error( FATAL , "ran out of memory (enterstring)" );
684822Speter }
6859572Speter tablep = tablep->chain;
686822Speter }
687822Speter herep = &( tablep -> entry[ hashindex ] );
688822Speter limitp = &( tablep -> entry[ STRINGPRIME ] );
689822Speter increment = 1;
690822Speter do {
691822Speter if ( *herep == NIL ) {
692822Speter /* empty */
6939572Speter if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) {
694822Speter /* too full, break for next table */
695822Speter break;
696822Speter }
697822Speter tablep -> used++;
698822Speter *herep = charalloc( strlen( string ) );
699822Speter strcpy( *herep , string );
7009572Speter # ifdef HASHDEBUG
7019572Speter fprintf( stderr ,
7029572Speter "[enterstring] string %s copied after %d\n" ,
7039572Speter *herep , increment / 2 );
7049572Speter # endif HASHDEBUG
705822Speter return *herep;
706822Speter }
707822Speter /* quick, check the first chars and then the rest */
708822Speter if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
7099572Speter # ifdef HASHDEBUG
7109572Speter fprintf( stderr ,
7119572Speter "[enterstring] string %s found after %d\n" ,
7129572Speter *herep , increment / 2 );
7139572Speter # endif HASHDEBUG
714822Speter return *herep;
715822Speter }
716822Speter herep += increment;
717822Speter if ( herep >= limitp ) {
718822Speter herep -= STRINGPRIME;
719822Speter }
720822Speter increment += 2;
721822Speter } while ( increment < STRINGPRIME );
7229572Speter # ifdef HASHDEBUG
7239572Speter fprintf( stderr , "[enterstring] next stringtable\n" );
7249572Speter # endif HASHDEBUG
725822Speter }
726822Speter }
727822Speter
728822Speter /*
729822Speter * copy a string to the dynamically allocated character table.
730822Speter */
731822Speter char *
charalloc(length)732822Speter charalloc( length )
733822Speter register long length;
734822Speter {
735822Speter static char *nextchar = NIL;
736822Speter static long charsleft = 0;
737822Speter register long lengthplus1 = length + 1;
738822Speter register long askfor;
739822Speter char *newstring;
740822Speter
741822Speter if ( charsleft < lengthplus1 ) {
742822Speter askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
7439572Speter # ifdef SPACEDEBUG
7449572Speter fprintf( stderr , "[charalloc] malloc space for %d chars\n"
745822Speter , askfor );
7469572Speter # endif SPACEDEBUG
747822Speter nextchar = ( char * ) malloc( askfor );
748822Speter if ( nextchar == 0 ) {
749822Speter error( FATAL , "no room for %d characters" , askfor );
750822Speter }
751822Speter charsleft = askfor;
752822Speter }
753822Speter newstring = nextchar;
754822Speter nextchar += lengthplus1;
755822Speter charsleft -= lengthplus1;
756822Speter return newstring;
757822Speter }
758822Speter
759822Speter /*
760822Speter * read an archive header for the next element
761822Speter * and find the offset of the one after this.
762822Speter */
763822Speter BOOL
nextelement(ofilep)764822Speter nextelement( ofilep )
765822Speter struct fileinfo *ofilep;
766822Speter {
767822Speter register char *cp;
768822Speter register long red;
769822Speter register off_t arsize;
770822Speter struct ar_hdr archdr;
771822Speter
772822Speter fseek( ofilep -> file , ofilep -> nextoffset , 0 );
773822Speter red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
774822Speter if ( red != sizeof archdr ) {
775822Speter return FALSE;
776822Speter }
777822Speter /* null terminate the blank-padded name */
778822Speter cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
779822Speter *cp = '\0';
780822Speter while ( *--cp == ' ' ) {
781822Speter *cp = '\0';
782822Speter }
783822Speter /* set up the address of the beginning of next element */
784822Speter arsize = atol( archdr.ar_size );
785822Speter /* archive elements are aligned on 0 mod 2 boundaries */
786822Speter if ( arsize & 1 ) {
787822Speter arsize += 1;
788822Speter }
789822Speter ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
790822Speter /* say we had one */
791822Speter return TRUE;
792822Speter }
793822Speter
794822Speter /*
795822Speter * variable number of arguments to error, like printf.
796822Speter */
error(type,message,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)7977601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 )
7987598Speter int type;
799822Speter char *message;
800822Speter {
8017598Speter errors = type > errors ? type : errors;
8027598Speter if ( wflag && type == WARNING ) {
8037598Speter return;
8047598Speter }
805822Speter fprintf( stderr , "%s: " , program );
8067598Speter switch ( type ) {
8077598Speter case WARNING:
8087598Speter fprintf( stderr , "Warning: " );
8097598Speter break;
8107598Speter case ERROR:
8117598Speter fprintf( stderr , "Error: " );
8127598Speter break;
8137598Speter case FATAL:
8147598Speter fprintf( stderr , "Fatal: " );
8157598Speter break;
8167598Speter default:
8177598Speter fprintf( stderr , "Ooops: " );
8187598Speter break;
8197598Speter }
8207601Speter fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 );
821822Speter fprintf( stderr , "\n" );
8227598Speter if ( type == FATAL ) {
8237598Speter exit( FATAL );
824822Speter }
825822Speter }
826822Speter
827822Speter char *
classify(type)828822Speter classify( type )
829822Speter unsigned char type;
830822Speter {
831822Speter switch ( type ) {
832822Speter case N_PSO:
833822Speter return "source file";
834822Speter case N_PSOL:
835822Speter return "include file";
836844Speter case N_PGLABEL:
837822Speter return "label";
838844Speter case N_PGCONST:
839822Speter return "constant";
840844Speter case N_PGTYPE:
841822Speter return "type";
842822Speter case N_PGVAR:
843822Speter return "variable";
844844Speter case N_PGFUNC:
845822Speter return "function";
846844Speter case N_PGPROC:
847822Speter return "procedure";
848844Speter case N_PEFUNC:
849822Speter return "external function";
850844Speter case N_PEPROC:
851822Speter return "external procedure";
8527601Speter case N_PLDATA:
8537601Speter return "library variable";
8547601Speter case N_PLTEXT:
8557601Speter return "library routine";
856822Speter default:
857822Speter return "unknown symbol";
858822Speter }
859822Speter }
8607601Speter
8617601Speter char *
article(type)8627601Speter article( type )
8637601Speter unsigned char type;
8647601Speter {
8657601Speter switch ( type ) {
8667601Speter case N_PSO:
8677601Speter return "a source file";
8687601Speter case N_PSOL:
8697601Speter return "an include file";
8707601Speter case N_PGLABEL:
8717601Speter return "a label";
8727601Speter case N_PGCONST:
8737601Speter return "a constant";
8747601Speter case N_PGTYPE:
8757601Speter return "a type";
8767601Speter case N_PGVAR:
8777601Speter return "a variable";
8787601Speter case N_PGFUNC:
8797601Speter return "a function";
8807601Speter case N_PGPROC:
8817601Speter return "a procedure";
8827601Speter case N_PEFUNC:
8837601Speter return "an external function";
8847601Speter case N_PEPROC:
8857601Speter return "an external procedure";
8867601Speter case N_PLDATA:
8877601Speter return "a library variable";
8887601Speter case N_PLTEXT:
8897601Speter return "a library routine";
8907601Speter default:
8917601Speter return "an unknown symbol";
8927601Speter }
8937601Speter }
894