19680Slinton /* Copyright (c) 1982 Regents of the University of California */ 29680Slinton 3*14337Slinton static char sccsid[] = "@(#)source.c 1.9 08/05/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 /* 119*14337Slinton * Search the sourcepath for a file. 1209680Slinton */ 1219680Slinton 122*14337Slinton static char fileNameBuf[1024]; 123*14337Slinton 124*14337Slinton public String findsource(filename) 1259680Slinton String filename; 1269680Slinton { 127*14337Slinton register File f; 128*14337Slinton register String src, dir; 1299680Slinton 13012608Slinton if (filename[0] == '/') { 131*14337Slinton src = filename; 13212608Slinton } else { 133*14337Slinton src = nil; 13412608Slinton foreach (String, dir, sourcepath) 135*14337Slinton sprintf(fileNameBuf, "%s/%s", dir, filename); 136*14337Slinton f = fopen(fileNameBuf, "r"); 13712608Slinton if (f != nil) { 138*14337Slinton fclose(f); 139*14337Slinton src = fileNameBuf; 14012608Slinton break; 141*14337Slinton } 14212608Slinton endfor 14312608Slinton } 144*14337Slinton return src; 145*14337Slinton } 146*14337Slinton 147*14337Slinton /* 148*14337Slinton * Open a source file looking in the appropriate places. 149*14337Slinton */ 150*14337Slinton 151*14337Slinton public File opensource(filename) 152*14337Slinton String filename; 153*14337Slinton { 154*14337Slinton String s; 155*14337Slinton File f; 156*14337Slinton 157*14337Slinton s = findsource(filename); 158*14337Slinton if (s == nil) { 159*14337Slinton f = nil; 160*14337Slinton } else { 161*14337Slinton f = fopen(s, "r"); 162*14337Slinton } 1639680Slinton return f; 1649680Slinton } 1659680Slinton 1669680Slinton /* 1679680Slinton * Set the current source file. 1689680Slinton */ 1699680Slinton 1709680Slinton public setsource(filename) 1719680Slinton String filename; 1729680Slinton { 1739680Slinton if (filename != nil and filename != cursource) { 1749680Slinton prevsource = cursource; 1759680Slinton cursource = filename; 1769680Slinton cursrcline = 1; 1779680Slinton } 1789680Slinton } 1799680Slinton 1809680Slinton /* 1819680Slinton * Read the source file getting seek pointers for each line. 1829680Slinton */ 1839680Slinton 1849680Slinton private skimsource() 1859680Slinton { 1869680Slinton register int c; 18710617Slinton register Seekaddr count; 1889680Slinton register File f; 1899680Slinton register Lineno linenum; 1909680Slinton register Seekaddr lastaddr; 1919680Slinton register int slot; 1929680Slinton 1939680Slinton f = opensource(cursource); 1949680Slinton if (f == nil) { 1959680Slinton lastlinenum = 0; 1969680Slinton } else { 1979680Slinton if (prevsource != nil) { 1989680Slinton free_seektab(); 1999680Slinton if (srcfp != nil) { 2009680Slinton fclose(srcfp); 2019680Slinton } 2029680Slinton } 2039680Slinton prevsource = cursource; 2049680Slinton linenum = 0; 2059680Slinton count = 0; 2069680Slinton lastaddr = 0; 2079680Slinton while ((c = getc(f)) != EOF) { 2089680Slinton ++count; 2099680Slinton if (c == '\n') { 2109680Slinton slot = slotno(++linenum); 2119680Slinton if (slot >= NSLOTS) { 2129680Slinton panic("skimsource: too many lines"); 2139680Slinton } 2149680Slinton if (seektab[slot] == nil) { 2159680Slinton seektab[slot] = slot_alloc(); 2169680Slinton } 2179680Slinton seektab[slot][index(linenum)] = lastaddr; 2189680Slinton lastaddr = count; 2199680Slinton } 2209680Slinton } 2219680Slinton lastlinenum = linenum; 2229680Slinton srcfp = f; 2239680Slinton } 2249680Slinton } 2259680Slinton 2269680Slinton /* 2279680Slinton * Erase information and release space in the current seektab. 2289680Slinton * This is in preparation for reading in seek pointers for a 2299680Slinton * new file. It is possible that seek pointers for all files 2309680Slinton * should be kept around, but the current concern is space. 2319680Slinton */ 2329680Slinton 2339680Slinton private free_seektab() 2349680Slinton { 2359680Slinton register int slot; 2369680Slinton 2379680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2389680Slinton if (seektab[slot] != nil) { 2399680Slinton dispose(seektab[slot]); 2409680Slinton } 2419680Slinton } 2429680Slinton } 2439680Slinton 2449680Slinton /* 2459680Slinton * Figure out current source position. 2469680Slinton */ 2479680Slinton 2489680Slinton public getsrcpos() 2499680Slinton { 2509680Slinton String filename; 2519680Slinton 25211105Slinton curline = srcline(pc); 25311105Slinton filename = srcfilename(pc); 2549680Slinton setsource(filename); 25511837Slinton if (curline != 0) { 25611837Slinton cursrcline = curline; 25711837Slinton } 2589680Slinton } 2599680Slinton 2609680Slinton /* 2619680Slinton * Print out the current source position. 2629680Slinton */ 2639680Slinton 2649680Slinton public printsrcpos() 2659680Slinton { 2669680Slinton printf("at line %d", curline); 2679680Slinton if (nlhdr.nfiles > 1) { 2689680Slinton printf(" in file \"%s\"", cursource); 2699680Slinton } 2709680Slinton } 271*14337Slinton 272*14337Slinton #define DEF_EDITOR "vi" 273*14337Slinton 274*14337Slinton /* 275*14337Slinton * Invoke an editor on the given file. Which editor to use might change 276*14337Slinton * installation to installation. For now, we use "vi". In any event, 277*14337Slinton * the environment variable "EDITOR" overrides any default. 278*14337Slinton */ 279*14337Slinton 280*14337Slinton public edit(filename) 281*14337Slinton String filename; 282*14337Slinton { 283*14337Slinton extern String getenv(); 284*14337Slinton String ed, src, s; 285*14337Slinton Symbol f; 286*14337Slinton Address addr; 287*14337Slinton char lineno[10]; 288*14337Slinton 289*14337Slinton ed = getenv("EDITOR"); 290*14337Slinton if (ed == nil) { 291*14337Slinton ed = DEF_EDITOR; 292*14337Slinton } 293*14337Slinton src = findsource((filename != nil) ? filename : cursource); 294*14337Slinton if (src == nil) { 295*14337Slinton f = which(identname(filename, true)); 296*14337Slinton if (not isblock(f)) { 297*14337Slinton error("can't read \"%s\"", filename); 298*14337Slinton } 299*14337Slinton addr = firstline(f); 300*14337Slinton if (addr == NOADDR) { 301*14337Slinton error("no source for \"%s\"", filename); 302*14337Slinton } 303*14337Slinton src = srcfilename(addr); 304*14337Slinton s = findsource(src); 305*14337Slinton if (s != nil) { 306*14337Slinton src = s; 307*14337Slinton } 308*14337Slinton sprintf(lineno, "+%d", srcline(addr)); 309*14337Slinton } else { 310*14337Slinton sprintf(lineno, "+1"); 311*14337Slinton } 312*14337Slinton call(ed, stdin, stdout, lineno, src, nil); 313*14337Slinton } 314