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