15521Slinton /* Copyright (c) 1982 Regents of the University of California */ 25521Slinton 3*5762Slinton static char sccsid[] = "@(#)source.c 1.2 02/11/82"; 45521Slinton 55521Slinton /* 6*5762Slinton * Source file management. 75521Slinton */ 85521Slinton 95521Slinton #include "defs.h" 105521Slinton #include "source.h" 115521Slinton 125521Slinton /* 13*5762Slinton * Seektab is the data structure used for indexing source 14*5762Slinton * seek addresses by line number. 155521Slinton * 165521Slinton * The constraints are: 175521Slinton * 18*5762Slinton * we want an array so indexing is fast and easy 19*5762Slinton * we don't want to waste space for small files 20*5762Slinton * we don't want an upper bound on # of lines in a file 21*5762Slinton * we don't know how many lines there are 225521Slinton * 235521Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 245521Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 255521Slinton * a particular line we find the slot, allocate space if necessary, 265521Slinton * and then find its location within the pointed to array. 27*5762Slinton * 28*5762Slinton * As a result, there is a limit of NSLOTS*NLINESPERSLOT lines per file 29*5762Slinton * but this is plenty high and still fairly inexpensive. 30*5762Slinton * 31*5762Slinton * This implementation maintains only one source file at any given 32*5762Slinton * so as to avoid consuming too much memory. In an environment where 33*5762Slinton * memory is less constrained and one expects to be changing between 34*5762Slinton * files often enough, it would be reasonable to have multiple seek tables. 355521Slinton */ 365521Slinton 375521Slinton typedef int SEEKADDR; 385521Slinton 395521Slinton #define NSLOTS 20 405521Slinton #define NLINESPERSLOT 500 415521Slinton 42*5762Slinton #define slotno(line) ((line)/NLINESPERSLOT) 43*5762Slinton #define index(line) ((line)%NLINESPERSLOT) 44*5762Slinton #define slot_alloc() alloc(NLINESPERSLOT, SEEKADDR) 45*5762Slinton #define srcaddr(line) seektab[(line)/NLINESPERSLOT][(line)%NLINESPERSLOT] 465521Slinton 475521Slinton LOCAL SEEKADDR *seektab[NSLOTS]; 485521Slinton 495521Slinton LOCAL FILE *srcfp; 505521Slinton 515521Slinton /* 525521Slinton * check to make sure a source line number is valid 535521Slinton */ 545521Slinton 555521Slinton chkline(linenum) 565521Slinton register LINENO linenum; 575521Slinton { 58*5762Slinton if (linenum < 1) { 59*5762Slinton error("line number must be positive"); 60*5762Slinton } 61*5762Slinton if (linenum > lastlinenum) { 62*5762Slinton error("not that many lines"); 63*5762Slinton } 645521Slinton } 655521Slinton 665521Slinton /* 675521Slinton * print out the given lines from the source 685521Slinton */ 695521Slinton 705521Slinton printlines(l1, l2) 715521Slinton LINENO l1, l2; 725521Slinton { 73*5762Slinton register int c; 74*5762Slinton register LINENO i; 75*5762Slinton register FILE *fp; 765521Slinton 77*5762Slinton chkline(l1); 78*5762Slinton chkline(l2); 79*5762Slinton if (l2 < l1) { 80*5762Slinton error("second line number less than first"); 81*5762Slinton } 82*5762Slinton fp = srcfp; 83*5762Slinton fseek(fp, (long) srcaddr(l1), 0); 84*5762Slinton for (i = l1; i <= l2; i++) { 85*5762Slinton printf("%5d ", i); 86*5762Slinton while ((c = getc(fp)) != '\n') { 87*5762Slinton putchar(c); 885521Slinton } 89*5762Slinton putchar('\n'); 90*5762Slinton } 915521Slinton } 925521Slinton 935521Slinton /* 945521Slinton * read the source file getting seek pointers for each line 955521Slinton */ 965521Slinton 975521Slinton skimsource(file) 985521Slinton char *file; 995521Slinton { 100*5762Slinton register int c; 101*5762Slinton register LINENO count; 102*5762Slinton register FILE *fp; 103*5762Slinton register LINENO linenum; 104*5762Slinton register SEEKADDR lastaddr; 105*5762Slinton register int slot; 1065521Slinton 107*5762Slinton if (file == NIL || file == cursource) { 108*5762Slinton return; 109*5762Slinton } 110*5762Slinton if ((fp = fopen(file, "r")) == NULL) { 111*5762Slinton panic("can't open \"%s\"", file); 112*5762Slinton } 113*5762Slinton if (cursource != NIL) { 114*5762Slinton free_seektab(); 115*5762Slinton } 116*5762Slinton cursource = file; 117*5762Slinton linenum = 0, count = 0, lastaddr = 0; 118*5762Slinton while ((c = getc(fp)) != EOF) { 119*5762Slinton count++; 120*5762Slinton if (c == '\n') { 121*5762Slinton slot = slotno(++linenum); 122*5762Slinton if (slot >= NSLOTS) { 123*5762Slinton panic("skimsource: too many lines"); 124*5762Slinton } 125*5762Slinton if (seektab[slot] == NIL) { 126*5762Slinton seektab[slot] = slot_alloc(); 127*5762Slinton } 128*5762Slinton seektab[slot][index(linenum)] = lastaddr; 129*5762Slinton lastaddr = count; 1305521Slinton } 131*5762Slinton } 132*5762Slinton lastlinenum = linenum; 133*5762Slinton srcfp = fp; 1345521Slinton } 1355521Slinton 1365521Slinton /* 1375521Slinton * Erase information and release space in the current seektab. 1385521Slinton * This is in preparation for reading in seek pointers for a 1395521Slinton * new file. It is possible that seek pointers for all files 1405521Slinton * should be kept around, but the current concern is space. 1415521Slinton */ 1425521Slinton 1435521Slinton LOCAL free_seektab() 1445521Slinton { 145*5762Slinton register int slot; 1465521Slinton 147*5762Slinton for (slot = 0; slot < NSLOTS; slot++) { 148*5762Slinton if (seektab[slot] != NIL) { 149*5762Slinton free(seektab[slot]); 150*5762Slinton seektab[slot] = NIL; 1515521Slinton } 152*5762Slinton } 1535521Slinton } 154