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