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