use syslog().
[unix-history] / usr / src / old / dbx / source.c
CommitLineData
79155b94
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
e1f4dbca 3static 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
17typedef int Lineno;
18
19String cursource;
20Lineno curline;
21Lineno cursrcline;
22
23#define LASTLINE 0 /* recognized by printlines */
24
25#include "lists.h"
26
27List sourcepath;
28#endif
29
30private Lineno lastlinenum;
31private 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 49typedef 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
59private File srcfp;
60private Seekaddr *seektab[NSLOTS];
61
62/*
63 * Print out the given lines from the source.
64 */
65
66public printlines(l1, l2)
67Lineno 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
123static char fileNameBuf[1024];
124
125public String findsource(filename)
79155b94
ML
126String 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
149public File opensource(filename)
150String 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
168public setsource(filename)
169String 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
182private 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
231private 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
246public 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
262public 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
278public edit(filename)
279String 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 */
318public 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}