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