xref: /csrg-svn/old/sdb/rdwr.c (revision 7776)
1*7776Srrh static	char sccsid[] = "@(#)rdwr.c 4.2 08/17/82";
21347Sbill /*
31347Sbill  * sdb - a symbolic debugger for unix - source file access routines.
41347Sbill  */
51347Sbill #include "head.h"
61347Sbill #include <stdio.h>
71347Sbill 
81347Sbill /*
91347Sbill  * These procedures manage the source files examined by sdb,
101347Sbill  * providing access to lines by number and utilities for printing
111347Sbill  * and scrolling.  One file is kept open by these routines, and
121347Sbill  * line index tables are maintained for all files which have been
131347Sbill  * ``current'' at any time so far.  This makes line access trivial,
141347Sbill  * since the location of each line in the files is known,
151347Sbill  * although we get ``burned'' if the file is changed.
161347Sbill  * SHOULD WATCH THE MODTIME OF FILES AND REINDEX IF IT CHANGES.
171347Sbill  */
181347Sbill 
191347Sbill /*
201347Sbill  * Structure for files which have been ``indexed''.
211347Sbill  * Contains a pointer to the file name, a pointer to an
221347Sbill  * array of seek pointers for the lines in the file,
231347Sbill  * and a next link in a chain of these for all files we have indexed,
241347Sbill  * The currently open file is cinfo->; the chain of active files is finfo.
251347Sbill  */
261347Sbill struct	finfo {
271347Sbill 	char	*name;			/* name of this file w/o common pfx */
281347Sbill 	off_t	*lines;			/* array of seek pointers */
291347Sbill /* line i stretches from lines[i-1] to lines[i] - 1, if first line is 1 */
301347Sbill 	int	nlines;			/* number of lines in file */
311347Sbill /* lines array actually has nlines+1 elements, so last line is bracketed */
321347Sbill 	struct	finfo *next;		/* link in chain of known files */
331347Sbill } *finfo, *cfile;
341347Sbill FILE	*FIO;				/* current open file (only 1 now) */
351347Sbill char	fibuf[BUFSIZ];
361347Sbill /*
371347Sbill  * We use stdio when first reading the file, but thereafter
381347Sbill  * use our own routines, because we want to be able
391347Sbill  * to read backwards efficiently and avoid a tell() system
401347Sbill  * call on each line.  Fseekpt remebers where we are in the current
411347Sbill  * file.
421347Sbill  */
431347Sbill off_t	fseekpt;
441347Sbill 
451347Sbill /*
461347Sbill  * Make ``name'' the current source file, if it isn't already.
471347Sbill  * If we have never seen this file before, then we create a finfo
481347Sbill  * structure for it indexing the lines (this requires reading the
491347Sbill  * entire file and building an index, but is well worth it since
501347Sbill  * we otherwise have to brute force search the files all the time.)
511347Sbill  */
finit(name)521347Sbill finit(name)
531347Sbill 	char *name;
541347Sbill {
551347Sbill 	char buf[BUFSIZ];
561347Sbill 	register off_t *lp;
571347Sbill 
581347Sbill 	if (cfile && !strcmp(cfile->name, name))
591347Sbill 		return;			/* its already current, do nothing */
601347Sbill 	/* IT WOULD BE BETTER TO HAVE A COUPLE OF FILE DESCRIPTORS, LRU */
611347Sbill 	if (FIO) {
621347Sbill 		fclose(FIO);
631347Sbill 		FIO = NULL;
641347Sbill 	}
651347Sbill 	/*
661347Sbill 	 * Paste the given name onto the common prefix (directory path)
671347Sbill 	 * to form the full name of the file to be opened.
681347Sbill 	 */
691347Sbill 	strcpy(fp, name);
701347Sbill 	if ((FIO = fopen(filework, "r")) == NULL) {
711347Sbill 		nolines = 1;
721347Sbill 		perror(filework);
731347Sbill 		return;
741347Sbill 	}
751347Sbill 	setbuf(FIO, fibuf);
761347Sbill 	fseekpt = -BUFSIZ;		/* putatively illegal */
771347Sbill 	strcpy(curfile, name);
781347Sbill 	/*
791347Sbill 	 * See if we have alread indexed this file.
801347Sbill 	 * If so, nothing much to do.
811347Sbill 	 */
821347Sbill 	for (cfile = finfo; cfile; cfile = cfile->next)
831347Sbill 		if (!strcmp(cfile->name, name))
841347Sbill 			return;
851347Sbill 	/*
861347Sbill 	 * Create a structure for this (new) file.
871347Sbill 	 * Lines array grows 100 lines at a time.
881347Sbill 	 * 1 extra so last line is bracketed.
891347Sbill 	 */
901347Sbill 	cfile = (struct finfo *)sbrk(sizeof (struct finfo));
911347Sbill 	lp = cfile->lines = (off_t *)sbrk(101 * sizeof (off_t));
921347Sbill 	*lp++ = 0;		/* line 1 starts at 0 ... */
931347Sbill 	cfile->nlines = 0;
941347Sbill 	/* IT WOULD PROBABLY BE FASTER TO JUST USE GETC AND LOOK FOR \n */
951347Sbill 	while (fgets(buf, sizeof buf, FIO)) {
961347Sbill 		if ((++cfile->nlines % 100) == 0)
971347Sbill 			sbrk(100 * sizeof (off_t));
981347Sbill 		/*
991347Sbill 		 * Mark end of the cfile->nlines'th line
1001347Sbill 		 */
1011347Sbill 		lp[0] = lp[-1] + strlen(buf);
1021347Sbill 		lp++;
1031347Sbill 	}
1041347Sbill 	if (cfile->nlines == 0) {
1051347Sbill 		printf("%s: no lines in file\n", filework);
1061347Sbill 		cfile = 0;
1071347Sbill 		return;
1081347Sbill 	}
1091347Sbill 	/*
1101347Sbill 	 * Allocate space for the name, making sure to leave the
1111347Sbill 	 * break on a word boundary.
1121347Sbill 	 * IT WOULD BE MUCH BETTER TO USE MALLOC AND REALLOC IN SDB.
1131347Sbill 	 */
1141347Sbill 	sbrk(lp + ((strlen(name)+sizeof(off_t)-1)&~(sizeof(off_t)-1)));
1151347Sbill 	strcpy(cfile->name = (char *)lp, name);
1161347Sbill 	cfile->next = finfo;
1171347Sbill 	finfo = cfile;
1181347Sbill }
1191347Sbill 
1201347Sbill /*
1211347Sbill  * Get the current line (fline) into fbuf
1221347Sbill  */
fgetline()1231347Sbill fgetline()
1241347Sbill {
1251347Sbill 	register off_t *op = &cfile->lines[fline-1];
1261347Sbill 	int o, n;
1271347Sbill 
1281347Sbill 	n = op[1] - op[0];
1291347Sbill 	fbuf[n] = 0;
1301347Sbill 	/*
1311347Sbill 	 * Case 1.  Line begins in current buffer.
1321347Sbill 	 *
1331347Sbill 	 * Compute the number of characters into the buffer where
1341347Sbill 	 * the line starts.  If this offset plus its length is greater
1351347Sbill 	 * than BUFSIZ, then this line splits across a buffer boundary
1361347Sbill 	 * so take the rest of this buffer and the first part of the next.
1371347Sbill 	 * Otherwise just take a chunk of this buffer.
1381347Sbill 	 */
1391347Sbill 	if (*op >= fseekpt && *op < fseekpt + BUFSIZ) {
1401347Sbill case1:
1411347Sbill 		o = op[0] - fseekpt;
1421347Sbill 		if (o + n > BUFSIZ) {
1431347Sbill 			strncpy(fbuf, fibuf+o, BUFSIZ-o);
1441347Sbill 			fseekpt += BUFSIZ;
1451347Sbill 			read(fileno(FIO), fibuf, BUFSIZ);
1461347Sbill 			strncpy(fbuf+BUFSIZ-o, fibuf, n-(BUFSIZ-o));
1471347Sbill 		} else
1481347Sbill 			strncpy(fbuf, fibuf+o, n);
1491347Sbill 		return;
1501347Sbill 	}
1511347Sbill 	/*
1521347Sbill 	 * Case 2.  Line ends in current buffer.
1531347Sbill 	 *
1541347Sbill 	 * If the line ends in this buffer (but doesn't begin in
1551347Sbill 	 * it or else we would have had case 1) take the beginning
1561347Sbill 	 * part of the buffer (end of the line) and then back up and
1571347Sbill 	 * get the rest of the line from the end of the previous block.
1581347Sbill 	 */
1591347Sbill 	if (op[1]-1 >= fseekpt && op[1] <= fseekpt+BUFSIZ) {
1601347Sbill 		o = op[1] - fseekpt;
1611347Sbill 		strncpy(fbuf+n-o, fibuf, o);
1621347Sbill 		fseekpt -= BUFSIZ;
1631347Sbill 		lseek(fileno(FIO), fseekpt, 0);
1641347Sbill 		read(fileno(FIO), fibuf, BUFSIZ);
1651347Sbill 		strncpy(fbuf, fibuf+op[0]-fseekpt, n-o);
1661347Sbill 		return;
1671347Sbill 	}
1681347Sbill 	/*
1691347Sbill 	 * Case 3.  Line not in current buffer at all.
1701347Sbill 	 *
1711347Sbill 	 * Read in the buffer where the line starts and then go
1721347Sbill 	 * back and handle as case 1.
1731347Sbill 	 */
1741347Sbill 	fseekpt = (op[0] / BUFSIZ) * BUFSIZ;
1751347Sbill 	lseek(fileno(FIO), fseekpt, 0);
1761347Sbill 	read(fileno(FIO), fibuf, BUFSIZ);
1771347Sbill 	goto case1;
1781347Sbill }
1791347Sbill 
1801347Sbill /*
1811347Sbill  * Advance current line, end-around (like for / search).
1821347Sbill  */
fnext()1831347Sbill fnext()
1841347Sbill {
1851347Sbill 
1861347Sbill 	if (cfile == 0)
1871347Sbill 		return;
1881347Sbill 	if (fline == cfile->nlines) {
1891347Sbill 		fline = 1;
1901347Sbill 	} else
1911347Sbill 		fline++;
1921347Sbill 	fgetline();
1931347Sbill }
1941347Sbill 
1951347Sbill /*
1961347Sbill  * Retreat the current line, end around.
1971347Sbill  */
fprev()1981347Sbill fprev()
1991347Sbill {
2001347Sbill 
2011347Sbill 	if (cfile == 0)
2021347Sbill 		return;
2031347Sbill 	if (fline == 1)
2041347Sbill 		fline = cfile->nlines;
2051347Sbill 	else
2061347Sbill 		fline--;
2071347Sbill 	fgetline();
2081347Sbill }
2091347Sbill 
2101347Sbill /*
2111347Sbill  * Print the current line.
2121347Sbill  */
fprint()2131347Sbill fprint()
2141347Sbill {
2151347Sbill 	register char *p;
2161347Sbill 
2171347Sbill 	if (cfile == 0) {
2181347Sbill 		error("No lines in file");
2191347Sbill 		return;
2201347Sbill 	}
2211347Sbill 	printf("%d: %s", fline, fbuf);
2221347Sbill }
2231347Sbill 
2241347Sbill /*
2251347Sbill  * Make line `num' current.
2261347Sbill  */
ffind(num)2271347Sbill ffind(num)
2281347Sbill 	register int num;
2291347Sbill {
2301347Sbill 
2311347Sbill 	if (cfile == 0)
2321347Sbill 		return;
2331347Sbill 	if (num > cfile->nlines)
2341347Sbill 		error("Not that many lines in file");
2351347Sbill 	else if (num <= 0)
2361347Sbill 		error("Zero or negative line?");
2371347Sbill 	else {
2381347Sbill 		fline = num;
2391347Sbill 		fgetline();
2401347Sbill 	}
2411347Sbill }
2421347Sbill 
2431347Sbill /*
2441347Sbill  * Go back n lines.
2451347Sbill  */
fback(n)2461347Sbill fback(n)
2471347Sbill {
2481347Sbill 	int i;
2491347Sbill 
2501347Sbill 	if (cfile == 0)
2511347Sbill 		return (0);
2521347Sbill 	if (n > fline - 1)
2531347Sbill 		n = fline - 1;
2541347Sbill 	fline -= n;
2551347Sbill 	fgetline();
2561347Sbill 	return (n);
2571347Sbill }
2581347Sbill 
2591347Sbill /*
2601347Sbill  * Go forwards n lines.
2611347Sbill  */
fforward(n)2621347Sbill fforward(n)
2631347Sbill 	int n;
2641347Sbill {
2651347Sbill 	register int fnext;
2661347Sbill 
2671347Sbill 	if (cfile == 0)
2681347Sbill 		return(0);
2691347Sbill 	if (fline + n > cfile->nlines)
2701347Sbill 		n = cfile->nlines - fline;
2711347Sbill 	fline += n;
2721347Sbill 	fgetline();
2731347Sbill 	return (n);
2741347Sbill }
2751347Sbill 
2761347Sbill /*
2771347Sbill  * Print (upto) n lines, returning number printed.
2781347Sbill  */
fprintn(n)2791347Sbill fprintn(n)
2801347Sbill 	int n;
2811347Sbill {
2821347Sbill 	register int i;
2831347Sbill 
2841347Sbill 	if (cfile == 0) {
2851347Sbill 		error("No lines in file");
2861347Sbill 		return (0);
2871347Sbill 	}
2881347Sbill 	for (i = 1; i <= n; i++) {
2891347Sbill 		fprint();
2901347Sbill 		if (fline == cfile->nlines || i == n)
2911347Sbill 			return(i);
2921347Sbill 		fnext();
2931347Sbill 	}
2941347Sbill 	return (n);
2951347Sbill }
296