1*22522Sdist /*
2*22522Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22522Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22522Sdist  * specifies the terms and conditions for redistribution.
5*22522Sdist  */
65521Slinton 
7*22522Sdist #ifndef lint
8*22522Sdist static char sccsid[] = "@(#)source.c	5.1 (Berkeley) 06/06/85";
9*22522Sdist #endif not lint
105521Slinton /*
115762Slinton  * Source file management.
125521Slinton  */
135521Slinton 
145521Slinton #include "defs.h"
155521Slinton #include "source.h"
165521Slinton 
175521Slinton /*
185762Slinton  * Seektab is the data structure used for indexing source
195762Slinton  * seek addresses by line number.
205521Slinton  *
215521Slinton  * The constraints are:
225521Slinton  *
235762Slinton  *  we want an array so indexing is fast and easy
245762Slinton  *  we don't want to waste space for small files
255762Slinton  *  we don't want an upper bound on # of lines in a file
265762Slinton  *  we don't know how many lines there are
275521Slinton  *
2811717Slinton  * The solution is a sparse array. We have NSLOTS pointers to
295521Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
305521Slinton  * a particular line we find the slot, allocate space if necessary,
315521Slinton  * and then find its location within the pointed to array.
325762Slinton  *
335762Slinton  * As a result, there is a limit of NSLOTS*NLINESPERSLOT lines per file
345762Slinton  * but this is plenty high and still fairly inexpensive.
355762Slinton  *
365762Slinton  * This implementation maintains only one source file at any given
375762Slinton  * so as to avoid consuming too much memory.  In an environment where
385762Slinton  * memory is less constrained and one expects to be changing between
395762Slinton  * files often enough, it would be reasonable to have multiple seek tables.
405521Slinton  */
415521Slinton 
425521Slinton typedef int SEEKADDR;
435521Slinton 
4411716Slinton #define NSLOTS 40
455521Slinton #define NLINESPERSLOT 500
465521Slinton 
4711717Slinton #define slotno(line)	((line)/NLINESPERSLOT)
4811717Slinton #define index(line)	((line)%NLINESPERSLOT)
4911717Slinton #define slot_alloc()	alloc(NLINESPERSLOT, SEEKADDR)
5011717Slinton #define srcaddr(line)	seektab[(line)/NLINESPERSLOT][(line)%NLINESPERSLOT]
515521Slinton 
525521Slinton LOCAL SEEKADDR *seektab[NSLOTS];
535521Slinton 
545521Slinton LOCAL FILE *srcfp;
555521Slinton 
565521Slinton /*
575521Slinton  * check to make sure a source line number is valid
585521Slinton  */
595521Slinton 
605521Slinton chkline(linenum)
615521Slinton register LINENO linenum;
625521Slinton {
635762Slinton     if (linenum < 1) {
645762Slinton 	error("line number must be positive");
655762Slinton     }
665762Slinton     if (linenum > lastlinenum) {
675762Slinton 	error("not that many lines");
685762Slinton     }
695521Slinton }
705521Slinton 
715521Slinton /*
725521Slinton  * print out the given lines from the source
735521Slinton  */
745521Slinton 
755521Slinton printlines(l1, l2)
765521Slinton LINENO l1, l2;
775521Slinton {
785762Slinton     register int c;
795762Slinton     register LINENO i;
805762Slinton     register FILE *fp;
815521Slinton 
825762Slinton     chkline(l1);
835762Slinton     chkline(l2);
845762Slinton     if (l2 < l1) {
855762Slinton 	error("second line number less than first");
865762Slinton     }
875762Slinton     fp = srcfp;
885762Slinton     fseek(fp, (long) srcaddr(l1), 0);
895762Slinton     for (i = l1; i <= l2; i++) {
905762Slinton 	printf("%5d   ", i);
915762Slinton 	while ((c = getc(fp)) != '\n') {
925762Slinton 	    putchar(c);
935521Slinton 	}
945762Slinton 	putchar('\n');
955762Slinton     }
965521Slinton }
975521Slinton 
985521Slinton /*
995521Slinton  * read the source file getting seek pointers for each line
1005521Slinton  */
1015521Slinton 
1025521Slinton skimsource(file)
1035521Slinton char *file;
1045521Slinton {
1055762Slinton     register int c;
10611717Slinton     register SEEKADDR count;
1075762Slinton     register FILE *fp;
1085762Slinton     register LINENO linenum;
1095762Slinton     register SEEKADDR lastaddr;
1105762Slinton     register int slot;
1115521Slinton 
1125762Slinton     if (file == NIL || file == cursource) {
1135762Slinton 	return;
1145762Slinton     }
1155762Slinton     if ((fp = fopen(file, "r")) == NULL) {
1165762Slinton 	panic("can't open \"%s\"", file);
1175762Slinton     }
1185762Slinton     if (cursource != NIL) {
1195762Slinton 	free_seektab();
1205762Slinton     }
1215762Slinton     cursource = file;
1225762Slinton     linenum = 0, count = 0, lastaddr = 0;
1235762Slinton     while ((c = getc(fp)) != EOF) {
1245762Slinton 	count++;
1255762Slinton 	if (c == '\n') {
1265762Slinton 	    slot = slotno(++linenum);
1275762Slinton 	    if (slot >= NSLOTS) {
1285762Slinton 		panic("skimsource: too many lines");
1295762Slinton 	    }
1305762Slinton 	    if (seektab[slot] == NIL) {
1315762Slinton 		seektab[slot] = slot_alloc();
1325762Slinton 	    }
1335762Slinton 	    seektab[slot][index(linenum)] = lastaddr;
1345762Slinton 	    lastaddr = count;
1355521Slinton 	}
1365762Slinton     }
1375762Slinton     lastlinenum = linenum;
1385762Slinton     srcfp = fp;
1395521Slinton }
1405521Slinton 
1415521Slinton /*
1425521Slinton  * Erase information and release space in the current seektab.
1435521Slinton  * This is in preparation for reading in seek pointers for a
1445521Slinton  * new file.  It is possible that seek pointers for all files
1455521Slinton  * should be kept around, but the current concern is space.
1465521Slinton  */
1475521Slinton 
1485521Slinton LOCAL free_seektab()
1495521Slinton {
1505762Slinton     register int slot;
1515521Slinton 
1525762Slinton     for (slot = 0; slot < NSLOTS; slot++) {
1535762Slinton 	if (seektab[slot] != NIL) {
1545762Slinton 	    free(seektab[slot]);
1555762Slinton 	    seektab[slot] = NIL;
1565521Slinton 	}
1575762Slinton     }
1585521Slinton }
159