|
|
1.1 root 1: /* Copyright (c) 1982 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)source.c 1.9 8/5/83";
4:
5: /*
6: * Source file management.
7: */
8:
9: #include "defs.h"
10: #include "source.h"
11: #include "object.h"
12: #include "mappings.h"
13: #include "machine.h"
14:
15: #ifndef public
16: typedef int Lineno;
17:
18: String cursource;
19: Lineno curline;
20: Lineno cursrcline;
21:
22: #define LASTLINE 0 /* recognized by printlines */
23:
24: #include "lists.h"
25:
26: List sourcepath;
27: #endif
28:
29: private Lineno lastlinenum;
30: private String prevsource = nil;
31:
32: /*
33: * Data structure for indexing source seek addresses by line number.
34: *
35: * The constraints are:
36: *
37: * we want an array so indexing is fast and easy
38: * we don't want to waste space for small files
39: * we don't want an upper bound on # of lines in a file
40: * we don't know how many lines there are
41: *
42: * The solution is a "dirty" hash table. We have NSLOTS pointers to
43: * arrays of NLINESPERSLOT addresses. To find the source address of
44: * a particular line we find the slot, allocate space if necessary,
45: * and then find its location within the pointed to array.
46: */
47:
48: typedef long Seekaddr;
49:
50: #define NSLOTS 20
51: #define NLINESPERSLOT 500
52:
53: #define slotno(line) ((line) div NLINESPERSLOT)
54: #define index(line) ((line) mod NLINESPERSLOT)
55: #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT)
56: #define srcaddr(line) seektab[slotno(line)][index(line)]
57:
58: private File srcfp;
59: private Seekaddr *seektab[NSLOTS];
60:
61: /*
62: * Print out the given lines from the source.
63: */
64:
65: public printlines(l1, l2)
66: Lineno l1, l2;
67: {
68: register int c;
69: register Lineno i, lb, ub;
70: register File f;
71:
72: if (cursource == nil) {
73: beginerrmsg();
74: fprintf(stderr, "no source file\n");
75: } else {
76: if (cursource != prevsource) {
77: skimsource();
78: }
79: if (lastlinenum == 0) {
80: beginerrmsg();
81: fprintf(stderr, "couldn't read \"%s\"\n", cursource);
82: } else {
83: lb = (l1 == 0) ? lastlinenum : l1;
84: ub = (l2 == 0) ? lastlinenum : l2;
85: if (lb < 1) {
86: beginerrmsg();
87: fprintf(stderr, "line number must be positive\n");
88: } else if (lb > lastlinenum) {
89: beginerrmsg();
90: if (lastlinenum == 1) {
91: fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
92: } else {
93: fprintf(stderr, "\"%s\" has only %d lines\n",
94: cursource, lastlinenum);
95: }
96: } else if (ub < lb) {
97: beginerrmsg();
98: fprintf(stderr, "second number must be greater than first\n");
99: } else {
100: if (ub > lastlinenum) {
101: ub = lastlinenum;
102: }
103: f = srcfp;
104: fseek(f, srcaddr(lb), 0);
105: for (i = lb; i <= ub; i++) {
106: printf("%5d ", i);
107: while ((c = getc(f)) != '\n') {
108: putchar(c);
109: }
110: putchar('\n');
111: }
112: cursrcline = ub + 1;
113: }
114: }
115: }
116: }
117:
118: /*
119: * Search the sourcepath for a file.
120: */
121:
122: static char fileNameBuf[1024];
123:
124: public String findsource(filename)
125: String filename;
126: {
127: register File f;
128: register String src, dir;
129:
130: if (filename[0] == '/') {
131: src = filename;
132: } else {
133: src = nil;
134: foreach (String, dir, sourcepath)
135: sprintf(fileNameBuf, "%s/%s", dir, filename);
136: f = fopen(fileNameBuf, "r");
137: if (f != nil) {
138: fclose(f);
139: src = fileNameBuf;
140: break;
141: }
142: endfor
143: }
144: return src;
145: }
146:
147: /*
148: * Open a source file looking in the appropriate places.
149: */
150:
151: public File opensource(filename)
152: String filename;
153: {
154: String s;
155: File f;
156:
157: s = findsource(filename);
158: if (s == nil) {
159: f = nil;
160: } else {
161: f = fopen(s, "r");
162: }
163: return f;
164: }
165:
166: /*
167: * Set the current source file.
168: */
169:
170: public setsource(filename)
171: String filename;
172: {
173: if (filename != nil and filename != cursource) {
174: prevsource = cursource;
175: cursource = filename;
176: cursrcline = 1;
177: }
178: }
179:
180: /*
181: * Read the source file getting seek pointers for each line.
182: */
183:
184: private skimsource()
185: {
186: register int c;
187: register Seekaddr count;
188: register File f;
189: register Lineno linenum;
190: register Seekaddr lastaddr;
191: register int slot;
192:
193: f = opensource(cursource);
194: if (f == nil) {
195: lastlinenum = 0;
196: } else {
197: if (prevsource != nil) {
198: free_seektab();
199: if (srcfp != nil) {
200: fclose(srcfp);
201: }
202: }
203: prevsource = cursource;
204: linenum = 0;
205: count = 0;
206: lastaddr = 0;
207: while ((c = getc(f)) != EOF) {
208: ++count;
209: if (c == '\n') {
210: slot = slotno(++linenum);
211: if (slot >= NSLOTS) {
212: panic("skimsource: too many lines");
213: }
214: if (seektab[slot] == nil) {
215: seektab[slot] = slot_alloc();
216: }
217: seektab[slot][index(linenum)] = lastaddr;
218: lastaddr = count;
219: }
220: }
221: lastlinenum = linenum;
222: srcfp = f;
223: }
224: }
225:
226: /*
227: * Erase information and release space in the current seektab.
228: * This is in preparation for reading in seek pointers for a
229: * new file. It is possible that seek pointers for all files
230: * should be kept around, but the current concern is space.
231: */
232:
233: private free_seektab()
234: {
235: register int slot;
236:
237: for (slot = 0; slot < NSLOTS; slot++) {
238: if (seektab[slot] != nil) {
239: dispose(seektab[slot]);
240: }
241: }
242: }
243:
244: /*
245: * Figure out current source position.
246: */
247:
248: public getsrcpos()
249: {
250: String filename;
251:
252: curline = srcline(pc);
253: filename = srcfilename(pc);
254: setsource(filename);
255: if (curline != 0) {
256: cursrcline = curline;
257: }
258: }
259:
260: /*
261: * Print out the current source position.
262: */
263:
264: public printsrcpos()
265: {
266: printf("at line %d", curline);
267: if (nlhdr.nfiles > 1) {
268: printf(" in file \"%s\"", cursource);
269: }
270: }
271:
272: #define DEF_EDITOR "vi"
273:
274: /*
275: * Invoke an editor on the given file. Which editor to use might change
276: * installation to installation. For now, we use "vi". In any event,
277: * the environment variable "EDITOR" overrides any default.
278: */
279:
280: public edit(filename)
281: String filename;
282: {
283: extern String getenv();
284: String ed, src, s;
285: Symbol f;
286: Address addr;
287: char lineno[10];
288:
289: ed = getenv("EDITOR");
290: if (ed == nil) {
291: ed = DEF_EDITOR;
292: }
293: src = findsource((filename != nil) ? filename : cursource);
294: if (src == nil) {
295: f = which(identname(filename, true));
296: if (not isblock(f)) {
297: error("can't read \"%s\"", filename);
298: }
299: addr = firstline(f);
300: if (addr == NOADDR) {
301: error("no source for \"%s\"", filename);
302: }
303: src = srcfilename(addr);
304: s = findsource(src);
305: if (s != nil) {
306: src = s;
307: }
308: sprintf(lineno, "+%d", srcline(addr));
309: } else {
310: sprintf(lineno, "+1");
311: }
312: call(ed, stdin, stdout, lineno, src, nil);
313: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.