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