Commit | Line | Data |
---|---|---|
79155b94 ML |
1 | /* Copyright (c) 1982 Regents of the University of California */ |
2 | ||
e3e28726 | 3 | static char sccsid[] = "@(#)source.c 1.8 %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 | /* | |
119 | * Open a source file looking in the appropriate places. | |
120 | */ | |
121 | ||
122 | public File opensource(filename) | |
123 | String filename; | |
124 | { | |
125 | register String dir; | |
126 | char buf[256]; | |
127 | File f; | |
128 | ||
129 | f = nil; | |
e3e28726 ML |
130 | if (filename[0] == '/') { |
131 | f = fopen(filename, "r"); | |
132 | } else { | |
133 | foreach (String, dir, sourcepath) | |
134 | sprintf(buf, "%s/%s", dir, filename); | |
135 | f = fopen(buf, "r"); | |
136 | if (f != nil) { | |
137 | break; | |
79155b94 | 138 | } |
e3e28726 ML |
139 | endfor |
140 | } | |
79155b94 ML |
141 | return f; |
142 | } | |
143 | ||
144 | /* | |
145 | * Set the current source file. | |
146 | */ | |
147 | ||
148 | public setsource(filename) | |
149 | String filename; | |
150 | { | |
151 | if (filename != nil and filename != cursource) { | |
152 | prevsource = cursource; | |
153 | cursource = filename; | |
154 | cursrcline = 1; | |
155 | } | |
156 | } | |
157 | ||
158 | /* | |
159 | * Read the source file getting seek pointers for each line. | |
160 | */ | |
161 | ||
162 | private skimsource() | |
163 | { | |
164 | register int c; | |
bb516de5 | 165 | register Seekaddr count; |
79155b94 ML |
166 | register File f; |
167 | register Lineno linenum; | |
168 | register Seekaddr lastaddr; | |
169 | register int slot; | |
170 | ||
171 | f = opensource(cursource); | |
172 | if (f == nil) { | |
173 | lastlinenum = 0; | |
174 | } else { | |
175 | if (prevsource != nil) { | |
176 | free_seektab(); | |
177 | if (srcfp != nil) { | |
178 | fclose(srcfp); | |
179 | } | |
180 | } | |
181 | prevsource = cursource; | |
182 | linenum = 0; | |
183 | count = 0; | |
184 | lastaddr = 0; | |
185 | while ((c = getc(f)) != EOF) { | |
186 | ++count; | |
187 | if (c == '\n') { | |
188 | slot = slotno(++linenum); | |
189 | if (slot >= NSLOTS) { | |
190 | panic("skimsource: too many lines"); | |
191 | } | |
192 | if (seektab[slot] == nil) { | |
193 | seektab[slot] = slot_alloc(); | |
194 | } | |
195 | seektab[slot][index(linenum)] = lastaddr; | |
196 | lastaddr = count; | |
197 | } | |
198 | } | |
199 | lastlinenum = linenum; | |
200 | srcfp = f; | |
201 | } | |
202 | } | |
203 | ||
204 | /* | |
205 | * Erase information and release space in the current seektab. | |
206 | * This is in preparation for reading in seek pointers for a | |
207 | * new file. It is possible that seek pointers for all files | |
208 | * should be kept around, but the current concern is space. | |
209 | */ | |
210 | ||
211 | private free_seektab() | |
212 | { | |
213 | register int slot; | |
214 | ||
215 | for (slot = 0; slot < NSLOTS; slot++) { | |
216 | if (seektab[slot] != nil) { | |
217 | dispose(seektab[slot]); | |
218 | } | |
219 | } | |
220 | } | |
221 | ||
222 | /* | |
223 | * Figure out current source position. | |
224 | */ | |
225 | ||
226 | public getsrcpos() | |
227 | { | |
228 | String filename; | |
229 | ||
ef552238 ML |
230 | curline = srcline(pc); |
231 | filename = srcfilename(pc); | |
79155b94 | 232 | setsource(filename); |
370fc044 ML |
233 | if (curline != 0) { |
234 | cursrcline = curline; | |
235 | } | |
79155b94 ML |
236 | } |
237 | ||
238 | /* | |
239 | * Print out the current source position. | |
240 | */ | |
241 | ||
242 | public printsrcpos() | |
243 | { | |
244 | printf("at line %d", curline); | |
245 | if (nlhdr.nfiles > 1) { | |
246 | printf(" in file \"%s\"", cursource); | |
247 | } | |
248 | } |