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