1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)source.c 8.1 (Berkeley) 06/06/93";
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
chkline(linenum)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
printlines(l1,l2)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
skimsource(file)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
free_seektab()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