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