121623Sdist /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621623Sdist */ 179680Slinton 1821623Sdist #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)source.c 5.3 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 219680Slinton 229680Slinton /* 239680Slinton * Source file management. 249680Slinton */ 259680Slinton 269680Slinton #include "defs.h" 279680Slinton #include "source.h" 289680Slinton #include "object.h" 299680Slinton #include "mappings.h" 309680Slinton #include "machine.h" 3118233Slinton #include "keywords.h" 3218233Slinton #include "tree.h" 3318233Slinton #include "eval.h" 3433335Sdonn #ifdef IRIS 3533335Sdonn # define R_OK 04 /* read access */ 3633335Sdonn # define L_SET 01 /* absolute offset for seek */ 3733335Sdonn #else 3833335Sdonn # include <sys/file.h> 3933335Sdonn #endif 409680Slinton 419680Slinton #ifndef public 429680Slinton typedef int Lineno; 439680Slinton 449680Slinton String cursource; 459680Slinton Lineno curline; 469680Slinton Lineno cursrcline; 479680Slinton 489680Slinton #define LASTLINE 0 /* recognized by printlines */ 499680Slinton 509680Slinton #include "lists.h" 519680Slinton 529680Slinton List sourcepath; 539680Slinton #endif 549680Slinton 5533335Sdonn #ifdef IRIS 5633335Sdonn # define re_comp regcmp 5733335Sdonn # define re_exec(buf) (regex(buf) != NULL) 5833335Sdonn #endif 5933335Sdonn 6018233Slinton extern char *re_comp(); 6118233Slinton 629680Slinton private Lineno lastlinenum; 639680Slinton private String prevsource = nil; 649680Slinton 659680Slinton /* 669680Slinton * Data structure for indexing source seek addresses by line number. 679680Slinton * 689680Slinton * The constraints are: 699680Slinton * 709680Slinton * we want an array so indexing is fast and easy 719680Slinton * we don't want to waste space for small files 729680Slinton * we don't want an upper bound on # of lines in a file 739680Slinton * we don't know how many lines there are 749680Slinton * 759680Slinton * The solution is a "dirty" hash table. We have NSLOTS pointers to 769680Slinton * arrays of NLINESPERSLOT addresses. To find the source address of 779680Slinton * a particular line we find the slot, allocate space if necessary, 789680Slinton * and then find its location within the pointed to array. 799680Slinton */ 809680Slinton 8110617Slinton typedef long Seekaddr; 829680Slinton 8318233Slinton #define NSLOTS 40 849680Slinton #define NLINESPERSLOT 500 859680Slinton 869680Slinton #define slotno(line) ((line) div NLINESPERSLOT) 879680Slinton #define index(line) ((line) mod NLINESPERSLOT) 889680Slinton #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 899680Slinton #define srcaddr(line) seektab[slotno(line)][index(line)] 909680Slinton 919680Slinton private File srcfp; 929680Slinton private Seekaddr *seektab[NSLOTS]; 939680Slinton 949680Slinton /* 9518233Slinton * Determine if the current source file is available. 9618233Slinton */ 9718233Slinton 9818233Slinton public boolean canReadSource () 9918233Slinton { 10018233Slinton boolean b; 10118233Slinton 10218233Slinton if (cursource == nil) { 10318233Slinton b = false; 10418233Slinton } else if (cursource != prevsource) { 10518233Slinton skimsource(); 10618233Slinton b = (boolean) (lastlinenum != 0); 10718233Slinton } else { 10818233Slinton b = true; 10918233Slinton } 11018233Slinton return b; 11118233Slinton } 11218233Slinton 11318233Slinton /* 1149680Slinton * Print out the given lines from the source. 1159680Slinton */ 1169680Slinton 1179680Slinton public printlines(l1, l2) 1189680Slinton Lineno l1, l2; 1199680Slinton { 1209680Slinton register int c; 1219680Slinton register Lineno i, lb, ub; 1229680Slinton register File f; 1239680Slinton 1249680Slinton if (cursource == nil) { 1259680Slinton beginerrmsg(); 1269680Slinton fprintf(stderr, "no source file\n"); 1279680Slinton } else { 1289680Slinton if (cursource != prevsource) { 1299680Slinton skimsource(); 1309680Slinton } 1319680Slinton if (lastlinenum == 0) { 1329680Slinton beginerrmsg(); 1339680Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 1349680Slinton } else { 13518233Slinton lb = (l1 == LASTLINE) ? lastlinenum : l1; 13618233Slinton ub = (l2 == LASTLINE) ? lastlinenum : l2; 1379680Slinton if (lb < 1) { 1389680Slinton beginerrmsg(); 1399680Slinton fprintf(stderr, "line number must be positive\n"); 1409680Slinton } else if (lb > lastlinenum) { 1419680Slinton beginerrmsg(); 1429680Slinton if (lastlinenum == 1) { 1439680Slinton fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 1449680Slinton } else { 1459680Slinton fprintf(stderr, "\"%s\" has only %d lines\n", 1469680Slinton cursource, lastlinenum); 1479680Slinton } 1489680Slinton } else if (ub < lb) { 1499680Slinton beginerrmsg(); 1509680Slinton fprintf(stderr, "second number must be greater than first\n"); 1519680Slinton } else { 1529680Slinton if (ub > lastlinenum) { 1539680Slinton ub = lastlinenum; 1549680Slinton } 1559680Slinton f = srcfp; 15610617Slinton fseek(f, srcaddr(lb), 0); 1579680Slinton for (i = lb; i <= ub; i++) { 1589680Slinton printf("%5d ", i); 1599680Slinton while ((c = getc(f)) != '\n') { 1609680Slinton putchar(c); 1619680Slinton } 1629680Slinton putchar('\n'); 1639680Slinton } 1649680Slinton cursrcline = ub + 1; 1659680Slinton } 1669680Slinton } 1679680Slinton } 1689680Slinton } 1699680Slinton 1709680Slinton /* 17114337Slinton * Search the sourcepath for a file. 1729680Slinton */ 1739680Slinton 17414337Slinton static char fileNameBuf[1024]; 17514337Slinton 17614337Slinton public String findsource(filename) 1779680Slinton String filename; 1789680Slinton { 17914337Slinton register String src, dir; 1809680Slinton 18112608Slinton if (filename[0] == '/') { 18214337Slinton src = filename; 18312608Slinton } else { 18414337Slinton src = nil; 18512608Slinton foreach (String, dir, sourcepath) 18614337Slinton sprintf(fileNameBuf, "%s/%s", dir, filename); 18716637Ssam if (access(fileNameBuf, R_OK) == 0) { 18814337Slinton src = fileNameBuf; 18912608Slinton break; 19014337Slinton } 19112608Slinton endfor 19212608Slinton } 19314337Slinton return src; 19414337Slinton } 19514337Slinton 19614337Slinton /* 19714337Slinton * Open a source file looking in the appropriate places. 19814337Slinton */ 19914337Slinton 20014337Slinton public File opensource(filename) 20114337Slinton String filename; 20214337Slinton { 20314337Slinton String s; 20414337Slinton File f; 20514337Slinton 20614337Slinton s = findsource(filename); 20714337Slinton if (s == nil) { 20814337Slinton f = nil; 20914337Slinton } else { 21014337Slinton f = fopen(s, "r"); 21114337Slinton } 2129680Slinton return f; 2139680Slinton } 2149680Slinton 2159680Slinton /* 2169680Slinton * Set the current source file. 2179680Slinton */ 2189680Slinton 2199680Slinton public setsource(filename) 2209680Slinton String filename; 2219680Slinton { 2229680Slinton if (filename != nil and filename != cursource) { 2239680Slinton prevsource = cursource; 2249680Slinton cursource = filename; 2259680Slinton cursrcline = 1; 2269680Slinton } 2279680Slinton } 2289680Slinton 2299680Slinton /* 2309680Slinton * Read the source file getting seek pointers for each line. 2319680Slinton */ 2329680Slinton 2339680Slinton private skimsource() 2349680Slinton { 2359680Slinton register int c; 23610617Slinton register Seekaddr count; 2379680Slinton register File f; 2389680Slinton register Lineno linenum; 2399680Slinton register Seekaddr lastaddr; 2409680Slinton register int slot; 2419680Slinton 2429680Slinton f = opensource(cursource); 2439680Slinton if (f == nil) { 2449680Slinton lastlinenum = 0; 2459680Slinton } else { 2469680Slinton if (prevsource != nil) { 2479680Slinton free_seektab(); 2489680Slinton if (srcfp != nil) { 2499680Slinton fclose(srcfp); 2509680Slinton } 2519680Slinton } 2529680Slinton prevsource = cursource; 2539680Slinton linenum = 0; 2549680Slinton count = 0; 2559680Slinton lastaddr = 0; 2569680Slinton while ((c = getc(f)) != EOF) { 2579680Slinton ++count; 2589680Slinton if (c == '\n') { 2599680Slinton slot = slotno(++linenum); 2609680Slinton if (slot >= NSLOTS) { 2619680Slinton panic("skimsource: too many lines"); 2629680Slinton } 2639680Slinton if (seektab[slot] == nil) { 2649680Slinton seektab[slot] = slot_alloc(); 2659680Slinton } 2669680Slinton seektab[slot][index(linenum)] = lastaddr; 2679680Slinton lastaddr = count; 2689680Slinton } 2699680Slinton } 2709680Slinton lastlinenum = linenum; 2719680Slinton srcfp = f; 2729680Slinton } 2739680Slinton } 2749680Slinton 2759680Slinton /* 2769680Slinton * Erase information and release space in the current seektab. 2779680Slinton * This is in preparation for reading in seek pointers for a 2789680Slinton * new file. It is possible that seek pointers for all files 2799680Slinton * should be kept around, but the current concern is space. 2809680Slinton */ 2819680Slinton 2829680Slinton private free_seektab() 2839680Slinton { 2849680Slinton register int slot; 2859680Slinton 2869680Slinton for (slot = 0; slot < NSLOTS; slot++) { 2879680Slinton if (seektab[slot] != nil) { 2889680Slinton dispose(seektab[slot]); 2899680Slinton } 2909680Slinton } 2919680Slinton } 2929680Slinton 2939680Slinton /* 2949680Slinton * Figure out current source position. 2959680Slinton */ 2969680Slinton 2979680Slinton public getsrcpos() 2989680Slinton { 2999680Slinton String filename; 3009680Slinton 30111105Slinton curline = srcline(pc); 30211105Slinton filename = srcfilename(pc); 3039680Slinton setsource(filename); 30411837Slinton if (curline != 0) { 30511837Slinton cursrcline = curline; 30611837Slinton } 3079680Slinton } 3089680Slinton 3099680Slinton /* 3109680Slinton * Print out the current source position. 3119680Slinton */ 3129680Slinton 3139680Slinton public printsrcpos() 3149680Slinton { 3159680Slinton printf("at line %d", curline); 3169680Slinton if (nlhdr.nfiles > 1) { 3179680Slinton printf(" in file \"%s\"", cursource); 3189680Slinton } 3199680Slinton } 32014337Slinton 32114337Slinton #define DEF_EDITOR "vi" 32214337Slinton 32314337Slinton /* 32414337Slinton * Invoke an editor on the given file. Which editor to use might change 32514337Slinton * installation to installation. For now, we use "vi". In any event, 32614337Slinton * the environment variable "EDITOR" overrides any default. 32714337Slinton */ 32814337Slinton 32914337Slinton public edit(filename) 33014337Slinton String filename; 33114337Slinton { 33214337Slinton extern String getenv(); 33314337Slinton String ed, src, s; 33414337Slinton Symbol f; 33514337Slinton Address addr; 33614337Slinton char lineno[10]; 33714337Slinton 33814337Slinton ed = getenv("EDITOR"); 33914337Slinton if (ed == nil) { 34014337Slinton ed = DEF_EDITOR; 34114337Slinton } 34214337Slinton src = findsource((filename != nil) ? filename : cursource); 34314337Slinton if (src == nil) { 34414337Slinton f = which(identname(filename, true)); 34514337Slinton if (not isblock(f)) { 34614337Slinton error("can't read \"%s\"", filename); 34714337Slinton } 34814337Slinton addr = firstline(f); 34914337Slinton if (addr == NOADDR) { 35014337Slinton error("no source for \"%s\"", filename); 35114337Slinton } 35214337Slinton src = srcfilename(addr); 35314337Slinton s = findsource(src); 35414337Slinton if (s != nil) { 35514337Slinton src = s; 35614337Slinton } 35714337Slinton sprintf(lineno, "+%d", srcline(addr)); 35814337Slinton } else { 35914337Slinton sprintf(lineno, "+1"); 36014337Slinton } 36118233Slinton if (streq(ed, "vi") or streq(ed, "ex")) { 36218233Slinton call(ed, stdin, stdout, lineno, src, nil); 36318233Slinton } else { 36418233Slinton call(ed, stdin, stdout, src, nil); 36518233Slinton } 36614337Slinton } 36716637Ssam 36816637Ssam /* 36918233Slinton * Strip away portions of a given pattern not part of the regular expression. 37016637Ssam */ 37118233Slinton 37218233Slinton private String getpattern (pattern) 37318233Slinton String pattern; 37416637Ssam { 37518233Slinton register char *p, *r; 37618233Slinton 37718233Slinton p = pattern; 37818233Slinton while (*p == ' ' or *p == '\t') { 37918233Slinton ++p; 38018233Slinton } 38118233Slinton r = p; 38218233Slinton while (*p != '\0') { 38318233Slinton ++p; 38418233Slinton } 38518233Slinton --p; 38618233Slinton if (*p == '\n') { 38718233Slinton *p = '\0'; 38818233Slinton --p; 38918233Slinton } 39018233Slinton if (*p == *r) { 39118233Slinton *p = '\0'; 39218233Slinton --p; 39318233Slinton } 39418233Slinton return r + 1; 39518233Slinton } 39618233Slinton 39718233Slinton /* 39818233Slinton * Search the current file for a regular expression. 39918233Slinton */ 40018233Slinton 40118233Slinton public search (direction, pattern) 40218233Slinton char direction; 40318233Slinton String pattern; 40418233Slinton { 40518233Slinton register String p; 40618233Slinton register File f; 40718233Slinton String re, err; 40818233Slinton Lineno line; 40918233Slinton boolean matched; 41018233Slinton char buf[512]; 41118233Slinton 41218233Slinton if (cursource == nil) { 41318233Slinton beginerrmsg(); 41418233Slinton fprintf(stderr, "no source file\n"); 41518233Slinton } else { 41618233Slinton if (cursource != prevsource) { 41718233Slinton skimsource(); 41816637Ssam } 41916637Ssam if (lastlinenum == 0) { 42018233Slinton beginerrmsg(); 42118233Slinton fprintf(stderr, "couldn't read \"%s\"\n", cursource); 42218233Slinton } else { 42318233Slinton re = getpattern(pattern); 42418233Slinton /* circf = 0; */ 42518233Slinton if (re != nil and *re != '\0') { 42618233Slinton err = re_comp(re); 42718233Slinton if (err != nil) { 42818233Slinton error(err); 42918233Slinton } 43018233Slinton } 43118233Slinton matched = false; 43218233Slinton f = srcfp; 43318233Slinton line = cursrcline; 43418233Slinton do { 43518233Slinton if (direction == '/') { 43618233Slinton ++line; 43718233Slinton if (line > lastlinenum) { 43818233Slinton line = 1; 43918233Slinton } 44016637Ssam } else { 44118233Slinton --line; 44218233Slinton if (line < 1) { 44318233Slinton line = lastlinenum; 44418233Slinton } 44516637Ssam } 44616637Ssam fseek(f, srcaddr(line), L_SET); 44718233Slinton p = buf; 44818233Slinton *p = getc(f); 44918233Slinton while ((*p != '\n') and (*p != EOF)) { 45018233Slinton ++p; 45118233Slinton *p = getc(f); 45218233Slinton } 45316637Ssam *p = '\0'; 45418233Slinton matched = (boolean) re_exec(buf); 45518233Slinton } while (not matched and line != cursrcline); 45618233Slinton if (not matched) { 45718233Slinton beginerrmsg(); 45818233Slinton fprintf(stderr, "no match\n"); 45918233Slinton } else { 46018233Slinton printlines(line, line); 46118233Slinton cursrcline = line; 46218233Slinton } 46318233Slinton } 46418233Slinton } 46516637Ssam } 46618233Slinton 46733335Sdonn public integer srcwindowlen () 46833335Sdonn { 46933335Sdonn Node s; 47033335Sdonn 47133335Sdonn s = findvar(identname("$listwindow", true)); 47233335Sdonn if (s == nil) 47333335Sdonn return 10; 47433335Sdonn eval(s); 47533335Sdonn return pop(integer); 47633335Sdonn } 47733335Sdonn 47818233Slinton /* 47918233Slinton * Compute a small window around the given line. 48018233Slinton */ 48118233Slinton 48218233Slinton public getsrcwindow (line, l1, l2) 48318233Slinton Lineno line, *l1, *l2; 48418233Slinton { 48518233Slinton integer size; 48618233Slinton 48733335Sdonn size = srcwindowlen(); 48818233Slinton *l1 = line - (size div 2); 48918233Slinton if (*l1 < 1) { 49018233Slinton *l1 = 1; 49118233Slinton } 49218233Slinton *l2 = *l1 + size; 49318233Slinton if (lastlinenum != LASTLINE and *l2 > lastlinenum) { 49418233Slinton *l2 = lastlinenum; 49518233Slinton } 49618233Slinton } 497