19680Slinton /* Copyright (c) 1982 Regents of the University of California */ 29680Slinton 3*16637Ssam static char sccsid[] = "@(#)source.c 1.11 (Berkeley) 06/23/84"; 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" 14*16637Ssam #include <sys/file.h> 159680Slinton 169680Slinton #ifndef public 179680Slinton typedef int Lineno; 189680Slinton 199680Slinton String cursource; 209680Slinton Lineno curline; 219680Slinton Lineno cursrcline; 229680Slinton 239680Slinton #define LASTLINE 0 /* recognized by printlines */ 249680Slinton 259680Slinton #include "lists.h" 269680Slinton 279680Slinton List sourcepath; 289680Slinton #endif 299680Slinton 309680Slinton private Lineno lastlinenum; 319680Slinton private String prevsource = nil; 329680Slinton 339680Slinton /* 349680Slinton * Data structure for indexing source seek addresses by line number. 359680Slinton * 369680Slinton * The constraints are: 379680Slinton * 389680Slinton * we want an array so indexing is fast and easy 399680Slinton * we don't want to waste space for small files 409680Slinton * we don't want an upper bound on # of lines in a file 419680Slinton * we don't know how many lines there are 429680Slinton * 439680Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 449680Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 459680Slinton * a particular line we find the slot, allocate space if necessary, 469680Slinton * and then find its location within the pointed to array. 479680Slinton */ 489680Slinton 4910617Slinton typedef long Seekaddr; 509680Slinton 519680Slinton #define NSLOTS 20 529680Slinton #define NLINESPERSLOT 500 539680Slinton 549680Slinton #define slotno(line) ((line) div NLINESPERSLOT) 559680Slinton #define index(line) ((line) mod NLINESPERSLOT) 569680Slinton #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 579680Slinton #define srcaddr(line) seektab[slotno(line)][index(line)] 589680Slinton 599680Slinton private File srcfp; 609680Slinton private Seekaddr *seektab[NSLOTS]; 619680Slinton 629680Slinton /* 639680Slinton * Print out the given lines from the source. 649680Slinton */ 659680Slinton 669680Slinton public printlines(l1, l2) 679680Slinton Lineno l1, l2; 689680Slinton { 699680Slinton register int c; 709680Slinton register Lineno i, lb, ub; 719680Slinton register File f; 729680Slinton 739680Slinton if (cursource == nil) { 749680Slinton beginerrmsg(); 759680Slinton fprintf(stderr, "no source file\n"); 769680Slinton } else { 779680Slinton if (cursource != prevsource) { 789680Slinton skimsource(); 799680Slinton } 809680Slinton if (lastlinenum == 0) { 819680Slinton beginerrmsg(); 829680Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 839680Slinton } else { 849680Slinton lb = (l1 == 0) ? lastlinenum : l1; 859680Slinton ub = (l2 == 0) ? lastlinenum : l2; 869680Slinton if (lb < 1) { 879680Slinton beginerrmsg(); 889680Slinton fprintf(stderr, "line number must be positive\n"); 899680Slinton } else if (lb > lastlinenum) { 909680Slinton beginerrmsg(); 919680Slinton if (lastlinenum == 1) { 929680Slinton fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 939680Slinton } else { 949680Slinton fprintf(stderr, "\"%s\" has only %d lines\n", 959680Slinton cursource, lastlinenum); 969680Slinton } 979680Slinton } else if (ub < lb) { 989680Slinton beginerrmsg(); 999680Slinton fprintf(stderr, "second number must be greater than first\n"); 1009680Slinton } else { 1019680Slinton if (ub > lastlinenum) { 1029680Slinton ub = lastlinenum; 1039680Slinton } 1049680Slinton f = srcfp; 10510617Slinton fseek(f, srcaddr(lb), 0); 1069680Slinton for (i = lb; i <= ub; i++) { 1079680Slinton printf("%5d ", i); 1089680Slinton while ((c = getc(f)) != '\n') { 1099680Slinton putchar(c); 1109680Slinton } 1119680Slinton putchar('\n'); 1129680Slinton } 1139680Slinton cursrcline = ub + 1; 1149680Slinton } 1159680Slinton } 1169680Slinton } 1179680Slinton } 1189680Slinton 1199680Slinton /* 12014337Slinton * Search the sourcepath for a file. 1219680Slinton */ 1229680Slinton 12314337Slinton static char fileNameBuf[1024]; 12414337Slinton 12514337Slinton public String findsource(filename) 1269680Slinton String filename; 1279680Slinton { 12814337Slinton register String src, dir; 1299680Slinton 13012608Slinton if (filename[0] == '/') { 13114337Slinton src = filename; 13212608Slinton } else { 13314337Slinton src = nil; 13412608Slinton foreach (String, dir, sourcepath) 13514337Slinton sprintf(fileNameBuf, "%s/%s", dir, filename); 136*16637Ssam if (access(fileNameBuf, R_OK) == 0) { 13714337Slinton src = fileNameBuf; 13812608Slinton break; 13914337Slinton } 14012608Slinton endfor 14112608Slinton } 14214337Slinton return src; 14314337Slinton } 14414337Slinton 14514337Slinton /* 14614337Slinton * Open a source file looking in the appropriate places. 14714337Slinton */ 14814337Slinton 14914337Slinton public File opensource(filename) 15014337Slinton String filename; 15114337Slinton { 15214337Slinton String s; 15314337Slinton File f; 15414337Slinton 15514337Slinton s = findsource(filename); 15614337Slinton if (s == nil) { 15714337Slinton f = nil; 15814337Slinton } else { 15914337Slinton f = fopen(s, "r"); 16014337Slinton } 1619680Slinton return f; 1629680Slinton } 1639680Slinton 1649680Slinton /* 1659680Slinton * Set the current source file. 1669680Slinton */ 1679680Slinton 1689680Slinton public setsource(filename) 1699680Slinton String filename; 1709680Slinton { 1719680Slinton if (filename != nil and filename != cursource) { 1729680Slinton prevsource = cursource; 1739680Slinton cursource = filename; 1749680Slinton cursrcline = 1; 1759680Slinton } 1769680Slinton } 1779680Slinton 1789680Slinton /* 1799680Slinton * Read the source file getting seek pointers for each line. 1809680Slinton */ 1819680Slinton 1829680Slinton private skimsource() 1839680Slinton { 1849680Slinton register int c; 18510617Slinton register Seekaddr count; 1869680Slinton register File f; 1879680Slinton register Lineno linenum; 1889680Slinton register Seekaddr lastaddr; 1899680Slinton register int slot; 1909680Slinton 1919680Slinton f = opensource(cursource); 1929680Slinton if (f == nil) { 1939680Slinton lastlinenum = 0; 1949680Slinton } else { 1959680Slinton if (prevsource != nil) { 1969680Slinton free_seektab(); 1979680Slinton if (srcfp != nil) { 1989680Slinton fclose(srcfp); 1999680Slinton } 2009680Slinton } 2019680Slinton prevsource = cursource; 2029680Slinton linenum = 0; 2039680Slinton count = 0; 2049680Slinton lastaddr = 0; 2059680Slinton while ((c = getc(f)) != EOF) { 2069680Slinton ++count; 2079680Slinton if (c == '\n') { 2089680Slinton slot = slotno(++linenum); 2099680Slinton if (slot >= NSLOTS) { 2109680Slinton panic("skimsource: too many lines"); 2119680Slinton } 2129680Slinton if (seektab[slot] == nil) { 2139680Slinton seektab[slot] = slot_alloc(); 2149680Slinton } 2159680Slinton seektab[slot][index(linenum)] = lastaddr; 2169680Slinton lastaddr = count; 2179680Slinton } 2189680Slinton } 2199680Slinton lastlinenum = linenum; 2209680Slinton srcfp = f; 2219680Slinton } 2229680Slinton } 2239680Slinton 2249680Slinton /* 2259680Slinton * Erase information and release space in the current seektab. 2269680Slinton * This is in preparation for reading in seek pointers for a 2279680Slinton * new file. It is possible that seek pointers for all files 2289680Slinton * should be kept around, but the current concern is space. 2299680Slinton */ 2309680Slinton 2319680Slinton private free_seektab() 2329680Slinton { 2339680Slinton register int slot; 2349680Slinton 2359680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2369680Slinton if (seektab[slot] != nil) { 2379680Slinton dispose(seektab[slot]); 2389680Slinton } 2399680Slinton } 2409680Slinton } 2419680Slinton 2429680Slinton /* 2439680Slinton * Figure out current source position. 2449680Slinton */ 2459680Slinton 2469680Slinton public getsrcpos() 2479680Slinton { 2489680Slinton String filename; 2499680Slinton 25011105Slinton curline = srcline(pc); 25111105Slinton filename = srcfilename(pc); 2529680Slinton setsource(filename); 25311837Slinton if (curline != 0) { 25411837Slinton cursrcline = curline; 25511837Slinton } 2569680Slinton } 2579680Slinton 2589680Slinton /* 2599680Slinton * Print out the current source position. 2609680Slinton */ 2619680Slinton 2629680Slinton public printsrcpos() 2639680Slinton { 2649680Slinton printf("at line %d", curline); 2659680Slinton if (nlhdr.nfiles > 1) { 2669680Slinton printf(" in file \"%s\"", cursource); 2679680Slinton } 2689680Slinton } 26914337Slinton 27014337Slinton #define DEF_EDITOR "vi" 27114337Slinton 27214337Slinton /* 27314337Slinton * Invoke an editor on the given file. Which editor to use might change 27414337Slinton * installation to installation. For now, we use "vi". In any event, 27514337Slinton * the environment variable "EDITOR" overrides any default. 27614337Slinton */ 27714337Slinton 27814337Slinton public edit(filename) 27914337Slinton String filename; 28014337Slinton { 28114337Slinton extern String getenv(); 28214337Slinton String ed, src, s; 28314337Slinton Symbol f; 28414337Slinton Address addr; 28514337Slinton char lineno[10]; 28614337Slinton 28714337Slinton ed = getenv("EDITOR"); 28814337Slinton if (ed == nil) { 28914337Slinton ed = DEF_EDITOR; 29014337Slinton } 29114337Slinton src = findsource((filename != nil) ? filename : cursource); 29214337Slinton if (src == nil) { 29314337Slinton f = which(identname(filename, true)); 29414337Slinton if (not isblock(f)) { 29514337Slinton error("can't read \"%s\"", filename); 29614337Slinton } 29714337Slinton addr = firstline(f); 29814337Slinton if (addr == NOADDR) { 29914337Slinton error("no source for \"%s\"", filename); 30014337Slinton } 30114337Slinton src = srcfilename(addr); 30214337Slinton s = findsource(src); 30314337Slinton if (s != nil) { 30414337Slinton src = s; 30514337Slinton } 30614337Slinton sprintf(lineno, "+%d", srcline(addr)); 30714337Slinton } else { 30814337Slinton sprintf(lineno, "+1"); 30914337Slinton } 31014337Slinton call(ed, stdin, stdout, lineno, src, nil); 31114337Slinton } 312*16637Ssam 313*16637Ssam #include "re.h" 314*16637Ssam /* 315*16637Ssam * Search the current file with 316*16637Ssam * a regular expression. 317*16637Ssam */ 318*16637Ssam public search(forward, re) 319*16637Ssam Boolean forward; 320*16637Ssam String re; 321*16637Ssam { 322*16637Ssam register String p; 323*16637Ssam register File f; 324*16637Ssam register Lineno line; 325*16637Ssam Lineno l1, l2; 326*16637Ssam Boolean matched; 327*16637Ssam Char buf[512]; 328*16637Ssam 329*16637Ssam if (cursource == nil) { 330*16637Ssam beginerrmsg(); 331*16637Ssam fprintf(stderr, "No source file.\n"); 332*16637Ssam return; 333*16637Ssam } 334*16637Ssam if (cursource != prevsource) 335*16637Ssam skimsource(); 336*16637Ssam if (lastlinenum == 0) { 337*16637Ssam beginerrmsg(); 338*16637Ssam fprintf(stderr, "Couldn't read \"%s\"\n", cursource); 339*16637Ssam return; 340*16637Ssam } 341*16637Ssam circf = 0; 342*16637Ssam if (re != nil && *re != '\0') 343*16637Ssam recompile(re); 344*16637Ssam matched = false; 345*16637Ssam f = srcfp; 346*16637Ssam line = cursrcline; 347*16637Ssam do { 348*16637Ssam if (forward) { 349*16637Ssam line++; 350*16637Ssam if (line > lastlinenum) 351*16637Ssam line = 1; 352*16637Ssam } else { 353*16637Ssam line--; 354*16637Ssam if (line < 1) 355*16637Ssam line = lastlinenum; 356*16637Ssam } 357*16637Ssam fseek(f, srcaddr(line), L_SET); 358*16637Ssam for (p = buf; (*p = getc(f)) != '\n'; p++) 359*16637Ssam if (*p == EOF) 360*16637Ssam error("Unexpected EOF."); 361*16637Ssam *p = '\0'; 362*16637Ssam matched = (Boolean)rematch(buf); 363*16637Ssam if (matched) 364*16637Ssam break; 365*16637Ssam } while (line != cursrcline); 366*16637Ssam if (!matched) 367*16637Ssam error("No match"); 368*16637Ssam #define WINDOW 10 /* should be used globally */ 369*16637Ssam l1 = line - WINDOW / 2; 370*16637Ssam if (l1 < 1) 371*16637Ssam l1 = 1; 372*16637Ssam l2 = line + WINDOW / 2; 373*16637Ssam if (l2 > lastlinenum) 374*16637Ssam l2 = lastlinenum; 375*16637Ssam printlines(l1, l2); 376*16637Ssam cursrcline = line; /* override printlines */ 377*16637Ssam } 378