148094Sbostic /*-
2*62146Sbostic  * Copyright (c) 1980, 1993
3*62146Sbostic  *	The Regents of the University of California.  All rights reserved.
448094Sbostic  *
548094Sbostic  * %sccs.include.redist.c%
622522Sdist  */
75521Slinton 
822522Sdist #ifndef lint
9*62146Sbostic static char sccsid[] = "@(#)source.c	8.1 (Berkeley) 06/06/93";
1048094Sbostic #endif /* not lint */
1148094Sbostic 
125521Slinton /*
135762Slinton  * Source file management.
145521Slinton  */
155521Slinton 
165521Slinton #include "defs.h"
175521Slinton #include "source.h"
185521Slinton 
195521Slinton /*
205762Slinton  * Seektab is the data structure used for indexing source
215762Slinton  * seek addresses by line number.
225521Slinton  *
235521Slinton  * The constraints are:
245521Slinton  *
255762Slinton  *  we want an array so indexing is fast and easy
265762Slinton  *  we don't want to waste space for small files
275762Slinton  *  we don't want an upper bound on # of lines in a file
285762Slinton  *  we don't know how many lines there are
295521Slinton  *
3011717Slinton  * The solution is a sparse array. We have NSLOTS pointers to
315521Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
325521Slinton  * a particular line we find the slot, allocate space if necessary,
335521Slinton  * and then find its location within the pointed to array.
345762Slinton  *
355762Slinton  * As a result, there is a limit of NSLOTS*NLINESPERSLOT lines per file
365762Slinton  * but this is plenty high and still fairly inexpensive.
375762Slinton  *
385762Slinton  * This implementation maintains only one source file at any given
395762Slinton  * so as to avoid consuming too much memory.  In an environment where
405762Slinton  * memory is less constrained and one expects to be changing between
415762Slinton  * files often enough, it would be reasonable to have multiple seek tables.
425521Slinton  */
435521Slinton 
445521Slinton typedef int SEEKADDR;
455521Slinton 
4611716Slinton #define NSLOTS 40
475521Slinton #define NLINESPERSLOT 500
485521Slinton 
4911717Slinton #define slotno(line)	((line)/NLINESPERSLOT)
5011717Slinton #define index(line)	((line)%NLINESPERSLOT)
5111717Slinton #define slot_alloc()	alloc(NLINESPERSLOT, SEEKADDR)
5211717Slinton #define srcaddr(line)	seektab[(line)/NLINESPERSLOT][(line)%NLINESPERSLOT]
535521Slinton 
545521Slinton LOCAL SEEKADDR *seektab[NSLOTS];
555521Slinton 
565521Slinton LOCAL FILE *srcfp;
575521Slinton 
585521Slinton /*
595521Slinton  * check to make sure a source line number is valid
605521Slinton  */
615521Slinton 
chkline(linenum)625521Slinton chkline(linenum)
635521Slinton register LINENO linenum;
645521Slinton {
655762Slinton     if (linenum < 1) {
665762Slinton 	error("line number must be positive");
675762Slinton     }
685762Slinton     if (linenum > lastlinenum) {
695762Slinton 	error("not that many lines");
705762Slinton     }
715521Slinton }
725521Slinton 
735521Slinton /*
745521Slinton  * print out the given lines from the source
755521Slinton  */
765521Slinton 
printlines(l1,l2)775521Slinton printlines(l1, l2)
785521Slinton LINENO l1, l2;
795521Slinton {
805762Slinton     register int c;
815762Slinton     register LINENO i;
825762Slinton     register FILE *fp;
835521Slinton 
845762Slinton     chkline(l1);
855762Slinton     chkline(l2);
865762Slinton     if (l2 < l1) {
875762Slinton 	error("second line number less than first");
885762Slinton     }
895762Slinton     fp = srcfp;
905762Slinton     fseek(fp, (long) srcaddr(l1), 0);
915762Slinton     for (i = l1; i <= l2; i++) {
925762Slinton 	printf("%5d   ", i);
935762Slinton 	while ((c = getc(fp)) != '\n') {
945762Slinton 	    putchar(c);
955521Slinton 	}
965762Slinton 	putchar('\n');
975762Slinton     }
985521Slinton }
995521Slinton 
1005521Slinton /*
1015521Slinton  * read the source file getting seek pointers for each line
1025521Slinton  */
1035521Slinton 
skimsource(file)1045521Slinton skimsource(file)
1055521Slinton char *file;
1065521Slinton {
1075762Slinton     register int c;
10811717Slinton     register SEEKADDR count;
1095762Slinton     register FILE *fp;
1105762Slinton     register LINENO linenum;
1115762Slinton     register SEEKADDR lastaddr;
1125762Slinton     register int slot;
1135521Slinton 
1145762Slinton     if (file == NIL || file == cursource) {
1155762Slinton 	return;
1165762Slinton     }
1175762Slinton     if ((fp = fopen(file, "r")) == NULL) {
1185762Slinton 	panic("can't open \"%s\"", file);
1195762Slinton     }
1205762Slinton     if (cursource != NIL) {
1215762Slinton 	free_seektab();
1225762Slinton     }
1235762Slinton     cursource = file;
1245762Slinton     linenum = 0, count = 0, lastaddr = 0;
1255762Slinton     while ((c = getc(fp)) != EOF) {
1265762Slinton 	count++;
1275762Slinton 	if (c == '\n') {
1285762Slinton 	    slot = slotno(++linenum);
1295762Slinton 	    if (slot >= NSLOTS) {
1305762Slinton 		panic("skimsource: too many lines");
1315762Slinton 	    }
1325762Slinton 	    if (seektab[slot] == NIL) {
1335762Slinton 		seektab[slot] = slot_alloc();
1345762Slinton 	    }
1355762Slinton 	    seektab[slot][index(linenum)] = lastaddr;
1365762Slinton 	    lastaddr = count;
1375521Slinton 	}
1385762Slinton     }
1395762Slinton     lastlinenum = linenum;
1405762Slinton     srcfp = fp;
1415521Slinton }
1425521Slinton 
1435521Slinton /*
1445521Slinton  * Erase information and release space in the current seektab.
1455521Slinton  * This is in preparation for reading in seek pointers for a
1465521Slinton  * new file.  It is possible that seek pointers for all files
1475521Slinton  * should be kept around, but the current concern is space.
1485521Slinton  */
1495521Slinton 
free_seektab()1505521Slinton LOCAL free_seektab()
1515521Slinton {
1525762Slinton     register int slot;
1535521Slinton 
1545762Slinton     for (slot = 0; slot < NSLOTS; slot++) {
1555762Slinton 	if (seektab[slot] != NIL) {
1565762Slinton 	    free(seektab[slot]);
1575762Slinton 	    seektab[slot] = NIL;
1585521Slinton 	}
1595762Slinton     }
1605521Slinton }
161