X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/9fffe4230c434a04ac1a760a8057e9c8244a3243..31cef89cb428866f787983e68246030321893df4:/usr/src/cmd/sdb/fio.c diff --git a/usr/src/cmd/sdb/fio.c b/usr/src/cmd/sdb/fio.c index e56660e096..1cf1275fe6 100644 --- a/usr/src/cmd/sdb/fio.c +++ b/usr/src/cmd/sdb/fio.c @@ -1,137 +1,295 @@ +static char sccsid[] = "@(#)fio.c 4.1 10/9/80"; +/* + * sdb - a symbolic debugger for unix - source file access routines. + */ #include "head.h" +#include +/* + * These procedures manage the source files examined by sdb, + * providing access to lines by number and utilities for printing + * and scrolling. One file is kept open by these routines, and + * line index tables are maintained for all files which have been + * ``current'' at any time so far. This makes line access trivial, + * since the location of each line in the files is known, + * although we get ``burned'' if the file is changed. + * SHOULD WATCH THE MODTIME OF FILES AND REINDEX IF IT CHANGES. + */ + +/* + * Structure for files which have been ``indexed''. + * Contains a pointer to the file name, a pointer to an + * array of seek pointers for the lines in the file, + * and a next link in a chain of these for all files we have indexed, + * The currently open file is cinfo->; the chain of active files is finfo. + */ +struct finfo { + char *name; /* name of this file w/o common pfx */ + off_t *lines; /* array of seek pointers */ +/* line i stretches from lines[i-1] to lines[i] - 1, if first line is 1 */ + int nlines; /* number of lines in file */ +/* lines array actually has nlines+1 elements, so last line is bracketed */ + struct finfo *next; /* link in chain of known files */ +} *finfo, *cfile; +FILE *FIO; /* current open file (only 1 now) */ +char fibuf[BUFSIZ]; +/* + * We use stdio when first reading the file, but thereafter + * use our own routines, because we want to be able + * to read backwards efficiently and avoid a tell() system + * call on each line. Fseekpt remebers where we are in the current + * file. + */ +off_t fseekpt; + +/* + * Make ``name'' the current source file, if it isn't already. + * If we have never seen this file before, then we create a finfo + * structure for it indexing the lines (this requires reading the + * entire file and building an index, but is well worth it since + * we otherwise have to brute force search the files all the time.) + */ finit(name) -char *name; { - register char *p, *q; + char *name; +{ + char buf[BUFSIZ]; + register off_t *lp; - if (fiobuf.fd) close(fiobuf.fd); - q = name; - for (p=fp; *q; *p++ = *q++) ; - *p = 0; - if ((fiobuf.fd = open(filework,0)) == -1) { + if (cfile && !strcmp(cfile->name, name)) + return; /* its already current, do nothing */ + /* IT WOULD BE BETTER TO HAVE A COUPLE OF FILE DESCRIPTORS, LRU */ + if (FIO) { + fclose(FIO); + FIO = NULL; + } + /* + * Paste the given name onto the common prefix (directory path) + * to form the full name of the file to be opened. + */ + strcpy(fp, name); + if ((FIO = fopen(filework, "r")) == NULL) { + nolines = 1; perror(filework); return; } - binit(&fiobuf); - cpstr(curfile, name); - for (p=fbuf;;p++) { - if (bread(&fiobuf,p,1) <= 0) { - printf("%s - No lines in file\n", name); + setbuf(FIO, fibuf); + fseekpt = -BUFSIZ; /* putatively illegal */ + strcpy(curfile, name); + /* + * See if we have alread indexed this file. + * If so, nothing much to do. + */ + for (cfile = finfo; cfile; cfile = cfile->next) + if (!strcmp(cfile->name, name)) return; - } - if (*p == '\n') break; + /* + * Create a structure for this (new) file. + * Lines array grows 100 lines at a time. + * 1 extra so last line is bracketed. + */ + cfile = (struct finfo *)sbrk(sizeof (struct finfo)); + lp = cfile->lines = (off_t *)sbrk(101 * sizeof (off_t)); + *lp++ = 0; /* line 1 starts at 0 ... */ + cfile->nlines = 0; + /* IT WOULD PROBABLY BE FASTER TO JUST USE GETC AND LOOK FOR \n */ + while (fgets(buf, sizeof buf, FIO)) { + if ((++cfile->nlines % 100) == 0) + sbrk(100 * sizeof (off_t)); + /* + * Mark end of the cfile->nlines'th line + */ + lp[0] = lp[-1] + strlen(buf); + lp++; } - fline = 1; - maxfline = 0; -} - -fnext() { - register char *p; - - for(p=fbuf;;p++) { - if (bread(&fiobuf,p,1) <= 0) { - p--; - blseek(&fiobuf,0L,0); - fline = 0; - continue; - } - if (*p == '\n') break; + if (cfile->nlines == 0) { + printf("%s: no lines in file\n", filework); + cfile = 0; + return; } - fline++; + /* + * Allocate space for the name, making sure to leave the + * break on a word boundary. + * IT WOULD BE MUCH BETTER TO USE MALLOC AND REALLOC IN SDB. + */ + sbrk(lp + ((strlen(name)+sizeof(off_t)-1)&~(sizeof(off_t)-1))); + strcpy(cfile->name = (char *)lp, name); + cfile->next = finfo; + finfo = cfile; } +/* + * Get the current line (fline) into fbuf + */ +fgetline() +{ + register off_t *op = &cfile->lines[fline-1]; + int o, n; -fprev() { - char c; - register int i; - - for(i=0; i<3; i++) { - for (;;) { - if (bread(&fiobuf, &c+1, -1) <= 0) { - if (maxfline) blseek(&fiobuf,0L,2); - else { - blseek(&fiobuf,0L,0); - for(;;) { - if (bread(&fiobuf,&c,1)<=0) break; - if (c == '\n') maxfline++; - } - } - } - if (c == '\n') break; - } + n = op[1] - op[0]; + fbuf[n] = 0; + /* + * Case 1. Line begins in current buffer. + * + * Compute the number of characters into the buffer where + * the line starts. If this offset plus its length is greater + * than BUFSIZ, then this line splits across a buffer boundary + * so take the rest of this buffer and the first part of the next. + * Otherwise just take a chunk of this buffer. + */ + if (*op >= fseekpt && *op < fseekpt + BUFSIZ) { +case1: + o = op[0] - fseekpt; + if (o + n > BUFSIZ) { + strncpy(fbuf, fibuf+o, BUFSIZ-o); + fseekpt += BUFSIZ; + read(fileno(FIO), fibuf, BUFSIZ); + strncpy(fbuf+BUFSIZ-o, fibuf, n-(BUFSIZ-o)); + } else + strncpy(fbuf, fibuf+o, n); + return; } - bread(&fiobuf, &c, 1); /* eat the '\n' */ - - fline -= 2; - if (fline < 0) fline = maxfline - 1; + /* + * Case 2. Line ends in current buffer. + * + * If the line ends in this buffer (but doesn't begin in + * it or else we would have had case 1) take the beginning + * part of the buffer (end of the line) and then back up and + * get the rest of the line from the end of the previous block. + */ + if (op[1]-1 >= fseekpt && op[1] <= fseekpt+BUFSIZ) { + o = op[1] - fseekpt; + strncpy(fbuf+n-o, fibuf, o); + fseekpt -= BUFSIZ; + lseek(fileno(FIO), fseekpt, 0); + read(fileno(FIO), fibuf, BUFSIZ); + strncpy(fbuf, fibuf+op[0]-fseekpt, n-o); + return; + } + /* + * Case 3. Line not in current buffer at all. + * + * Read in the buffer where the line starts and then go + * back and handle as case 1. + */ + fseekpt = (op[0] / BUFSIZ) * BUFSIZ; + lseek(fileno(FIO), fseekpt, 0); + read(fileno(FIO), fibuf, BUFSIZ); + goto case1; +} + +/* + * Advance current line, end-around (like for / search). + */ +fnext() +{ - fnext(); + if (cfile == 0) + return; + if (fline == cfile->nlines) { + fline = 1; + } else + fline++; + fgetline(); } +/* + * Retreat the current line, end around. + */ +fprev() +{ -fprint() { + if (cfile == 0) + return; + if (fline == 1) + fline = cfile->nlines; + else + fline--; + fgetline(); +} + +/* + * Print the current line. + */ +fprint() +{ register char *p; - printf("%d: ", fline); - p = fbuf; - while(putchar(*p++) != '\n') - ; + if (cfile == 0) { + error("No lines in file"); + return; + } + printf("%d: %s", fline, fbuf); } +/* + * Make line `num' current. + */ ffind(num) -register int num; { - register int i, ofline; - - ofline = fline; - if (num>fline) - for (i=fline; imaxfline) goto bad; + register int num; +{ - return; - -bad: error("Not that many lines in file"); - ffind(ofline); + if (cfile == 0) + return; + if (num > cfile->nlines) + error("Not that many lines in file"); + else if (num <= 0) + error("Zero or negative line?"); + else { + fline = num; + fgetline(); + } } -fback(n) { +/* + * Go back n lines. + */ +fback(n) +{ int i; - for (i=0; i fline - 1) + n = fline - 1; + fline -= n; + fgetline(); + return (n); } -fforward(n) { - int i; +/* + * Go forwards n lines. + */ +fforward(n) + int n; +{ + register int fnext; - for (i=0; i cfile->nlines) + n = cfile->nlines - fline; + fline += n; + fgetline(); + return (n); } -fprintn(n) { - int i; +/* + * Print (upto) n lines, returning number printed. + */ +fprintn(n) + int n; +{ + register int i; - for (i=0; inlines || i == n) + return(i); fnext(); - if (fline == 1) break; } - fprev(); - return(i); + return (n); }