19680Slinton /* Copyright (c) 1982 Regents of the University of California */ 29680Slinton 3*12608Slinton static char sccsid[] = "@(#)source.c 1.8 05/20/83"; 49680Slinton 59680Slinton /* 69680Slinton * Source file management. 79680Slinton */ 89680Slinton 99680Slinton #include "defs.h" 109680Slinton #include "source.h" 119680Slinton #include "object.h" 129680Slinton #include "mappings.h" 139680Slinton #include "machine.h" 149680Slinton 159680Slinton #ifndef public 169680Slinton typedef int Lineno; 179680Slinton 189680Slinton String cursource; 199680Slinton Lineno curline; 209680Slinton Lineno cursrcline; 219680Slinton 229680Slinton #define LASTLINE 0 /* recognized by printlines */ 239680Slinton 249680Slinton #include "lists.h" 259680Slinton 269680Slinton List sourcepath; 279680Slinton #endif 289680Slinton 299680Slinton private Lineno lastlinenum; 309680Slinton private String prevsource = nil; 319680Slinton 329680Slinton /* 339680Slinton * Data structure for indexing source seek addresses by line number. 349680Slinton * 359680Slinton * The constraints are: 369680Slinton * 379680Slinton * we want an array so indexing is fast and easy 389680Slinton * we don't want to waste space for small files 399680Slinton * we don't want an upper bound on # of lines in a file 409680Slinton * we don't know how many lines there are 419680Slinton * 429680Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 439680Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 449680Slinton * a particular line we find the slot, allocate space if necessary, 459680Slinton * and then find its location within the pointed to array. 469680Slinton */ 479680Slinton 4810617Slinton typedef long Seekaddr; 499680Slinton 509680Slinton #define NSLOTS 20 519680Slinton #define NLINESPERSLOT 500 529680Slinton 539680Slinton #define slotno(line) ((line) div NLINESPERSLOT) 549680Slinton #define index(line) ((line) mod NLINESPERSLOT) 559680Slinton #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 569680Slinton #define srcaddr(line) seektab[slotno(line)][index(line)] 579680Slinton 589680Slinton private File srcfp; 599680Slinton private Seekaddr *seektab[NSLOTS]; 609680Slinton 619680Slinton /* 629680Slinton * Print out the given lines from the source. 639680Slinton */ 649680Slinton 659680Slinton public printlines(l1, l2) 669680Slinton Lineno l1, l2; 679680Slinton { 689680Slinton register int c; 699680Slinton register Lineno i, lb, ub; 709680Slinton register File f; 719680Slinton 729680Slinton if (cursource == nil) { 739680Slinton beginerrmsg(); 749680Slinton fprintf(stderr, "no source file\n"); 759680Slinton } else { 769680Slinton if (cursource != prevsource) { 779680Slinton skimsource(); 789680Slinton } 799680Slinton if (lastlinenum == 0) { 809680Slinton beginerrmsg(); 819680Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 829680Slinton } else { 839680Slinton lb = (l1 == 0) ? lastlinenum : l1; 849680Slinton ub = (l2 == 0) ? lastlinenum : l2; 859680Slinton if (lb < 1) { 869680Slinton beginerrmsg(); 879680Slinton fprintf(stderr, "line number must be positive\n"); 889680Slinton } else if (lb > lastlinenum) { 899680Slinton beginerrmsg(); 909680Slinton if (lastlinenum == 1) { 919680Slinton fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 929680Slinton } else { 939680Slinton fprintf(stderr, "\"%s\" has only %d lines\n", 949680Slinton cursource, lastlinenum); 959680Slinton } 969680Slinton } else if (ub < lb) { 979680Slinton beginerrmsg(); 989680Slinton fprintf(stderr, "second number must be greater than first\n"); 999680Slinton } else { 1009680Slinton if (ub > lastlinenum) { 1019680Slinton ub = lastlinenum; 1029680Slinton } 1039680Slinton f = srcfp; 10410617Slinton fseek(f, srcaddr(lb), 0); 1059680Slinton for (i = lb; i <= ub; i++) { 1069680Slinton printf("%5d ", i); 1079680Slinton while ((c = getc(f)) != '\n') { 1089680Slinton putchar(c); 1099680Slinton } 1109680Slinton putchar('\n'); 1119680Slinton } 1129680Slinton cursrcline = ub + 1; 1139680Slinton } 1149680Slinton } 1159680Slinton } 1169680Slinton } 1179680Slinton 1189680Slinton /* 1199680Slinton * Open a source file looking in the appropriate places. 1209680Slinton */ 1219680Slinton 1229680Slinton public File opensource(filename) 1239680Slinton String filename; 1249680Slinton { 1259680Slinton register String dir; 1269680Slinton char buf[256]; 1279680Slinton File f; 1289680Slinton 1299680Slinton f = nil; 130*12608Slinton if (filename[0] == '/') { 131*12608Slinton f = fopen(filename, "r"); 132*12608Slinton } else { 133*12608Slinton foreach (String, dir, sourcepath) 134*12608Slinton sprintf(buf, "%s/%s", dir, filename); 135*12608Slinton f = fopen(buf, "r"); 136*12608Slinton if (f != nil) { 137*12608Slinton break; 1389680Slinton } 139*12608Slinton endfor 140*12608Slinton } 1419680Slinton return f; 1429680Slinton } 1439680Slinton 1449680Slinton /* 1459680Slinton * Set the current source file. 1469680Slinton */ 1479680Slinton 1489680Slinton public setsource(filename) 1499680Slinton String filename; 1509680Slinton { 1519680Slinton if (filename != nil and filename != cursource) { 1529680Slinton prevsource = cursource; 1539680Slinton cursource = filename; 1549680Slinton cursrcline = 1; 1559680Slinton } 1569680Slinton } 1579680Slinton 1589680Slinton /* 1599680Slinton * Read the source file getting seek pointers for each line. 1609680Slinton */ 1619680Slinton 1629680Slinton private skimsource() 1639680Slinton { 1649680Slinton register int c; 16510617Slinton register Seekaddr count; 1669680Slinton register File f; 1679680Slinton register Lineno linenum; 1689680Slinton register Seekaddr lastaddr; 1699680Slinton register int slot; 1709680Slinton 1719680Slinton f = opensource(cursource); 1729680Slinton if (f == nil) { 1739680Slinton lastlinenum = 0; 1749680Slinton } else { 1759680Slinton if (prevsource != nil) { 1769680Slinton free_seektab(); 1779680Slinton if (srcfp != nil) { 1789680Slinton fclose(srcfp); 1799680Slinton } 1809680Slinton } 1819680Slinton prevsource = cursource; 1829680Slinton linenum = 0; 1839680Slinton count = 0; 1849680Slinton lastaddr = 0; 1859680Slinton while ((c = getc(f)) != EOF) { 1869680Slinton ++count; 1879680Slinton if (c == '\n') { 1889680Slinton slot = slotno(++linenum); 1899680Slinton if (slot >= NSLOTS) { 1909680Slinton panic("skimsource: too many lines"); 1919680Slinton } 1929680Slinton if (seektab[slot] == nil) { 1939680Slinton seektab[slot] = slot_alloc(); 1949680Slinton } 1959680Slinton seektab[slot][index(linenum)] = lastaddr; 1969680Slinton lastaddr = count; 1979680Slinton } 1989680Slinton } 1999680Slinton lastlinenum = linenum; 2009680Slinton srcfp = f; 2019680Slinton } 2029680Slinton } 2039680Slinton 2049680Slinton /* 2059680Slinton * Erase information and release space in the current seektab. 2069680Slinton * This is in preparation for reading in seek pointers for a 2079680Slinton * new file. It is possible that seek pointers for all files 2089680Slinton * should be kept around, but the current concern is space. 2099680Slinton */ 2109680Slinton 2119680Slinton private free_seektab() 2129680Slinton { 2139680Slinton register int slot; 2149680Slinton 2159680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2169680Slinton if (seektab[slot] != nil) { 2179680Slinton dispose(seektab[slot]); 2189680Slinton } 2199680Slinton } 2209680Slinton } 2219680Slinton 2229680Slinton /* 2239680Slinton * Figure out current source position. 2249680Slinton */ 2259680Slinton 2269680Slinton public getsrcpos() 2279680Slinton { 2289680Slinton String filename; 2299680Slinton 23011105Slinton curline = srcline(pc); 23111105Slinton filename = srcfilename(pc); 2329680Slinton setsource(filename); 23311837Slinton if (curline != 0) { 23411837Slinton cursrcline = curline; 23511837Slinton } 2369680Slinton } 2379680Slinton 2389680Slinton /* 2399680Slinton * Print out the current source position. 2409680Slinton */ 2419680Slinton 2429680Slinton public printsrcpos() 2439680Slinton { 2449680Slinton printf("at line %d", curline); 2459680Slinton if (nlhdr.nfiles > 1) { 2469680Slinton printf(" in file \"%s\"", cursource); 2479680Slinton } 2489680Slinton } 249