date and time created 83/08/05 13:34:37 by sam
[unix-history] / usr / src / old / dbx / source.c
CommitLineData
79155b94
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
1468ee3c 3static 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
16typedef int Lineno;
17
18String cursource;
19Lineno curline;
20Lineno cursrcline;
21
22#define LASTLINE 0 /* recognized by printlines */
23
24#include "lists.h"
25
26List sourcepath;
27#endif
28
29private Lineno lastlinenum;
30private 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 48typedef 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
58private File srcfp;
59private Seekaddr *seektab[NSLOTS];
60
61/*
62 * Print out the given lines from the source.
63 */
64
65public printlines(l1, l2)
66Lineno 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
122static char fileNameBuf[1024];
123
124public String findsource(filename)
79155b94
ML
125String 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
151public File opensource(filename)
152String 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
170public setsource(filename)
171String 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
184private 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
233private 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
248public 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
264public 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
280public edit(filename)
281String 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}