|
|
1.1 root 1: static char sccsid[] = "@(#)fio.c 4.2 8/17/82";
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: */
26: struct 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;
34: FILE *FIO; /* current open file (only 1 now) */
35: char 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: */
43: off_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: */
52: finit(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: */
123: fgetline()
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) {
140: case1:
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: */
183: fnext()
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: */
198: fprev()
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: */
213: fprint()
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: */
227: ffind(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: */
246: fback(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: */
262: fforward(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: */
279: fprintn(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.