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