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