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