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