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