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