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