BSD 4 development
[unix-history] / .ref-5cb41021d721f4e0ac572d592613f963e495d1ff / usr / src / old / sdb / fio.c
CommitLineData
c2e9dc00
BJ
1static char sccsid[] = "@(#)fio.c 4.1 %G%";
2/*
3 * sdb - a symbolic debugger for unix - source file access routines.
4 */
5#include "head.h"
6#include <stdio.h>
7
8/*
9 * These procedures manage the source files examined by sdb,
10 * providing access to lines by number and utilities for printing
11 * and scrolling. One file is kept open by these routines, and
12 * line index tables are maintained for all files which have been
13 * ``current'' at any time so far. This makes line access trivial,
14 * since the location of each line in the files is known,
15 * although we get ``burned'' if the file is changed.
16 * SHOULD WATCH THE MODTIME OF FILES AND REINDEX IF IT CHANGES.
17 */
18
19/*
20 * Structure for files which have been ``indexed''.
21 * Contains a pointer to the file name, a pointer to an
22 * array of seek pointers for the lines in the file,
23 * and a next link in a chain of these for all files we have indexed,
24 * The currently open file is cinfo->; the chain of active files is finfo.
25 */
26struct finfo {
27 char *name; /* name of this file w/o common pfx */
28 off_t *lines; /* array of seek pointers */
29/* line i stretches from lines[i-1] to lines[i] - 1, if first line is 1 */
30 int nlines; /* number of lines in file */
31/* lines array actually has nlines+1 elements, so last line is bracketed */
32 struct finfo *next; /* link in chain of known files */
33} *finfo, *cfile;
34FILE *FIO; /* current open file (only 1 now) */
35char fibuf[BUFSIZ];
36/*
37 * We use stdio when first reading the file, but thereafter
38 * use our own routines, because we want to be able
39 * to read backwards efficiently and avoid a tell() system
40 * call on each line. Fseekpt remebers where we are in the current
41 * file.
42 */
43off_t fseekpt;
44
45/*
46 * Make ``name'' the current source file, if it isn't already.
47 * If we have never seen this file before, then we create a finfo
48 * structure for it indexing the lines (this requires reading the
49 * entire file and building an index, but is well worth it since
50 * we otherwise have to brute force search the files all the time.)
51 */
52finit(name)
53 char *name;
54{
55 char buf[BUFSIZ];
56 register off_t *lp;
57
58 if (cfile && !strcmp(cfile->name, name))
59 return; /* its already current, do nothing */
60 /* IT WOULD BE BETTER TO HAVE A COUPLE OF FILE DESCRIPTORS, LRU */
61 if (FIO) {
62 fclose(FIO);
63 FIO = NULL;
64 }
65 /*
66 * Paste the given name onto the common prefix (directory path)
67 * to form the full name of the file to be opened.
68 */
69 strcpy(fp, name);
70 if ((FIO = fopen(filework, "r")) == NULL) {
71 nolines = 1;
72 perror(filework);
73 return;
74 }
75 setbuf(FIO, fibuf);
76 fseekpt = -BUFSIZ; /* putatively illegal */
77 strcpy(curfile, name);
78 /*
79 * See if we have alread indexed this file.
80 * If so, nothing much to do.
81 */
82 for (cfile = finfo; cfile; cfile = cfile->next)
83 if (!strcmp(cfile->name, name))
84 return;
85 /*
86 * Create a structure for this (new) file.
87 * Lines array grows 100 lines at a time.
88 * 1 extra so last line is bracketed.
89 */
90 cfile = (struct finfo *)sbrk(sizeof (struct finfo));
91 lp = cfile->lines = (off_t *)sbrk(101 * sizeof (off_t));
92 *lp++ = 0; /* line 1 starts at 0 ... */
93 cfile->nlines = 0;
94 /* IT WOULD PROBABLY BE FASTER TO JUST USE GETC AND LOOK FOR \n */
95 while (fgets(buf, sizeof buf, FIO)) {
96 if ((++cfile->nlines % 100) == 0)
97 sbrk(100 * sizeof (off_t));
98 /*
99 * Mark end of the cfile->nlines'th line
100 */
101 lp[0] = lp[-1] + strlen(buf);
102 lp++;
103 }
104 if (cfile->nlines == 0) {
105 printf("%s: no lines in file\n", filework);
106 cfile = 0;
107 return;
108 }
109 /*
110 * Allocate space for the name, making sure to leave the
111 * break on a word boundary.
112 * IT WOULD BE MUCH BETTER TO USE MALLOC AND REALLOC IN SDB.
113 */
114 sbrk(lp + ((strlen(name)+sizeof(off_t)-1)&~(sizeof(off_t)-1)));
115 strcpy(cfile->name = (char *)lp, name);
116 cfile->next = finfo;
117 finfo = cfile;
118}
119
120/*
121 * Get the current line (fline) into fbuf
122 */
123fgetline()
124{
125 register off_t *op = &cfile->lines[fline-1];
126 int o, n;
127
128 n = op[1] - op[0];
129 fbuf[n] = 0;
130 /*
131 * Case 1. Line begins in current buffer.
132 *
133 * Compute the number of characters into the buffer where
134 * the line starts. If this offset plus its length is greater
135 * than BUFSIZ, then this line splits across a buffer boundary
136 * so take the rest of this buffer and the first part of the next.
137 * Otherwise just take a chunk of this buffer.
138 */
139 if (*op >= fseekpt && *op < fseekpt + BUFSIZ) {
140case1:
141 o = op[0] - fseekpt;
142 if (o + n > BUFSIZ) {
143 strncpy(fbuf, fibuf+o, BUFSIZ-o);
144 fseekpt += BUFSIZ;
145 read(fileno(FIO), fibuf, BUFSIZ);
146 strncpy(fbuf+BUFSIZ-o, fibuf, n-(BUFSIZ-o));
147 } else
148 strncpy(fbuf, fibuf+o, n);
149 return;
150 }
151 /*
152 * Case 2. Line ends in current buffer.
153 *
154 * If the line ends in this buffer (but doesn't begin in
155 * it or else we would have had case 1) take the beginning
156 * part of the buffer (end of the line) and then back up and
157 * get the rest of the line from the end of the previous block.
158 */
159 if (op[1]-1 >= fseekpt && op[1] <= fseekpt+BUFSIZ) {
160 o = op[1] - fseekpt;
161 strncpy(fbuf+n-o, fibuf, o);
162 fseekpt -= BUFSIZ;
163 lseek(fileno(FIO), fseekpt, 0);
164 read(fileno(FIO), fibuf, BUFSIZ);
165 strncpy(fbuf, fibuf+op[0]-fseekpt, n-o);
166 return;
167 }
168 /*
169 * Case 3. Line not in current buffer at all.
170 *
171 * Read in the buffer where the line starts and then go
172 * back and handle as case 1.
173 */
174 fseekpt = (op[0] / BUFSIZ) * BUFSIZ;
175 lseek(fileno(FIO), fseekpt, 0);
176 read(fileno(FIO), fibuf, BUFSIZ);
177 goto case1;
178}
179
180/*
181 * Advance current line, end-around (like for / search).
182 */
183fnext()
184{
185
186 if (cfile == 0)
187 return;
188 if (fline == cfile->nlines) {
189 fline = 1;
190 } else
191 fline++;
192 fgetline();
193}
194
195/*
196 * Retreat the current line, end around.
197 */
198fprev()
199{
200
201 if (cfile == 0)
202 return;
203 if (fline == 1)
204 fline = cfile->nlines;
205 else
206 fline--;
207 fgetline();
208}
209
210/*
211 * Print the current line.
212 */
213fprint()
214{
215 register char *p;
216
217 if (cfile == 0) {
218 error("No lines in file");
219 return;
220 }
221 printf("%d: %s", fline, fbuf);
222}
223
224/*
225 * Make line `num' current.
226 */
227ffind(num)
228 register int num;
229{
230
231 if (cfile == 0)
232 return;
233 if (num > cfile->nlines)
234 error("Not that many lines in file");
235 else if (num <= 0)
236 error("Zero or negative line?");
237 else {
238 fline = num;
239 fgetline();
240 }
241}
242
243/*
244 * Go back n lines.
245 */
246fback(n)
247{
248 int i;
249
250 if (cfile == 0)
251 return (0);
252 if (n > fline - 1)
253 n = fline - 1;
254 fline -= n;
255 fgetline();
256 return (n);
257}
258
259/*
260 * Go forwards n lines.
261 */
262fforward(n)
263 int n;
264{
265 register int fnext;
266
267 if (cfile == 0)
268 return(0);
269 if (fline + n > cfile->nlines)
270 n = cfile->nlines - fline;
271 fline += n;
272 fgetline();
273 return (n);
274}
275
276/*
277 * Print (upto) n lines, returning number printed.
278 */
279fprintn(n)
280 int n;
281{
282 register int i;
283
284 if (cfile == 0) {
285 error("No lines in file");
286 return (0);
287 }
288 for (i = 1; i <= n; i++) {
289 fprint();
290 if (fline == cfile->nlines || i == n)
291 return(i);
292 fnext();
293 }
294 return (n);
295}