|
|
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[] = "@(#)source.c 5.1 (Berkeley) 5/31/85";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: source.c,v 1.4 84/06/07 16:29:38 linton Exp $";
12:
13: /*
14: * Source file management.
15: */
16:
17: #include "defs.h"
18: #include "source.h"
19: #include "object.h"
20: #include "mappings.h"
21: #include "machine.h"
22: #include "keywords.h"
23: #include "tree.h"
24: #include "eval.h"
25: #include <sys/file.h>
26:
27: #ifndef public
28: typedef int Lineno;
29:
30: String cursource;
31: Lineno curline;
32: Lineno cursrcline;
33:
34: #define LASTLINE 0 /* recognized by printlines */
35:
36: #include "lists.h"
37:
38: List sourcepath;
39: #endif
40:
41: extern char *re_comp();
42:
43: private Lineno lastlinenum;
44: private String prevsource = nil;
45:
46: /*
47: * Data structure for indexing source seek addresses by line number.
48: *
49: * The constraints are:
50: *
51: * we want an array so indexing is fast and easy
52: * we don't want to waste space for small files
53: * we don't want an upper bound on # of lines in a file
54: * we don't know how many lines there are
55: *
56: * The solution is a "dirty" hash table. We have NSLOTS pointers to
57: * arrays of NLINESPERSLOT addresses. To find the source address of
58: * a particular line we find the slot, allocate space if necessary,
59: * and then find its location within the pointed to array.
60: */
61:
62: typedef long Seekaddr;
63:
64: #define NSLOTS 40
65: #define NLINESPERSLOT 500
66:
67: #define slotno(line) ((line) div NLINESPERSLOT)
68: #define index(line) ((line) mod NLINESPERSLOT)
69: #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT)
70: #define srcaddr(line) seektab[slotno(line)][index(line)]
71:
72: private File srcfp;
73: private Seekaddr *seektab[NSLOTS];
74:
75: /*
76: * Determine if the current source file is available.
77: */
78:
79: public boolean canReadSource ()
80: {
81: boolean b;
82:
83: if (cursource == nil) {
84: b = false;
85: } else if (cursource != prevsource) {
86: skimsource();
87: b = (boolean) (lastlinenum != 0);
88: } else {
89: b = true;
90: }
91: return b;
92: }
93:
94: /*
95: * Print out the given lines from the source.
96: */
97:
98: public printlines(l1, l2)
99: Lineno l1, l2;
100: {
101: register int c;
102: register Lineno i, lb, ub;
103: register File f;
104:
105: if (cursource == nil) {
106: beginerrmsg();
107: fprintf(stderr, "no source file\n");
108: } else {
109: if (cursource != prevsource) {
110: skimsource();
111: }
112: if (lastlinenum == 0) {
113: beginerrmsg();
114: fprintf(stderr, "couldn't read \"%s\"\n", cursource);
115: } else {
116: lb = (l1 == LASTLINE) ? lastlinenum : l1;
117: ub = (l2 == LASTLINE) ? lastlinenum : l2;
118: if (lb < 1) {
119: beginerrmsg();
120: fprintf(stderr, "line number must be positive\n");
121: } else if (lb > lastlinenum) {
122: beginerrmsg();
123: if (lastlinenum == 1) {
124: fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
125: } else {
126: fprintf(stderr, "\"%s\" has only %d lines\n",
127: cursource, lastlinenum);
128: }
129: } else if (ub < lb) {
130: beginerrmsg();
131: fprintf(stderr, "second number must be greater than first\n");
132: } else {
133: if (ub > lastlinenum) {
134: ub = lastlinenum;
135: }
136: f = srcfp;
137: fseek(f, srcaddr(lb), 0);
138: for (i = lb; i <= ub; i++) {
139: printf("%5d ", i);
140: while ((c = getc(f)) != '\n') {
141: putchar(c);
142: }
143: putchar('\n');
144: }
145: cursrcline = ub + 1;
146: }
147: }
148: }
149: }
150:
151: /*
152: * Search the sourcepath for a file.
153: */
154:
155: static char fileNameBuf[1024];
156:
157: public String findsource(filename)
158: String filename;
159: {
160: register String src, dir;
161:
162: if (filename[0] == '/') {
163: src = filename;
164: } else {
165: src = nil;
166: foreach (String, dir, sourcepath)
167: sprintf(fileNameBuf, "%s/%s", dir, filename);
168: if (access(fileNameBuf, R_OK) == 0) {
169: src = fileNameBuf;
170: break;
171: }
172: endfor
173: }
174: return src;
175: }
176:
177: /*
178: * Open a source file looking in the appropriate places.
179: */
180:
181: public File opensource(filename)
182: String filename;
183: {
184: String s;
185: File f;
186:
187: s = findsource(filename);
188: if (s == nil) {
189: f = nil;
190: } else {
191: f = fopen(s, "r");
192: }
193: return f;
194: }
195:
196: /*
197: * Set the current source file.
198: */
199:
200: public setsource(filename)
201: String filename;
202: {
203: if (filename != nil and filename != cursource) {
204: prevsource = cursource;
205: cursource = filename;
206: cursrcline = 1;
207: }
208: }
209:
210: /*
211: * Read the source file getting seek pointers for each line.
212: */
213:
214: private skimsource()
215: {
216: register int c;
217: register Seekaddr count;
218: register File f;
219: register Lineno linenum;
220: register Seekaddr lastaddr;
221: register int slot;
222:
223: f = opensource(cursource);
224: if (f == nil) {
225: lastlinenum = 0;
226: } else {
227: if (prevsource != nil) {
228: free_seektab();
229: if (srcfp != nil) {
230: fclose(srcfp);
231: }
232: }
233: prevsource = cursource;
234: linenum = 0;
235: count = 0;
236: lastaddr = 0;
237: while ((c = getc(f)) != EOF) {
238: ++count;
239: if (c == '\n') {
240: slot = slotno(++linenum);
241: if (slot >= NSLOTS) {
242: panic("skimsource: too many lines");
243: }
244: if (seektab[slot] == nil) {
245: seektab[slot] = slot_alloc();
246: }
247: seektab[slot][index(linenum)] = lastaddr;
248: lastaddr = count;
249: }
250: }
251: lastlinenum = linenum;
252: srcfp = f;
253: }
254: }
255:
256: /*
257: * Erase information and release space in the current seektab.
258: * This is in preparation for reading in seek pointers for a
259: * new file. It is possible that seek pointers for all files
260: * should be kept around, but the current concern is space.
261: */
262:
263: private free_seektab()
264: {
265: register int slot;
266:
267: for (slot = 0; slot < NSLOTS; slot++) {
268: if (seektab[slot] != nil) {
269: dispose(seektab[slot]);
270: }
271: }
272: }
273:
274: /*
275: * Figure out current source position.
276: */
277:
278: public getsrcpos()
279: {
280: String filename;
281:
282: curline = srcline(pc);
283: filename = srcfilename(pc);
284: setsource(filename);
285: if (curline != 0) {
286: cursrcline = curline;
287: }
288: }
289:
290: /*
291: * Print out the current source position.
292: */
293:
294: public printsrcpos()
295: {
296: printf("at line %d", curline);
297: if (nlhdr.nfiles > 1) {
298: printf(" in file \"%s\"", cursource);
299: }
300: }
301:
302: #define DEF_EDITOR "vi"
303:
304: /*
305: * Invoke an editor on the given file. Which editor to use might change
306: * installation to installation. For now, we use "vi". In any event,
307: * the environment variable "EDITOR" overrides any default.
308: */
309:
310: public edit(filename)
311: String filename;
312: {
313: extern String getenv();
314: String ed, src, s;
315: Symbol f;
316: Address addr;
317: char lineno[10];
318:
319: ed = getenv("EDITOR");
320: if (ed == nil) {
321: ed = DEF_EDITOR;
322: }
323: src = findsource((filename != nil) ? filename : cursource);
324: if (src == nil) {
325: f = which(identname(filename, true));
326: if (not isblock(f)) {
327: error("can't read \"%s\"", filename);
328: }
329: addr = firstline(f);
330: if (addr == NOADDR) {
331: error("no source for \"%s\"", filename);
332: }
333: src = srcfilename(addr);
334: s = findsource(src);
335: if (s != nil) {
336: src = s;
337: }
338: sprintf(lineno, "+%d", srcline(addr));
339: } else {
340: sprintf(lineno, "+1");
341: }
342: if (streq(ed, "vi") or streq(ed, "ex")) {
343: call(ed, stdin, stdout, lineno, src, nil);
344: } else {
345: call(ed, stdin, stdout, src, nil);
346: }
347: }
348:
349: /*
350: * Strip away portions of a given pattern not part of the regular expression.
351: */
352:
353: private String getpattern (pattern)
354: String pattern;
355: {
356: register char *p, *r;
357:
358: p = pattern;
359: while (*p == ' ' or *p == '\t') {
360: ++p;
361: }
362: r = p;
363: while (*p != '\0') {
364: ++p;
365: }
366: --p;
367: if (*p == '\n') {
368: *p = '\0';
369: --p;
370: }
371: if (*p == *r) {
372: *p = '\0';
373: --p;
374: }
375: return r + 1;
376: }
377:
378: /*
379: * Search the current file for a regular expression.
380: */
381:
382: public search (direction, pattern)
383: char direction;
384: String pattern;
385: {
386: register String p;
387: register File f;
388: String re, err;
389: Lineno line;
390: boolean matched;
391: char buf[512];
392:
393: if (cursource == nil) {
394: beginerrmsg();
395: fprintf(stderr, "no source file\n");
396: } else {
397: if (cursource != prevsource) {
398: skimsource();
399: }
400: if (lastlinenum == 0) {
401: beginerrmsg();
402: fprintf(stderr, "couldn't read \"%s\"\n", cursource);
403: } else {
404: re = getpattern(pattern);
405: /* circf = 0; */
406: if (re != nil and *re != '\0') {
407: err = re_comp(re);
408: if (err != nil) {
409: error(err);
410: }
411: }
412: matched = false;
413: f = srcfp;
414: line = cursrcline;
415: do {
416: if (direction == '/') {
417: ++line;
418: if (line > lastlinenum) {
419: line = 1;
420: }
421: } else {
422: --line;
423: if (line < 1) {
424: line = lastlinenum;
425: }
426: }
427: fseek(f, srcaddr(line), L_SET);
428: p = buf;
429: *p = getc(f);
430: while ((*p != '\n') and (*p != EOF)) {
431: ++p;
432: *p = getc(f);
433: }
434: *p = '\0';
435: matched = (boolean) re_exec(buf);
436: } while (not matched and line != cursrcline);
437: if (not matched) {
438: beginerrmsg();
439: fprintf(stderr, "no match\n");
440: } else {
441: printlines(line, line);
442: cursrcline = line;
443: }
444: }
445: }
446: }
447:
448: /*
449: * Compute a small window around the given line.
450: */
451:
452: public getsrcwindow (line, l1, l2)
453: Lineno line, *l1, *l2;
454: {
455: Node s;
456: integer size;
457:
458: s = findvar(identname("$listwindow", true));
459: if (s == nil) {
460: size = 10;
461: } else {
462: eval(s);
463: size = pop(integer);
464: }
465: *l1 = line - (size div 2);
466: if (*l1 < 1) {
467: *l1 = 1;
468: }
469: *l2 = *l1 + size;
470: if (lastlinenum != LASTLINE and *l2 > lastlinenum) {
471: *l2 = lastlinenum;
472: }
473: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.