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