xref: /csrg-svn/old/dbx/source.c (revision 42685)
121623Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42685Sbostic  * %sccs.include.redist.c%
621623Sdist  */
79680Slinton 
821623Sdist #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)source.c	5.4 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119680Slinton 
129680Slinton /*
139680Slinton  * Source file management.
149680Slinton  */
159680Slinton 
169680Slinton #include "defs.h"
179680Slinton #include "source.h"
189680Slinton #include "object.h"
199680Slinton #include "mappings.h"
209680Slinton #include "machine.h"
2118233Slinton #include "keywords.h"
2218233Slinton #include "tree.h"
2318233Slinton #include "eval.h"
2433335Sdonn #ifdef IRIS
2533335Sdonn #   define R_OK 04	/* read access */
2633335Sdonn #   define L_SET 01	/* absolute offset for seek */
2733335Sdonn #else
2833335Sdonn #   include <sys/file.h>
2933335Sdonn #endif
309680Slinton 
319680Slinton #ifndef public
329680Slinton typedef int Lineno;
339680Slinton 
349680Slinton String cursource;
359680Slinton Lineno curline;
369680Slinton Lineno cursrcline;
379680Slinton 
389680Slinton #define LASTLINE 0		/* recognized by printlines */
399680Slinton 
409680Slinton #include "lists.h"
419680Slinton 
429680Slinton List sourcepath;
439680Slinton #endif
449680Slinton 
4533335Sdonn #ifdef IRIS
4633335Sdonn #   define re_comp regcmp
4733335Sdonn #   define re_exec(buf) (regex(buf) != NULL)
4833335Sdonn #endif
4933335Sdonn 
5018233Slinton extern char *re_comp();
5118233Slinton 
529680Slinton private Lineno lastlinenum;
539680Slinton private String prevsource = nil;
549680Slinton 
559680Slinton /*
569680Slinton  * Data structure for indexing source seek addresses by line number.
579680Slinton  *
589680Slinton  * The constraints are:
599680Slinton  *
609680Slinton  *  we want an array so indexing is fast and easy
619680Slinton  *  we don't want to waste space for small files
629680Slinton  *  we don't want an upper bound on # of lines in a file
639680Slinton  *  we don't know how many lines there are
649680Slinton  *
659680Slinton  * The solution is a "dirty" hash table.  We have NSLOTS pointers to
669680Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
679680Slinton  * a particular line we find the slot, allocate space if necessary,
689680Slinton  * and then find its location within the pointed to array.
699680Slinton  */
709680Slinton 
7110617Slinton typedef long Seekaddr;
729680Slinton 
7318233Slinton #define NSLOTS 40
749680Slinton #define NLINESPERSLOT 500
759680Slinton 
769680Slinton #define slotno(line)    ((line) div NLINESPERSLOT)
779680Slinton #define index(line)	((line) mod NLINESPERSLOT)
789680Slinton #define slot_alloc()    newarr(Seekaddr, NLINESPERSLOT)
799680Slinton #define srcaddr(line)	seektab[slotno(line)][index(line)]
809680Slinton 
819680Slinton private File srcfp;
829680Slinton private Seekaddr *seektab[NSLOTS];
839680Slinton 
849680Slinton /*
8518233Slinton  * Determine if the current source file is available.
8618233Slinton  */
8718233Slinton 
canReadSource()8818233Slinton public boolean canReadSource ()
8918233Slinton {
9018233Slinton     boolean b;
9118233Slinton 
9218233Slinton     if (cursource == nil) {
9318233Slinton 	b = false;
9418233Slinton     } else if (cursource != prevsource) {
9518233Slinton 	skimsource();
9618233Slinton 	b = (boolean) (lastlinenum != 0);
9718233Slinton     } else {
9818233Slinton 	b = true;
9918233Slinton     }
10018233Slinton     return b;
10118233Slinton }
10218233Slinton 
10318233Slinton /*
1049680Slinton  * Print out the given lines from the source.
1059680Slinton  */
1069680Slinton 
printlines(l1,l2)1079680Slinton public printlines(l1, l2)
1089680Slinton Lineno l1, l2;
1099680Slinton {
1109680Slinton     register int c;
1119680Slinton     register Lineno i, lb, ub;
1129680Slinton     register File f;
1139680Slinton 
1149680Slinton     if (cursource == nil) {
1159680Slinton 	beginerrmsg();
1169680Slinton 	fprintf(stderr, "no source file\n");
1179680Slinton     } else {
1189680Slinton 	if (cursource != prevsource) {
1199680Slinton 	    skimsource();
1209680Slinton 	}
1219680Slinton 	if (lastlinenum == 0) {
1229680Slinton 	    beginerrmsg();
1239680Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
1249680Slinton 	} else {
12518233Slinton 	    lb = (l1 == LASTLINE) ? lastlinenum : l1;
12618233Slinton 	    ub = (l2 == LASTLINE) ? lastlinenum : l2;
1279680Slinton 	    if (lb < 1) {
1289680Slinton 		beginerrmsg();
1299680Slinton 		fprintf(stderr, "line number must be positive\n");
1309680Slinton 	    } else if (lb > lastlinenum) {
1319680Slinton 		beginerrmsg();
1329680Slinton 		if (lastlinenum == 1) {
1339680Slinton 		    fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
1349680Slinton 		} else {
1359680Slinton 		    fprintf(stderr, "\"%s\" has only %d lines\n",
1369680Slinton 			cursource, lastlinenum);
1379680Slinton 		}
1389680Slinton 	    } else if (ub < lb) {
1399680Slinton 		beginerrmsg();
1409680Slinton 		fprintf(stderr, "second number must be greater than first\n");
1419680Slinton 	    } else {
1429680Slinton 		if (ub > lastlinenum) {
1439680Slinton 		    ub = lastlinenum;
1449680Slinton 		}
1459680Slinton 		f = srcfp;
14610617Slinton 		fseek(f, srcaddr(lb), 0);
1479680Slinton 		for (i = lb; i <= ub; i++) {
1489680Slinton 		    printf("%5d   ", i);
1499680Slinton 		    while ((c = getc(f)) != '\n') {
1509680Slinton 			putchar(c);
1519680Slinton 		    }
1529680Slinton 		    putchar('\n');
1539680Slinton 		}
1549680Slinton 		cursrcline = ub + 1;
1559680Slinton 	    }
1569680Slinton 	}
1579680Slinton     }
1589680Slinton }
1599680Slinton 
1609680Slinton /*
16114337Slinton  * Search the sourcepath for a file.
1629680Slinton  */
1639680Slinton 
16414337Slinton static char fileNameBuf[1024];
16514337Slinton 
findsource(filename)16614337Slinton public String findsource(filename)
1679680Slinton String filename;
1689680Slinton {
16914337Slinton     register String src, dir;
1709680Slinton 
17112608Slinton     if (filename[0] == '/') {
17214337Slinton 	src = filename;
17312608Slinton     } else {
17414337Slinton 	src = nil;
17512608Slinton 	foreach (String, dir, sourcepath)
17614337Slinton 	    sprintf(fileNameBuf, "%s/%s", dir, filename);
17716637Ssam 	    if (access(fileNameBuf, R_OK) == 0) {
17814337Slinton 		src = fileNameBuf;
17912608Slinton 		break;
18014337Slinton 	    }
18112608Slinton 	endfor
18212608Slinton     }
18314337Slinton     return src;
18414337Slinton }
18514337Slinton 
18614337Slinton /*
18714337Slinton  * Open a source file looking in the appropriate places.
18814337Slinton  */
18914337Slinton 
opensource(filename)19014337Slinton public File opensource(filename)
19114337Slinton String filename;
19214337Slinton {
19314337Slinton     String s;
19414337Slinton     File f;
19514337Slinton 
19614337Slinton     s = findsource(filename);
19714337Slinton     if (s == nil) {
19814337Slinton 	f = nil;
19914337Slinton     } else {
20014337Slinton 	f = fopen(s, "r");
20114337Slinton     }
2029680Slinton     return f;
2039680Slinton }
2049680Slinton 
2059680Slinton /*
2069680Slinton  * Set the current source file.
2079680Slinton  */
2089680Slinton 
setsource(filename)2099680Slinton public setsource(filename)
2109680Slinton String filename;
2119680Slinton {
2129680Slinton     if (filename != nil and filename != cursource) {
2139680Slinton 	prevsource = cursource;
2149680Slinton 	cursource = filename;
2159680Slinton 	cursrcline = 1;
2169680Slinton     }
2179680Slinton }
2189680Slinton 
2199680Slinton /*
2209680Slinton  * Read the source file getting seek pointers for each line.
2219680Slinton  */
2229680Slinton 
skimsource()2239680Slinton private skimsource()
2249680Slinton {
2259680Slinton     register int c;
22610617Slinton     register Seekaddr count;
2279680Slinton     register File f;
2289680Slinton     register Lineno linenum;
2299680Slinton     register Seekaddr lastaddr;
2309680Slinton     register int slot;
2319680Slinton 
2329680Slinton     f = opensource(cursource);
2339680Slinton     if (f == nil) {
2349680Slinton 	lastlinenum = 0;
2359680Slinton     } else {
2369680Slinton 	if (prevsource != nil) {
2379680Slinton 	    free_seektab();
2389680Slinton 	    if (srcfp != nil) {
2399680Slinton 		fclose(srcfp);
2409680Slinton 	    }
2419680Slinton 	}
2429680Slinton 	prevsource = cursource;
2439680Slinton 	linenum = 0;
2449680Slinton 	count = 0;
2459680Slinton 	lastaddr = 0;
2469680Slinton 	while ((c = getc(f)) != EOF) {
2479680Slinton 	    ++count;
2489680Slinton 	    if (c == '\n') {
2499680Slinton 		slot = slotno(++linenum);
2509680Slinton 		if (slot >= NSLOTS) {
2519680Slinton 		    panic("skimsource: too many lines");
2529680Slinton 		}
2539680Slinton 		if (seektab[slot] == nil) {
2549680Slinton 		    seektab[slot] = slot_alloc();
2559680Slinton 		}
2569680Slinton 		seektab[slot][index(linenum)] = lastaddr;
2579680Slinton 		lastaddr = count;
2589680Slinton 	    }
2599680Slinton 	}
2609680Slinton 	lastlinenum = linenum;
2619680Slinton 	srcfp = f;
2629680Slinton     }
2639680Slinton }
2649680Slinton 
2659680Slinton /*
2669680Slinton  * Erase information and release space in the current seektab.
2679680Slinton  * This is in preparation for reading in seek pointers for a
2689680Slinton  * new file.  It is possible that seek pointers for all files
2699680Slinton  * should be kept around, but the current concern is space.
2709680Slinton  */
2719680Slinton 
free_seektab()2729680Slinton private free_seektab()
2739680Slinton {
2749680Slinton     register int slot;
2759680Slinton 
2769680Slinton     for (slot = 0; slot < NSLOTS; slot++) {
2779680Slinton 	if (seektab[slot] != nil) {
2789680Slinton 	    dispose(seektab[slot]);
2799680Slinton 	}
2809680Slinton     }
2819680Slinton }
2829680Slinton 
2839680Slinton /*
2849680Slinton  * Figure out current source position.
2859680Slinton  */
2869680Slinton 
getsrcpos()2879680Slinton public getsrcpos()
2889680Slinton {
2899680Slinton     String filename;
2909680Slinton 
29111105Slinton     curline = srcline(pc);
29211105Slinton     filename = srcfilename(pc);
2939680Slinton     setsource(filename);
29411837Slinton     if (curline != 0) {
29511837Slinton 	cursrcline = curline;
29611837Slinton     }
2979680Slinton }
2989680Slinton 
2999680Slinton /*
3009680Slinton  * Print out the current source position.
3019680Slinton  */
3029680Slinton 
printsrcpos()3039680Slinton public printsrcpos()
3049680Slinton {
3059680Slinton     printf("at line %d", curline);
3069680Slinton     if (nlhdr.nfiles > 1) {
3079680Slinton 	printf(" in file \"%s\"", cursource);
3089680Slinton     }
3099680Slinton }
31014337Slinton 
31114337Slinton #define DEF_EDITOR  "vi"
31214337Slinton 
31314337Slinton /*
31414337Slinton  * Invoke an editor on the given file.  Which editor to use might change
31514337Slinton  * installation to installation.  For now, we use "vi".  In any event,
31614337Slinton  * the environment variable "EDITOR" overrides any default.
31714337Slinton  */
31814337Slinton 
edit(filename)31914337Slinton public edit(filename)
32014337Slinton String filename;
32114337Slinton {
32214337Slinton     extern String getenv();
32314337Slinton     String ed, src, s;
32414337Slinton     Symbol f;
32514337Slinton     Address addr;
32614337Slinton     char lineno[10];
32714337Slinton 
32814337Slinton     ed = getenv("EDITOR");
32914337Slinton     if (ed == nil) {
33014337Slinton 	ed = DEF_EDITOR;
33114337Slinton     }
33214337Slinton     src = findsource((filename != nil) ? filename : cursource);
33314337Slinton     if (src == nil) {
33414337Slinton 	f = which(identname(filename, true));
33514337Slinton 	if (not isblock(f)) {
33614337Slinton 	    error("can't read \"%s\"", filename);
33714337Slinton 	}
33814337Slinton 	addr = firstline(f);
33914337Slinton 	if (addr == NOADDR) {
34014337Slinton 	    error("no source for \"%s\"", filename);
34114337Slinton 	}
34214337Slinton 	src = srcfilename(addr);
34314337Slinton 	s = findsource(src);
34414337Slinton 	if (s != nil) {
34514337Slinton 	    src = s;
34614337Slinton 	}
34714337Slinton 	sprintf(lineno, "+%d", srcline(addr));
34814337Slinton     } else {
34914337Slinton 	sprintf(lineno, "+1");
35014337Slinton     }
35118233Slinton     if (streq(ed, "vi") or streq(ed, "ex")) {
35218233Slinton 	call(ed, stdin, stdout, lineno, src, nil);
35318233Slinton     } else {
35418233Slinton 	call(ed, stdin, stdout, src, nil);
35518233Slinton     }
35614337Slinton }
35716637Ssam 
35816637Ssam /*
35918233Slinton  * Strip away portions of a given pattern not part of the regular expression.
36016637Ssam  */
36118233Slinton 
getpattern(pattern)36218233Slinton private String getpattern (pattern)
36318233Slinton String pattern;
36416637Ssam {
36518233Slinton     register char *p, *r;
36618233Slinton 
36718233Slinton     p = pattern;
36818233Slinton     while (*p == ' ' or *p == '\t') {
36918233Slinton 	++p;
37018233Slinton     }
37118233Slinton     r = p;
37218233Slinton     while (*p != '\0') {
37318233Slinton 	++p;
37418233Slinton     }
37518233Slinton     --p;
37618233Slinton     if (*p == '\n') {
37718233Slinton 	*p = '\0';
37818233Slinton 	--p;
37918233Slinton     }
38018233Slinton     if (*p == *r) {
38118233Slinton 	*p = '\0';
38218233Slinton 	--p;
38318233Slinton     }
38418233Slinton     return r + 1;
38518233Slinton }
38618233Slinton 
38718233Slinton /*
38818233Slinton  * Search the current file for a regular expression.
38918233Slinton  */
39018233Slinton 
search(direction,pattern)39118233Slinton public search (direction, pattern)
39218233Slinton char direction;
39318233Slinton String pattern;
39418233Slinton {
39518233Slinton     register String p;
39618233Slinton     register File f;
39718233Slinton     String re, err;
39818233Slinton     Lineno line;
39918233Slinton     boolean matched;
40018233Slinton     char buf[512];
40118233Slinton 
40218233Slinton     if (cursource == nil) {
40318233Slinton 	beginerrmsg();
40418233Slinton 	fprintf(stderr, "no source file\n");
40518233Slinton     } else {
40618233Slinton 	if (cursource != prevsource) {
40718233Slinton 	    skimsource();
40816637Ssam 	}
40916637Ssam 	if (lastlinenum == 0) {
41018233Slinton 	    beginerrmsg();
41118233Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
41218233Slinton 	} else {
41318233Slinton 	    re = getpattern(pattern);
41418233Slinton 	    /* circf = 0; */
41518233Slinton 	    if (re != nil and *re != '\0') {
41618233Slinton 		err = re_comp(re);
41718233Slinton 		if (err != nil) {
41818233Slinton 		    error(err);
41918233Slinton 		}
42018233Slinton 	    }
42118233Slinton 	    matched = false;
42218233Slinton 	    f = srcfp;
42318233Slinton 	    line = cursrcline;
42418233Slinton 	    do {
42518233Slinton 		if (direction == '/') {
42618233Slinton 		    ++line;
42718233Slinton 		    if (line > lastlinenum) {
42818233Slinton 			line = 1;
42918233Slinton 		    }
43016637Ssam 		} else {
43118233Slinton 		    --line;
43218233Slinton 		    if (line < 1) {
43318233Slinton 			line = lastlinenum;
43418233Slinton 		    }
43516637Ssam 		}
43616637Ssam 		fseek(f, srcaddr(line), L_SET);
43718233Slinton 		p = buf;
43818233Slinton 		*p = getc(f);
43918233Slinton 		while ((*p != '\n') and (*p != EOF)) {
44018233Slinton 		    ++p;
44118233Slinton 		    *p = getc(f);
44218233Slinton 		}
44316637Ssam 		*p = '\0';
44418233Slinton 		matched = (boolean) re_exec(buf);
44518233Slinton 	    } while (not matched and line != cursrcline);
44618233Slinton 	    if (not matched) {
44718233Slinton 		beginerrmsg();
44818233Slinton 		fprintf(stderr, "no match\n");
44918233Slinton 	    } else {
45018233Slinton 		printlines(line, line);
45118233Slinton 		cursrcline = line;
45218233Slinton 	    }
45318233Slinton 	}
45418233Slinton     }
45516637Ssam }
45618233Slinton 
srcwindowlen()45733335Sdonn public integer srcwindowlen ()
45833335Sdonn {
45933335Sdonn     Node s;
46033335Sdonn 
46133335Sdonn     s = findvar(identname("$listwindow", true));
46233335Sdonn     if (s == nil)
46333335Sdonn 	return 10;
46433335Sdonn     eval(s);
46533335Sdonn     return pop(integer);
46633335Sdonn }
46733335Sdonn 
46818233Slinton /*
46918233Slinton  * Compute a small window around the given line.
47018233Slinton  */
47118233Slinton 
getsrcwindow(line,l1,l2)47218233Slinton public getsrcwindow (line, l1, l2)
47318233Slinton Lineno line, *l1, *l2;
47418233Slinton {
47518233Slinton     integer size;
47618233Slinton 
47733335Sdonn     size = srcwindowlen();
47818233Slinton     *l1 = line - (size div 2);
47918233Slinton     if (*l1 < 1) {
48018233Slinton 	*l1 = 1;
48118233Slinton     }
48218233Slinton     *l2 = *l1 + size;
48318233Slinton     if (lastlinenum != LASTLINE and *l2 > lastlinenum) {
48418233Slinton 	*l2 = lastlinenum;
48518233Slinton     }
48618233Slinton }
487