1*21623Sdist /* 2*21623Sdist * Copyright (c) 1983 Regents of the University of California. 3*21623Sdist * All rights reserved. The Berkeley software License Agreement 4*21623Sdist * specifies the terms and conditions for redistribution. 5*21623Sdist */ 69680Slinton 7*21623Sdist #ifndef lint 8*21623Sdist static char sccsid[] = "@(#)source.c 5.1 (Berkeley) 05/31/85"; 9*21623Sdist #endif not lint 109680Slinton 1118233Slinton static char rcsid[] = "$Header: source.c,v 1.4 84/06/07 16:29:38 linton Exp $"; 1218233Slinton 139680Slinton /* 149680Slinton * Source file management. 159680Slinton */ 169680Slinton 179680Slinton #include "defs.h" 189680Slinton #include "source.h" 199680Slinton #include "object.h" 209680Slinton #include "mappings.h" 219680Slinton #include "machine.h" 2218233Slinton #include "keywords.h" 2318233Slinton #include "tree.h" 2418233Slinton #include "eval.h" 2516637Ssam #include <sys/file.h> 269680Slinton 279680Slinton #ifndef public 289680Slinton typedef int Lineno; 299680Slinton 309680Slinton String cursource; 319680Slinton Lineno curline; 329680Slinton Lineno cursrcline; 339680Slinton 349680Slinton #define LASTLINE 0 /* recognized by printlines */ 359680Slinton 369680Slinton #include "lists.h" 379680Slinton 389680Slinton List sourcepath; 399680Slinton #endif 409680Slinton 4118233Slinton extern char *re_comp(); 4218233Slinton 439680Slinton private Lineno lastlinenum; 449680Slinton private String prevsource = nil; 459680Slinton 469680Slinton /* 479680Slinton * Data structure for indexing source seek addresses by line number. 489680Slinton * 499680Slinton * The constraints are: 509680Slinton * 519680Slinton * we want an array so indexing is fast and easy 529680Slinton * we don't want to waste space for small files 539680Slinton * we don't want an upper bound on # of lines in a file 549680Slinton * we don't know how many lines there are 559680Slinton * 569680Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 579680Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 589680Slinton * a particular line we find the slot, allocate space if necessary, 599680Slinton * and then find its location within the pointed to array. 609680Slinton */ 619680Slinton 6210617Slinton typedef long Seekaddr; 639680Slinton 6418233Slinton #define NSLOTS 40 659680Slinton #define NLINESPERSLOT 500 669680Slinton 679680Slinton #define slotno(line) ((line) div NLINESPERSLOT) 689680Slinton #define index(line) ((line) mod NLINESPERSLOT) 699680Slinton #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 709680Slinton #define srcaddr(line) seektab[slotno(line)][index(line)] 719680Slinton 729680Slinton private File srcfp; 739680Slinton private Seekaddr *seektab[NSLOTS]; 749680Slinton 759680Slinton /* 7618233Slinton * Determine if the current source file is available. 7718233Slinton */ 7818233Slinton 7918233Slinton public boolean canReadSource () 8018233Slinton { 8118233Slinton boolean b; 8218233Slinton 8318233Slinton if (cursource == nil) { 8418233Slinton b = false; 8518233Slinton } else if (cursource != prevsource) { 8618233Slinton skimsource(); 8718233Slinton b = (boolean) (lastlinenum != 0); 8818233Slinton } else { 8918233Slinton b = true; 9018233Slinton } 9118233Slinton return b; 9218233Slinton } 9318233Slinton 9418233Slinton /* 959680Slinton * Print out the given lines from the source. 969680Slinton */ 979680Slinton 989680Slinton public printlines(l1, l2) 999680Slinton Lineno l1, l2; 1009680Slinton { 1019680Slinton register int c; 1029680Slinton register Lineno i, lb, ub; 1039680Slinton register File f; 1049680Slinton 1059680Slinton if (cursource == nil) { 1069680Slinton beginerrmsg(); 1079680Slinton fprintf(stderr, "no source file\n"); 1089680Slinton } else { 1099680Slinton if (cursource != prevsource) { 1109680Slinton skimsource(); 1119680Slinton } 1129680Slinton if (lastlinenum == 0) { 1139680Slinton beginerrmsg(); 1149680Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 1159680Slinton } else { 11618233Slinton lb = (l1 == LASTLINE) ? lastlinenum : l1; 11718233Slinton ub = (l2 == LASTLINE) ? lastlinenum : l2; 1189680Slinton if (lb < 1) { 1199680Slinton beginerrmsg(); 1209680Slinton fprintf(stderr, "line number must be positive\n"); 1219680Slinton } else if (lb > lastlinenum) { 1229680Slinton beginerrmsg(); 1239680Slinton if (lastlinenum == 1) { 1249680Slinton fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 1259680Slinton } else { 1269680Slinton fprintf(stderr, "\"%s\" has only %d lines\n", 1279680Slinton cursource, lastlinenum); 1289680Slinton } 1299680Slinton } else if (ub < lb) { 1309680Slinton beginerrmsg(); 1319680Slinton fprintf(stderr, "second number must be greater than first\n"); 1329680Slinton } else { 1339680Slinton if (ub > lastlinenum) { 1349680Slinton ub = lastlinenum; 1359680Slinton } 1369680Slinton f = srcfp; 13710617Slinton fseek(f, srcaddr(lb), 0); 1389680Slinton for (i = lb; i <= ub; i++) { 1399680Slinton printf("%5d ", i); 1409680Slinton while ((c = getc(f)) != '\n') { 1419680Slinton putchar(c); 1429680Slinton } 1439680Slinton putchar('\n'); 1449680Slinton } 1459680Slinton cursrcline = ub + 1; 1469680Slinton } 1479680Slinton } 1489680Slinton } 1499680Slinton } 1509680Slinton 1519680Slinton /* 15214337Slinton * Search the sourcepath for a file. 1539680Slinton */ 1549680Slinton 15514337Slinton static char fileNameBuf[1024]; 15614337Slinton 15714337Slinton public String findsource(filename) 1589680Slinton String filename; 1599680Slinton { 16014337Slinton register String src, dir; 1619680Slinton 16212608Slinton if (filename[0] == '/') { 16314337Slinton src = filename; 16412608Slinton } else { 16514337Slinton src = nil; 16612608Slinton foreach (String, dir, sourcepath) 16714337Slinton sprintf(fileNameBuf, "%s/%s", dir, filename); 16816637Ssam if (access(fileNameBuf, R_OK) == 0) { 16914337Slinton src = fileNameBuf; 17012608Slinton break; 17114337Slinton } 17212608Slinton endfor 17312608Slinton } 17414337Slinton return src; 17514337Slinton } 17614337Slinton 17714337Slinton /* 17814337Slinton * Open a source file looking in the appropriate places. 17914337Slinton */ 18014337Slinton 18114337Slinton public File opensource(filename) 18214337Slinton String filename; 18314337Slinton { 18414337Slinton String s; 18514337Slinton File f; 18614337Slinton 18714337Slinton s = findsource(filename); 18814337Slinton if (s == nil) { 18914337Slinton f = nil; 19014337Slinton } else { 19114337Slinton f = fopen(s, "r"); 19214337Slinton } 1939680Slinton return f; 1949680Slinton } 1959680Slinton 1969680Slinton /* 1979680Slinton * Set the current source file. 1989680Slinton */ 1999680Slinton 2009680Slinton public setsource(filename) 2019680Slinton String filename; 2029680Slinton { 2039680Slinton if (filename != nil and filename != cursource) { 2049680Slinton prevsource = cursource; 2059680Slinton cursource = filename; 2069680Slinton cursrcline = 1; 2079680Slinton } 2089680Slinton } 2099680Slinton 2109680Slinton /* 2119680Slinton * Read the source file getting seek pointers for each line. 2129680Slinton */ 2139680Slinton 2149680Slinton private skimsource() 2159680Slinton { 2169680Slinton register int c; 21710617Slinton register Seekaddr count; 2189680Slinton register File f; 2199680Slinton register Lineno linenum; 2209680Slinton register Seekaddr lastaddr; 2219680Slinton register int slot; 2229680Slinton 2239680Slinton f = opensource(cursource); 2249680Slinton if (f == nil) { 2259680Slinton lastlinenum = 0; 2269680Slinton } else { 2279680Slinton if (prevsource != nil) { 2289680Slinton free_seektab(); 2299680Slinton if (srcfp != nil) { 2309680Slinton fclose(srcfp); 2319680Slinton } 2329680Slinton } 2339680Slinton prevsource = cursource; 2349680Slinton linenum = 0; 2359680Slinton count = 0; 2369680Slinton lastaddr = 0; 2379680Slinton while ((c = getc(f)) != EOF) { 2389680Slinton ++count; 2399680Slinton if (c == '\n') { 2409680Slinton slot = slotno(++linenum); 2419680Slinton if (slot >= NSLOTS) { 2429680Slinton panic("skimsource: too many lines"); 2439680Slinton } 2449680Slinton if (seektab[slot] == nil) { 2459680Slinton seektab[slot] = slot_alloc(); 2469680Slinton } 2479680Slinton seektab[slot][index(linenum)] = lastaddr; 2489680Slinton lastaddr = count; 2499680Slinton } 2509680Slinton } 2519680Slinton lastlinenum = linenum; 2529680Slinton srcfp = f; 2539680Slinton } 2549680Slinton } 2559680Slinton 2569680Slinton /* 2579680Slinton * Erase information and release space in the current seektab. 2589680Slinton * This is in preparation for reading in seek pointers for a 2599680Slinton * new file. It is possible that seek pointers for all files 2609680Slinton * should be kept around, but the current concern is space. 2619680Slinton */ 2629680Slinton 2639680Slinton private free_seektab() 2649680Slinton { 2659680Slinton register int slot; 2669680Slinton 2679680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2689680Slinton if (seektab[slot] != nil) { 2699680Slinton dispose(seektab[slot]); 2709680Slinton } 2719680Slinton } 2729680Slinton } 2739680Slinton 2749680Slinton /* 2759680Slinton * Figure out current source position. 2769680Slinton */ 2779680Slinton 2789680Slinton public getsrcpos() 2799680Slinton { 2809680Slinton String filename; 2819680Slinton 28211105Slinton curline = srcline(pc); 28311105Slinton filename = srcfilename(pc); 2849680Slinton setsource(filename); 28511837Slinton if (curline != 0) { 28611837Slinton cursrcline = curline; 28711837Slinton } 2889680Slinton } 2899680Slinton 2909680Slinton /* 2919680Slinton * Print out the current source position. 2929680Slinton */ 2939680Slinton 2949680Slinton public printsrcpos() 2959680Slinton { 2969680Slinton printf("at line %d", curline); 2979680Slinton if (nlhdr.nfiles > 1) { 2989680Slinton printf(" in file \"%s\"", cursource); 2999680Slinton } 3009680Slinton } 30114337Slinton 30214337Slinton #define DEF_EDITOR "vi" 30314337Slinton 30414337Slinton /* 30514337Slinton * Invoke an editor on the given file. Which editor to use might change 30614337Slinton * installation to installation. For now, we use "vi". In any event, 30714337Slinton * the environment variable "EDITOR" overrides any default. 30814337Slinton */ 30914337Slinton 31014337Slinton public edit(filename) 31114337Slinton String filename; 31214337Slinton { 31314337Slinton extern String getenv(); 31414337Slinton String ed, src, s; 31514337Slinton Symbol f; 31614337Slinton Address addr; 31714337Slinton char lineno[10]; 31814337Slinton 31914337Slinton ed = getenv("EDITOR"); 32014337Slinton if (ed == nil) { 32114337Slinton ed = DEF_EDITOR; 32214337Slinton } 32314337Slinton src = findsource((filename != nil) ? filename : cursource); 32414337Slinton if (src == nil) { 32514337Slinton f = which(identname(filename, true)); 32614337Slinton if (not isblock(f)) { 32714337Slinton error("can't read \"%s\"", filename); 32814337Slinton } 32914337Slinton addr = firstline(f); 33014337Slinton if (addr == NOADDR) { 33114337Slinton error("no source for \"%s\"", filename); 33214337Slinton } 33314337Slinton src = srcfilename(addr); 33414337Slinton s = findsource(src); 33514337Slinton if (s != nil) { 33614337Slinton src = s; 33714337Slinton } 33814337Slinton sprintf(lineno, "+%d", srcline(addr)); 33914337Slinton } else { 34014337Slinton sprintf(lineno, "+1"); 34114337Slinton } 34218233Slinton if (streq(ed, "vi") or streq(ed, "ex")) { 34318233Slinton call(ed, stdin, stdout, lineno, src, nil); 34418233Slinton } else { 34518233Slinton call(ed, stdin, stdout, src, nil); 34618233Slinton } 34714337Slinton } 34816637Ssam 34916637Ssam /* 35018233Slinton * Strip away portions of a given pattern not part of the regular expression. 35116637Ssam */ 35218233Slinton 35318233Slinton private String getpattern (pattern) 35418233Slinton String pattern; 35516637Ssam { 35618233Slinton register char *p, *r; 35718233Slinton 35818233Slinton p = pattern; 35918233Slinton while (*p == ' ' or *p == '\t') { 36018233Slinton ++p; 36118233Slinton } 36218233Slinton r = p; 36318233Slinton while (*p != '\0') { 36418233Slinton ++p; 36518233Slinton } 36618233Slinton --p; 36718233Slinton if (*p == '\n') { 36818233Slinton *p = '\0'; 36918233Slinton --p; 37018233Slinton } 37118233Slinton if (*p == *r) { 37218233Slinton *p = '\0'; 37318233Slinton --p; 37418233Slinton } 37518233Slinton return r + 1; 37618233Slinton } 37718233Slinton 37818233Slinton /* 37918233Slinton * Search the current file for a regular expression. 38018233Slinton */ 38118233Slinton 38218233Slinton public search (direction, pattern) 38318233Slinton char direction; 38418233Slinton String pattern; 38518233Slinton { 38618233Slinton register String p; 38718233Slinton register File f; 38818233Slinton String re, err; 38918233Slinton Lineno line; 39018233Slinton boolean matched; 39118233Slinton char buf[512]; 39218233Slinton 39318233Slinton if (cursource == nil) { 39418233Slinton beginerrmsg(); 39518233Slinton fprintf(stderr, "no source file\n"); 39618233Slinton } else { 39718233Slinton if (cursource != prevsource) { 39818233Slinton skimsource(); 39916637Ssam } 40016637Ssam if (lastlinenum == 0) { 40118233Slinton beginerrmsg(); 40218233Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 40318233Slinton } else { 40418233Slinton re = getpattern(pattern); 40518233Slinton /* circf = 0; */ 40618233Slinton if (re != nil and *re != '\0') { 40718233Slinton err = re_comp(re); 40818233Slinton if (err != nil) { 40918233Slinton error(err); 41018233Slinton } 41118233Slinton } 41218233Slinton matched = false; 41318233Slinton f = srcfp; 41418233Slinton line = cursrcline; 41518233Slinton do { 41618233Slinton if (direction == '/') { 41718233Slinton ++line; 41818233Slinton if (line > lastlinenum) { 41918233Slinton line = 1; 42018233Slinton } 42116637Ssam } else { 42218233Slinton --line; 42318233Slinton if (line < 1) { 42418233Slinton line = lastlinenum; 42518233Slinton } 42616637Ssam } 42716637Ssam fseek(f, srcaddr(line), L_SET); 42818233Slinton p = buf; 42918233Slinton *p = getc(f); 43018233Slinton while ((*p != '\n') and (*p != EOF)) { 43118233Slinton ++p; 43218233Slinton *p = getc(f); 43318233Slinton } 43416637Ssam *p = '\0'; 43518233Slinton matched = (boolean) re_exec(buf); 43618233Slinton } while (not matched and line != cursrcline); 43718233Slinton if (not matched) { 43818233Slinton beginerrmsg(); 43918233Slinton fprintf(stderr, "no match\n"); 44018233Slinton } else { 44118233Slinton printlines(line, line); 44218233Slinton cursrcline = line; 44318233Slinton } 44418233Slinton } 44518233Slinton } 44616637Ssam } 44718233Slinton 44818233Slinton /* 44918233Slinton * Compute a small window around the given line. 45018233Slinton */ 45118233Slinton 45218233Slinton public getsrcwindow (line, l1, l2) 45318233Slinton Lineno line, *l1, *l2; 45418233Slinton { 45518233Slinton Node s; 45618233Slinton integer size; 45718233Slinton 45818233Slinton s = findvar(identname("$listwindow", true)); 45918233Slinton if (s == nil) { 46018233Slinton size = 10; 46118233Slinton } else { 46218233Slinton eval(s); 46318233Slinton size = pop(integer); 46418233Slinton } 46518233Slinton *l1 = line - (size div 2); 46618233Slinton if (*l1 < 1) { 46718233Slinton *l1 = 1; 46818233Slinton } 46918233Slinton *l2 = *l1 + size; 47018233Slinton if (lastlinenum != LASTLINE and *l2 > lastlinenum) { 47118233Slinton *l2 = lastlinenum; 47218233Slinton } 47318233Slinton } 474