xref: /csrg-svn/old/dbx/source.c (revision 12608)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)source.c 1.8 05/20/83";
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 
48 typedef long Seekaddr;
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;
104 		fseek(f, srcaddr(lb), 0);
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;
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;
138 	}
139 	endfor
140     }
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;
165     register Seekaddr count;
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 
230     curline = srcline(pc);
231     filename = srcfilename(pc);
232     setsource(filename);
233     if (curline != 0) {
234 	cursrcline = curline;
235     }
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 }
249