|
|
1.1 root 1: /*
2: * Copyright (c) 1983 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)object.c 5.4 (Berkeley) 6/1/90";
22: #endif /* not lint */
23:
24: /*
25: * Object code interface, mainly for extraction of symbolic information.
26: */
27:
28: #include "defs.h"
29: #include "object.h"
30: #include "stabstring.h"
31: #include "main.h"
32: #include "symbols.h"
33: #include "names.h"
34: #include "languages.h"
35: #include "mappings.h"
36: #include "lists.h"
37: #include <a.out.h>
38: #include <stab.h>
39: #include <ctype.h>
40:
41: #ifndef public
42:
43: struct {
44: unsigned int stringsize; /* size of the dumped string table */
45: unsigned int nsyms; /* number of symbols */
46: unsigned int nfiles; /* number of files */
47: unsigned int nlines; /* number of lines */
48: } nlhdr;
49:
50: #include "languages.h"
51: #include "symbols.h"
52:
53: #endif
54:
55: #ifndef N_MOD2
56: # define N_MOD2 0x50
57: #endif
58:
59: public String objname = "a.out";
60: public integer objsize;
61:
62: public Language curlang;
63: public Symbol curmodule;
64: public Symbol curparam;
65: public Symbol curcomm;
66: public Symbol commchain;
67:
68: private char *stringtab;
69: private struct nlist *curnp;
70: private Boolean warned;
71: private Boolean strip_ = false;
72:
73: private Filetab *filep;
74: private Linetab *linep, *prevlinep;
75:
76: public String curfilename ()
77: {
78: return ((filep-1)->filename);
79: }
80:
81: /*
82: * Blocks are figured out on the fly while reading the symbol table.
83: */
84:
85: #define MAXBLKDEPTH 25
86:
87: public Symbol curblock;
88:
89: private Symbol blkstack[MAXBLKDEPTH];
90: private integer curlevel;
91: private integer bnum, nesting;
92: private Address addrstk[MAXBLKDEPTH];
93:
94: public pushBlock (b)
95: Symbol b;
96: {
97: if (curlevel >= MAXBLKDEPTH) {
98: fatal("nesting depth too large (%d)", curlevel);
99: }
100: blkstack[curlevel] = curblock;
101: ++curlevel;
102: curblock = b;
103: if (traceblocks) {
104: printf("entering block %s\n", symname(b));
105: }
106: }
107:
108: /*
109: * Change the current block with saving the previous one,
110: * since it is assumed that the symbol for the current one is to be deleted.
111: */
112:
113: public changeBlock (b)
114: Symbol b;
115: {
116: curblock = b;
117: }
118:
119: public enterblock (b)
120: Symbol b;
121: {
122: if (curblock == nil) {
123: b->level = 1;
124: } else {
125: b->level = curblock->level + 1;
126: }
127: b->block = curblock;
128: pushBlock(b);
129: }
130:
131: public exitblock ()
132: {
133: if (curblock->class == FUNC or curblock->class == PROC) {
134: if (prevlinep != linep) {
135: curblock->symvalue.funcv.src = true;
136: }
137: }
138: if (curlevel <= 0) {
139: panic("nesting depth underflow (%d)", curlevel);
140: }
141: --curlevel;
142: if (traceblocks) {
143: printf("exiting block %s\n", symname(curblock));
144: }
145: curblock = blkstack[curlevel];
146: }
147:
148: /*
149: * Enter a source line or file name reference into the appropriate table.
150: * Expanded inline to reduce procedure calls.
151: *
152: * private enterline (linenumber, address)
153: * Lineno linenumber;
154: * Address address;
155: * ...
156: */
157:
158: #define enterline(linenumber, address) \
159: { \
160: register Linetab *lp; \
161: \
162: lp = linep - 1; \
163: if (linenumber != lp->line) { \
164: if (address != lp->addr) { \
165: ++lp; \
166: } \
167: lp->line = linenumber; \
168: lp->addr = address; \
169: linep = lp + 1; \
170: } \
171: }
172:
173: /*
174: * Read in the namelist from the obj file.
175: *
176: * Reads and seeks are used instead of fread's and fseek's
177: * for efficiency sake; there's a lot of data being read here.
178: */
179:
180: public readobj (file)
181: String file;
182: {
183: Fileid f;
184: struct exec hdr;
185: struct nlist nlist;
186:
187: f = open(file, 0);
188: if (f < 0) {
189: fatal("can't open %s", file);
190: }
191: read(f, &hdr, sizeof(hdr));
192: if (N_BADMAG(hdr)) {
193: objsize = 0;
194: nlhdr.nsyms = 0;
195: nlhdr.nfiles = 0;
196: nlhdr.nlines = 0;
197: } else {
198: objsize = hdr.a_text;
199: nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
200: nlhdr.nfiles = nlhdr.nsyms;
201: nlhdr.nlines = nlhdr.nsyms;
202: }
203: if (nlhdr.nsyms > 0) {
204: lseek(f, (long) N_STROFF(hdr), 0);
205: read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
206: nlhdr.stringsize -= 4;
207: stringtab = newarr(char, nlhdr.stringsize);
208: read(f, stringtab, nlhdr.stringsize);
209: allocmaps(nlhdr.nfiles, nlhdr.nlines);
210: lseek(f, (long) N_SYMOFF(hdr), 0);
211: readsyms(f);
212: ordfunctab();
213: setnlines();
214: setnfiles();
215: } else {
216: initsyms();
217: }
218: close(f);
219: }
220:
221: /*
222: * Found the beginning of the externals in the object file
223: * (signified by the "-lg" or find an external), close the
224: * block for the last procedure.
225: */
226:
227: private foundglobals ()
228: {
229: if (curblock->class != PROG) {
230: exitblock();
231: if (curblock->class != PROG) {
232: exitblock();
233: }
234: }
235: enterline(0, (linep-1)->addr + 1);
236: }
237:
238: /*
239: * Read in symbols from object file.
240: */
241:
242: private readsyms (f)
243: Fileid f;
244: {
245: struct nlist *namelist;
246: register struct nlist *np, *ub;
247: register String name;
248: boolean afterlg, foundstab;
249: integer index;
250: char *lastchar;
251:
252: initsyms();
253: namelist = newarr(struct nlist, nlhdr.nsyms);
254: read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
255: afterlg = false;
256: foundstab = false;
257: ub = &namelist[nlhdr.nsyms];
258: curnp = &namelist[0];
259: np = curnp;
260: while (np < ub) {
261: index = np->n_un.n_strx;
262: if (index != 0) {
263: name = &stringtab[index - 4];
264: /*
265: * If the program contains any .f files a trailing _ is stripped
266: * from the name on the assumption it was added by the compiler.
267: * This only affects names that follow the sdb N_SO entry with
268: * the .f name.
269: */
270: if (strip_ and name[0] != '\0' ) {
271: lastchar = &name[strlen(name) - 1];
272: if (*lastchar == '_') {
273: *lastchar = '\0';
274: }
275: }
276: } else {
277: name = nil;
278: }
279:
280: /*
281: * Assumptions:
282: * not an N_STAB ==> name != nil
283: * name[0] == '-' ==> name == "-lg"
284: * name[0] != '_' ==> filename or invisible
285: *
286: * The "-lg" signals the beginning of global loader symbols.
287: *
288: */
289: if ((np->n_type&N_STAB) != 0) {
290: foundstab = true;
291: enter_nl(name, np);
292: } else if (name[0] == '-') {
293: afterlg = true;
294: foundglobals();
295: } else if (afterlg) {
296: check_global(name, np);
297: } else if ((np->n_type&N_EXT) == N_EXT) {
298: afterlg = true;
299: foundglobals();
300: check_global(name, np);
301: } else if (name[0] == '_') {
302: check_local(&name[1], np);
303: } else if ((np->n_type&N_TEXT) == N_TEXT) {
304: check_filename(name);
305: }
306: ++curnp;
307: np = curnp;
308: }
309: if (not foundstab) {
310: warning("no source compiled with -g");
311: }
312: dispose(namelist);
313: }
314:
315: /*
316: * Get a continuation entry from the name list.
317: * Return the beginning of the name.
318: */
319:
320: public String getcont ()
321: {
322: register integer index;
323: register String name;
324:
325: ++curnp;
326: index = curnp->n_un.n_strx;
327: if (index == 0) {
328: name = "";
329: } else {
330: name = &stringtab[index - 4];
331: }
332: return name;
333: }
334:
335: /*
336: * Initialize symbol information.
337: */
338:
339: private initsyms ()
340: {
341: curblock = nil;
342: curlevel = 0;
343: nesting = 0;
344: program = insert(identname("", true));
345: program->class = PROG;
346: program->language = primlang;
347: program->symvalue.funcv.beginaddr = CODESTART;
348: program->symvalue.funcv.inline = false;
349: newfunc(program, codeloc(program));
350: findbeginning(program);
351: enterblock(program);
352: curmodule = program;
353: }
354:
355: /*
356: * Free all the object file information that's being stored.
357: */
358:
359: public objfree ()
360: {
361: symbol_free();
362: /* keywords_free(); */
363: /* names_free(); */
364: /* dispose(stringtab); */
365: clrfunctab();
366: }
367:
368: /*
369: * Enter a namelist entry.
370: */
371:
372: private enter_nl (name, np)
373: String name;
374: register struct nlist *np;
375: {
376: register Symbol s;
377: register Name n;
378:
379: s = nil;
380: switch (np->n_type) {
381: /*
382: * Build a symbol for the FORTRAN common area. All GSYMS that follow
383: * will be chained in a list with the head kept in common.offset, and
384: * the tail in common.chain.
385: */
386: case N_BCOMM:
387: if (curcomm) {
388: curcomm->symvalue.common.chain = commchain;
389: }
390: n = identname(name, true);
391: curcomm = lookup(n);
392: if (curcomm == nil) {
393: curcomm = insert(n);
394: curcomm->class = COMMON;
395: curcomm->block = curblock;
396: curcomm->level = program->level;
397: curcomm->symvalue.common.chain = nil;
398: }
399: commchain = curcomm->symvalue.common.chain;
400: break;
401:
402: case N_ECOMM:
403: if (curcomm) {
404: curcomm->symvalue.common.chain = commchain;
405: curcomm = nil;
406: }
407: break;
408:
409: case N_LBRAC:
410: ++nesting;
411: addrstk[nesting] = (linep - 1)->addr;
412: break;
413:
414: case N_RBRAC:
415: --nesting;
416: if (addrstk[nesting] == NOADDR) {
417: exitblock();
418: newfunc(curblock, (linep - 1)->addr);
419: addrstk[nesting] = (linep - 1)->addr;
420: }
421: break;
422:
423: case N_SLINE:
424: enterline((Lineno) np->n_desc, (Address) np->n_value);
425: break;
426:
427: /*
428: * Source files.
429: */
430: case N_SO:
431: n = identname(name, true);
432: enterSourceModule(n, (Address) np->n_value);
433: break;
434:
435: /*
436: * Textually included files.
437: */
438: case N_SOL:
439: enterfile(name, (Address) np->n_value);
440: break;
441:
442: /*
443: * These symbols are assumed to have non-nil names.
444: */
445: case N_GSYM:
446: case N_FUN:
447: case N_STSYM:
448: case N_LCSYM:
449: case N_RSYM:
450: case N_PSYM:
451: case N_LSYM:
452: case N_SSYM:
453: case N_LENG:
454: if (index(name, ':') == nil) {
455: if (not warned) {
456: warned = true;
457: printf("warning: old style symbol information ");
458: printf("found in \"%s\"\n", curfilename());
459: }
460: } else {
461: entersym(name, np);
462: }
463: break;
464:
465: case N_PC:
466: case N_MOD2:
467: break;
468:
469: default:
470: printf("warning: stab entry unrecognized: ");
471: if (name != nil) {
472: printf("name %s,", name);
473: }
474: printf("ntype %2x, desc %x, value %x'\n",
475: np->n_type, np->n_desc, np->n_value);
476: break;
477: }
478: }
479:
480: /*
481: * Try to find the symbol that is referred to by the given name. Since it's
482: * an external, we need to follow a level or two of indirection.
483: */
484:
485: private Symbol findsym (n, var_isextref)
486: Name n;
487: boolean *var_isextref;
488: {
489: register Symbol r, s;
490:
491: *var_isextref = false;
492: find(s, n) where
493: (
494: s->level == program->level and (
495: s->class == EXTREF or s->class == VAR or
496: s->class == PROC or s->class == FUNC
497: )
498: ) or (
499: s->block == program and s->class == MODULE
500: )
501: endfind(s);
502: if (s == nil) {
503: r = nil;
504: } else if (s->class == EXTREF) {
505: *var_isextref = true;
506: r = s->symvalue.extref;
507: delete(s);
508:
509: /*
510: * Now check for another level of indirection that could come from
511: * a forward reference in procedure nesting information. In this case
512: * the symbol has already been deleted.
513: */
514: if (r != nil and r->class == EXTREF) {
515: r = r->symvalue.extref;
516: }
517: /*
518: } else if (s->class == MODULE) {
519: s->class = FUNC;
520: s->level = program->level;
521: r = s;
522: */
523: } else {
524: r = s;
525: }
526: return r;
527: }
528:
529: /*
530: * Create a symbol for a text symbol with no source information.
531: * We treat it as an assembly language function.
532: */
533:
534: private Symbol deffunc (n)
535: Name n;
536: {
537: Symbol f;
538:
539: f = insert(n);
540: f->language = findlanguage(".s");
541: f->class = FUNC;
542: f->type = t_int;
543: f->block = curblock;
544: f->level = program->level;
545: f->symvalue.funcv.src = false;
546: f->symvalue.funcv.inline = false;
547: if (f->chain != nil) {
548: panic("chain not nil in deffunc");
549: }
550: return f;
551: }
552:
553: /*
554: * Create a symbol for a data or bss symbol with no source information.
555: * We treat it as an assembly language variable.
556: */
557:
558: private Symbol defvar (n)
559: Name n;
560: {
561: Symbol v;
562:
563: v = insert(n);
564: v->language = findlanguage(".s");
565: v->storage = EXT;
566: v->class = VAR;
567: v->type = t_int;
568: v->level = program->level;
569: v->block = curblock;
570: return v;
571: }
572:
573: /*
574: * Update a symbol entry with a text address.
575: */
576:
577: private updateTextSym (s, name, addr)
578: Symbol s;
579: char *name;
580: Address addr;
581: {
582: if (s->class == VAR) {
583: s->symvalue.offset = addr;
584: } else {
585: s->symvalue.funcv.beginaddr = addr;
586: if (name[0] == '_') {
587: newfunc(s, codeloc(s));
588: findbeginning(s);
589: }
590: }
591: }
592:
593: /*
594: * Avoid seeing Pascal labels as text symbols.
595: */
596:
597: private boolean PascalLabel (n)
598: Name n;
599: {
600: boolean b;
601: register char *p;
602:
603: b = false;
604: if (curlang == findlanguage(".p")) {
605: p = ident(n);
606: while (*p != '\0') {
607: if (*p == '_' and *(p+1) == '$') {
608: b = true;
609: break;
610: }
611: ++p;
612: }
613: }
614: return b;
615: }
616:
617: /*
618: * Check to see if a global _name is already in the symbol table,
619: * if not then insert it.
620: */
621:
622: private check_global (name, np)
623: String name;
624: register struct nlist *np;
625: {
626: register Name n;
627: register Symbol t, u;
628: char buf[4096];
629: boolean isextref;
630: integer count;
631:
632: if (not streq(name, "_end")) {
633: if (name[0] == '_') {
634: n = identname(&name[1], true);
635: } else {
636: n = identname(name, true);
637: if (lookup(n) != nil) {
638: sprintf(buf, "$%s", name);
639: n = identname(buf, false);
640: }
641: }
642: if ((np->n_type&N_TYPE) == N_TEXT) {
643: count = 0;
644: t = findsym(n, &isextref);
645: while (isextref) {
646: ++count;
647: updateTextSym(t, name, np->n_value);
648: t = findsym(n, &isextref);
649: }
650: if (count == 0) {
651: if (t == nil) {
652: if (not PascalLabel(n)) {
653: t = deffunc(n);
654: updateTextSym(t, name, np->n_value);
655: if (tracesyms) {
656: printdecl(t);
657: }
658: }
659: } else {
660: if (t->class == MODULE) {
661: u = t;
662: t = deffunc(n);
663: t->block = u;
664: if (tracesyms) {
665: printdecl(t);
666: }
667: }
668: updateTextSym(t, name, np->n_value);
669: }
670: }
671: } else if ((np->n_type&N_TYPE) == N_BSS or (np->n_type&N_TYPE) == N_DATA) {
672: find(t, n) where
673: t->class == COMMON
674: endfind(t);
675: if (t != nil) {
676: u = (Symbol) t->symvalue.common.offset;
677: while (u != nil) {
678: u->symvalue.offset = u->symvalue.common.offset+np->n_value;
679: u = u->symvalue.common.chain;
680: }
681: } else {
682: check_var(np, n);
683: }
684: } else {
685: check_var(np, n);
686: }
687: }
688: }
689:
690: /*
691: * Check to see if a namelist entry refers to a variable.
692: * If not, create a variable for the entry. In any case,
693: * set the offset of the variable according to the value field
694: * in the entry.
695: *
696: * If the external name has been referred to by several other symbols,
697: * we must update each of them.
698: */
699:
700: private check_var (np, n)
701: struct nlist *np;
702: register Name n;
703: {
704: register Symbol t, u, next;
705: Symbol conflict;
706:
707: t = lookup(n);
708: if (t == nil) {
709: t = defvar(n);
710: t->symvalue.offset = np->n_value;
711: if (tracesyms) {
712: printdecl(t);
713: }
714: } else {
715: conflict = nil;
716: do {
717: next = t->next_sym;
718: if (t->name == n) {
719: if (t->class == MODULE and t->block == program) {
720: conflict = t;
721: } else if (t->class == EXTREF and t->level == program->level) {
722: u = t->symvalue.extref;
723: while (u != nil and u->class == EXTREF) {
724: u = u->symvalue.extref;
725: }
726: u->symvalue.offset = np->n_value;
727: delete(t);
728: } else if (t->level == program->level and
729: (t->class == VAR or t->class == PROC or t->class == FUNC)
730: ) {
731: conflict = nil;
732: t->symvalue.offset = np->n_value;
733: }
734: }
735: t = next;
736: } while (t != nil);
737: if (conflict != nil) {
738: u = defvar(n);
739: u->block = conflict;
740: u->symvalue.offset = np->n_value;
741: }
742: }
743: }
744:
745: /*
746: * Check to see if a local _name is known in the current scope.
747: * If not then enter it.
748: */
749:
750: private check_local (name, np)
751: String name;
752: register struct nlist *np;
753: {
754: register Name n;
755: register Symbol t, cur;
756:
757: n = identname(name, true);
758: cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
759: find(t, n) where t->block == cur endfind(t);
760: if (t == nil) {
761: t = insert(n);
762: t->language = findlanguage(".s");
763: t->type = t_int;
764: t->block = cur;
765: t->storage = EXT;
766: t->level = cur->level;
767: if ((np->n_type&N_TYPE) == N_TEXT) {
768: t->class = FUNC;
769: t->symvalue.funcv.src = false;
770: t->symvalue.funcv.inline = false;
771: t->symvalue.funcv.beginaddr = np->n_value;
772: newfunc(t, codeloc(t));
773: findbeginning(t);
774: } else {
775: t->class = VAR;
776: t->symvalue.offset = np->n_value;
777: }
778: }
779: }
780:
781: /*
782: * Check to see if a symbol corresponds to a object file name.
783: * For some reason these are listed as in the text segment.
784: */
785:
786: private check_filename (name)
787: String name;
788: {
789: register String mname;
790: register integer i;
791: Name n;
792: Symbol s;
793:
794: mname = strdup(name);
795: i = strlen(mname) - 2;
796: if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
797: mname[i] = '\0';
798: --i;
799: while (mname[i] != '/' and i >= 0) {
800: --i;
801: }
802: n = identname(&mname[i+1], true);
803: find(s, n) where s->block == program and s->class == MODULE endfind(s);
804: if (s == nil) {
805: s = insert(n);
806: s->language = findlanguage(".s");
807: s->class = MODULE;
808: s->symvalue.funcv.beginaddr = 0;
809: findbeginning(s);
810: }
811: if (curblock->class != PROG) {
812: exitblock();
813: if (curblock->class != PROG) {
814: exitblock();
815: }
816: }
817: enterblock(s);
818: curmodule = s;
819: }
820: }
821:
822: /*
823: * Check to see if a symbol is about to be defined within an unnamed block.
824: * If this happens, we create a procedure for the unnamed block, make it
825: * "inline" so that tracebacks don't associate an activation record with it,
826: * and enter it into the function table so that it will be detected
827: * by "whatblock".
828: */
829:
830: public chkUnnamedBlock ()
831: {
832: register Symbol s;
833: static int bnum = 0;
834: char buf[100];
835: Address startaddr;
836:
837: if (nesting > 0 and addrstk[nesting] != NOADDR) {
838: startaddr = (linep - 1)->addr;
839: ++bnum;
840: sprintf(buf, "$b%d", bnum);
841: s = insert(identname(buf, false));
842: s->language = curlang;
843: s->class = PROC;
844: s->symvalue.funcv.src = false;
845: s->symvalue.funcv.inline = true;
846: s->symvalue.funcv.beginaddr = startaddr;
847: enterblock(s);
848: newfunc(s, startaddr);
849: addrstk[nesting] = NOADDR;
850: }
851: }
852:
853: /*
854: * Compilation unit. C associates scope with filenames
855: * so we treat them as "modules". The filename without
856: * the suffix is used for the module name.
857: *
858: * Because there is no explicit "end-of-block" mark in
859: * the object file, we must exit blocks for the current
860: * procedure and module.
861: */
862:
863: private enterSourceModule (n, addr)
864: Name n;
865: Address addr;
866: {
867: register Symbol s;
868: Name nn;
869: String mname, suffix;
870:
871: mname = strdup(ident(n));
872: if (rindex(mname, '/') != nil) {
873: mname = rindex(mname, '/') + 1;
874: }
875: suffix = rindex(mname, '.');
876: if (suffix > mname && *(suffix-1) == '.') {
877: /* special hack for C++ */
878: --suffix;
879: }
880: curlang = findlanguage(suffix);
881: if (curlang == findlanguage(".f")) {
882: strip_ = true;
883: }
884: if (suffix != nil) {
885: *suffix = '\0';
886: }
887: if (not (*language_op(curlang, L_HASMODULES))()) {
888: if (curblock->class != PROG) {
889: exitblock();
890: if (curblock->class != PROG) {
891: exitblock();
892: }
893: }
894: nn = identname(mname, true);
895: if (curmodule == nil or curmodule->name != nn) {
896: s = insert(nn);
897: s->class = MODULE;
898: s->symvalue.funcv.beginaddr = 0;
899: findbeginning(s);
900: } else {
901: s = curmodule;
902: }
903: s->language = curlang;
904: enterblock(s);
905: curmodule = s;
906: }
907: if (program->language == nil) {
908: program->language = curlang;
909: }
910: warned = false;
911: enterfile(ident(n), addr);
912: initTypeTable();
913: }
914:
915: /*
916: * Allocate file and line tables and initialize indices.
917: */
918:
919: private allocmaps (nf, nl)
920: integer nf, nl;
921: {
922: if (filetab != nil) {
923: dispose(filetab);
924: }
925: if (linetab != nil) {
926: dispose(linetab);
927: }
928: filetab = newarr(Filetab, nf);
929: linetab = newarr(Linetab, nl);
930: filep = filetab;
931: linep = linetab;
932: }
933:
934: /*
935: * Add a file to the file table.
936: *
937: * If the new address is the same as the previous file address
938: * this routine used to not enter the file, but this caused some
939: * problems so it has been removed. It's not clear that this in
940: * turn may not also cause a problem.
941: */
942:
943: private enterfile (filename, addr)
944: String filename;
945: Address addr;
946: {
947: filep->addr = addr;
948: filep->filename = filename;
949: filep->lineindex = linep - linetab;
950: ++filep;
951: }
952:
953: /*
954: * Since we only estimated the number of lines (and it was a poor
955: * estimation) and since we need to know the exact number of lines
956: * to do a binary search, we set it when we're done.
957: */
958:
959: private setnlines ()
960: {
961: nlhdr.nlines = linep - linetab;
962: }
963:
964: /*
965: * Similarly for nfiles ...
966: */
967:
968: private setnfiles ()
969: {
970: nlhdr.nfiles = filep - filetab;
971: setsource(filetab[0].filename);
972: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.