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