|
|
1.1 ! root 1: static char sccsid[] = "@(#)fio.c 4.1 10/9/80"; ! 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.