19680Slinton /* Copyright (c) 1982 Regents of the University of California */ 29680Slinton 3*11837Slinton static char sccsid[] = "@(#)source.c 1.6 04/04/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; 1309680Slinton foreach (String, dir, sourcepath) 1319680Slinton sprintf(buf, "%s/%s", dir, filename); 1329680Slinton f = fopen(buf, "r"); 1339680Slinton if (f != nil) { 1349680Slinton break; 1359680Slinton } 1369680Slinton endfor 1379680Slinton return f; 1389680Slinton } 1399680Slinton 1409680Slinton /* 1419680Slinton * Set the current source file. 1429680Slinton */ 1439680Slinton 1449680Slinton public setsource(filename) 1459680Slinton String filename; 1469680Slinton { 1479680Slinton if (filename != nil and filename != cursource) { 1489680Slinton prevsource = cursource; 1499680Slinton cursource = filename; 1509680Slinton cursrcline = 1; 1519680Slinton } 1529680Slinton } 1539680Slinton 1549680Slinton /* 1559680Slinton * Read the source file getting seek pointers for each line. 1569680Slinton */ 1579680Slinton 1589680Slinton private skimsource() 1599680Slinton { 1609680Slinton register int c; 16110617Slinton register Seekaddr count; 1629680Slinton register File f; 1639680Slinton register Lineno linenum; 1649680Slinton register Seekaddr lastaddr; 1659680Slinton register int slot; 1669680Slinton 1679680Slinton f = opensource(cursource); 1689680Slinton if (f == nil) { 1699680Slinton lastlinenum = 0; 1709680Slinton } else { 1719680Slinton if (prevsource != nil) { 1729680Slinton free_seektab(); 1739680Slinton if (srcfp != nil) { 1749680Slinton fclose(srcfp); 1759680Slinton } 1769680Slinton } 1779680Slinton prevsource = cursource; 1789680Slinton linenum = 0; 1799680Slinton count = 0; 1809680Slinton lastaddr = 0; 1819680Slinton while ((c = getc(f)) != EOF) { 1829680Slinton ++count; 1839680Slinton if (c == '\n') { 1849680Slinton slot = slotno(++linenum); 1859680Slinton if (slot >= NSLOTS) { 1869680Slinton panic("skimsource: too many lines"); 1879680Slinton } 1889680Slinton if (seektab[slot] == nil) { 1899680Slinton seektab[slot] = slot_alloc(); 1909680Slinton } 1919680Slinton seektab[slot][index(linenum)] = lastaddr; 1929680Slinton lastaddr = count; 1939680Slinton } 1949680Slinton } 1959680Slinton lastlinenum = linenum; 1969680Slinton srcfp = f; 1979680Slinton } 1989680Slinton } 1999680Slinton 2009680Slinton /* 2019680Slinton * Erase information and release space in the current seektab. 2029680Slinton * This is in preparation for reading in seek pointers for a 2039680Slinton * new file. It is possible that seek pointers for all files 2049680Slinton * should be kept around, but the current concern is space. 2059680Slinton */ 2069680Slinton 2079680Slinton private free_seektab() 2089680Slinton { 2099680Slinton register int slot; 2109680Slinton 2119680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2129680Slinton if (seektab[slot] != nil) { 2139680Slinton dispose(seektab[slot]); 2149680Slinton } 2159680Slinton } 2169680Slinton } 2179680Slinton 2189680Slinton /* 2199680Slinton * Figure out current source position. 2209841Slinton * Have to use "pc - 1" because pc is the address of the next instruction 2219841Slinton * rather than the current one. 2229680Slinton */ 2239680Slinton 2249680Slinton public getsrcpos() 2259680Slinton { 2269680Slinton String filename; 2279680Slinton 22811105Slinton curline = srcline(pc); 22911105Slinton filename = srcfilename(pc); 2309680Slinton setsource(filename); 231*11837Slinton if (curline != 0) { 232*11837Slinton cursrcline = curline; 233*11837Slinton } 2349680Slinton } 2359680Slinton 2369680Slinton /* 2379680Slinton * Print out the current source position. 2389680Slinton */ 2399680Slinton 2409680Slinton public printsrcpos() 2419680Slinton { 2429680Slinton printf("at line %d", curline); 2439680Slinton if (nlhdr.nfiles > 1) { 2449680Slinton printf(" in file \"%s\"", cursource); 2459680Slinton } 2469680Slinton } 247