1*48094Sbostic /*- 2*48094Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48094Sbostic * All rights reserved. 4*48094Sbostic * 5*48094Sbostic * %sccs.include.redist.c% 622522Sdist */ 75521Slinton 822522Sdist #ifndef lint 9*48094Sbostic static char sccsid[] = "@(#)source.c 5.2 (Berkeley) 04/16/91"; 10*48094Sbostic #endif /* not lint */ 11*48094Sbostic 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 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 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 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 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