1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)source.c 1.4 03/24/83"; 4 5 /* 6 * Source file management. 7 */ 8 9 #include "defs.h" 10 #include "source.h" 11 12 /* 13 * Seektab is the data structure used for indexing source 14 * seek addresses by line number. 15 * 16 * The constraints are: 17 * 18 * we want an array so indexing is fast and easy 19 * we don't want to waste space for small files 20 * we don't want an upper bound on # of lines in a file 21 * we don't know how many lines there are 22 * 23 * The solution is a sparse array. We have NSLOTS pointers to 24 * arrays of NLINESPERSLOT addresses. To find the source address of 25 * a particular line we find the slot, allocate space if necessary, 26 * and then find its location within the pointed to array. 27 * 28 * As a result, there is a limit of NSLOTS*NLINESPERSLOT lines per file 29 * but this is plenty high and still fairly inexpensive. 30 * 31 * This implementation maintains only one source file at any given 32 * so as to avoid consuming too much memory. In an environment where 33 * memory is less constrained and one expects to be changing between 34 * files often enough, it would be reasonable to have multiple seek tables. 35 */ 36 37 typedef int SEEKADDR; 38 39 #define NSLOTS 40 40 #define NLINESPERSLOT 500 41 42 #define slotno(line) ((line)/NLINESPERSLOT) 43 #define index(line) ((line)%NLINESPERSLOT) 44 #define slot_alloc() alloc(NLINESPERSLOT, SEEKADDR) 45 #define srcaddr(line) seektab[(line)/NLINESPERSLOT][(line)%NLINESPERSLOT] 46 47 LOCAL SEEKADDR *seektab[NSLOTS]; 48 49 LOCAL FILE *srcfp; 50 51 /* 52 * check to make sure a source line number is valid 53 */ 54 55 chkline(linenum) 56 register LINENO linenum; 57 { 58 if (linenum < 1) { 59 error("line number must be positive"); 60 } 61 if (linenum > lastlinenum) { 62 error("not that many lines"); 63 } 64 } 65 66 /* 67 * print out the given lines from the source 68 */ 69 70 printlines(l1, l2) 71 LINENO l1, l2; 72 { 73 register int c; 74 register LINENO i; 75 register FILE *fp; 76 77 chkline(l1); 78 chkline(l2); 79 if (l2 < l1) { 80 error("second line number less than first"); 81 } 82 fp = srcfp; 83 fseek(fp, (long) srcaddr(l1), 0); 84 for (i = l1; i <= l2; i++) { 85 printf("%5d ", i); 86 while ((c = getc(fp)) != '\n') { 87 putchar(c); 88 } 89 putchar('\n'); 90 } 91 } 92 93 /* 94 * read the source file getting seek pointers for each line 95 */ 96 97 skimsource(file) 98 char *file; 99 { 100 register int c; 101 register SEEKADDR count; 102 register FILE *fp; 103 register LINENO linenum; 104 register SEEKADDR lastaddr; 105 register int slot; 106 107 if (file == NIL || file == cursource) { 108 return; 109 } 110 if ((fp = fopen(file, "r")) == NULL) { 111 panic("can't open \"%s\"", file); 112 } 113 if (cursource != NIL) { 114 free_seektab(); 115 } 116 cursource = file; 117 linenum = 0, count = 0, lastaddr = 0; 118 while ((c = getc(fp)) != EOF) { 119 count++; 120 if (c == '\n') { 121 slot = slotno(++linenum); 122 if (slot >= NSLOTS) { 123 panic("skimsource: too many lines"); 124 } 125 if (seektab[slot] == NIL) { 126 seektab[slot] = slot_alloc(); 127 } 128 seektab[slot][index(linenum)] = lastaddr; 129 lastaddr = count; 130 } 131 } 132 lastlinenum = linenum; 133 srcfp = fp; 134 } 135 136 /* 137 * Erase information and release space in the current seektab. 138 * This is in preparation for reading in seek pointers for a 139 * new file. It is possible that seek pointers for all files 140 * should be kept around, but the current concern is space. 141 */ 142 143 LOCAL free_seektab() 144 { 145 register int slot; 146 147 for (slot = 0; slot < NSLOTS; slot++) { 148 if (seektab[slot] != NIL) { 149 free(seektab[slot]); 150 seektab[slot] = NIL; 151 } 152 } 153 } 154