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