15521Slinton /* Copyright (c) 1982 Regents of the University of California */ 25521Slinton 3*11716Slinton static char sccsid[] = "@(#)source.c 1.3 03/24/83"; 45521Slinton 55521Slinton /* 65762Slinton * Source file management. 75521Slinton */ 85521Slinton 95521Slinton #include "defs.h" 105521Slinton #include "source.h" 115521Slinton 125521Slinton /* 135762Slinton * Seektab is the data structure used for indexing source 145762Slinton * seek addresses by line number. 155521Slinton * 165521Slinton * The constraints are: 175521Slinton * 185762Slinton * we want an array so indexing is fast and easy 195762Slinton * we don't want to waste space for small files 205762Slinton * we don't want an upper bound on # of lines in a file 215762Slinton * we don't know how many lines there are 225521Slinton * 235521Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 245521Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 255521Slinton * a particular line we find the slot, allocate space if necessary, 265521Slinton * and then find its location within the pointed to array. 275762Slinton * 285762Slinton * As a result, there is a limit of NSLOTS*NLINESPERSLOT lines per file 295762Slinton * but this is plenty high and still fairly inexpensive. 305762Slinton * 315762Slinton * This implementation maintains only one source file at any given 325762Slinton * so as to avoid consuming too much memory. In an environment where 335762Slinton * memory is less constrained and one expects to be changing between 345762Slinton * files often enough, it would be reasonable to have multiple seek tables. 355521Slinton */ 365521Slinton 375521Slinton typedef int SEEKADDR; 385521Slinton 39*11716Slinton #define NSLOTS 40 405521Slinton #define NLINESPERSLOT 500 415521Slinton 425762Slinton #define slotno(line) ((line)/NLINESPERSLOT) 435762Slinton #define index(line) ((line)%NLINESPERSLOT) 445762Slinton #define slot_alloc() alloc(NLINESPERSLOT, SEEKADDR) 455762Slinton #define srcaddr(line) seektab[(line)/NLINESPERSLOT][(line)%NLINESPERSLOT] 465521Slinton 475521Slinton LOCAL SEEKADDR *seektab[NSLOTS]; 485521Slinton 495521Slinton LOCAL FILE *srcfp; 505521Slinton 515521Slinton /* 525521Slinton * check to make sure a source line number is valid 535521Slinton */ 545521Slinton 555521Slinton chkline(linenum) 565521Slinton register LINENO linenum; 575521Slinton { 585762Slinton if (linenum < 1) { 595762Slinton error("line number must be positive"); 605762Slinton } 615762Slinton if (linenum > lastlinenum) { 625762Slinton error("not that many lines"); 635762Slinton } 645521Slinton } 655521Slinton 665521Slinton /* 675521Slinton * print out the given lines from the source 685521Slinton */ 695521Slinton 705521Slinton printlines(l1, l2) 715521Slinton LINENO l1, l2; 725521Slinton { 735762Slinton register int c; 745762Slinton register LINENO i; 755762Slinton register FILE *fp; 765521Slinton 775762Slinton chkline(l1); 785762Slinton chkline(l2); 795762Slinton if (l2 < l1) { 805762Slinton error("second line number less than first"); 815762Slinton } 825762Slinton fp = srcfp; 835762Slinton fseek(fp, (long) srcaddr(l1), 0); 845762Slinton for (i = l1; i <= l2; i++) { 855762Slinton printf("%5d ", i); 865762Slinton while ((c = getc(fp)) != '\n') { 875762Slinton putchar(c); 885521Slinton } 895762Slinton putchar('\n'); 905762Slinton } 915521Slinton } 925521Slinton 935521Slinton /* 945521Slinton * read the source file getting seek pointers for each line 955521Slinton */ 965521Slinton 975521Slinton skimsource(file) 985521Slinton char *file; 995521Slinton { 1005762Slinton register int c; 1015762Slinton register LINENO count; 1025762Slinton register FILE *fp; 1035762Slinton register LINENO linenum; 1045762Slinton register SEEKADDR lastaddr; 1055762Slinton register int slot; 1065521Slinton 1075762Slinton if (file == NIL || file == cursource) { 1085762Slinton return; 1095762Slinton } 1105762Slinton if ((fp = fopen(file, "r")) == NULL) { 1115762Slinton panic("can't open \"%s\"", file); 1125762Slinton } 1135762Slinton if (cursource != NIL) { 1145762Slinton free_seektab(); 1155762Slinton } 1165762Slinton cursource = file; 1175762Slinton linenum = 0, count = 0, lastaddr = 0; 1185762Slinton while ((c = getc(fp)) != EOF) { 1195762Slinton count++; 1205762Slinton if (c == '\n') { 1215762Slinton slot = slotno(++linenum); 1225762Slinton if (slot >= NSLOTS) { 1235762Slinton panic("skimsource: too many lines"); 1245762Slinton } 1255762Slinton if (seektab[slot] == NIL) { 1265762Slinton seektab[slot] = slot_alloc(); 1275762Slinton } 1285762Slinton seektab[slot][index(linenum)] = lastaddr; 1295762Slinton lastaddr = count; 1305521Slinton } 1315762Slinton } 1325762Slinton lastlinenum = linenum; 1335762Slinton srcfp = fp; 1345521Slinton } 1355521Slinton 1365521Slinton /* 1375521Slinton * Erase information and release space in the current seektab. 1385521Slinton * This is in preparation for reading in seek pointers for a 1395521Slinton * new file. It is possible that seek pointers for all files 1405521Slinton * should be kept around, but the current concern is space. 1415521Slinton */ 1425521Slinton 1435521Slinton LOCAL free_seektab() 1445521Slinton { 1455762Slinton register int slot; 1465521Slinton 1475762Slinton for (slot = 0; slot < NSLOTS; slot++) { 1485762Slinton if (seektab[slot] != NIL) { 1495762Slinton free(seektab[slot]); 1505762Slinton seektab[slot] = NIL; 1515521Slinton } 1525762Slinton } 1535521Slinton } 154