xref: /csrg-svn/old/dbx/source.c (revision 33335)
121623Sdist /*
221623Sdist  * Copyright (c) 1983 Regents of the University of California.
321623Sdist  * All rights reserved.  The Berkeley software License Agreement
421623Sdist  * specifies the terms and conditions for redistribution.
521623Sdist  */
69680Slinton 
721623Sdist #ifndef lint
8*33335Sdonn static char sccsid[] = "@(#)source.c	5.2 (Berkeley) 01/12/88";
921623Sdist #endif not lint
109680Slinton 
11*33335Sdonn static char rcsid[] = "$Header: source.c,v 1.3 87/08/19 15:19:40 mike 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"
25*33335Sdonn #ifdef IRIS
26*33335Sdonn #   define R_OK 04	/* read access */
27*33335Sdonn #   define L_SET 01	/* absolute offset for seek */
28*33335Sdonn #else
29*33335Sdonn #   include <sys/file.h>
30*33335Sdonn #endif
319680Slinton 
329680Slinton #ifndef public
339680Slinton typedef int Lineno;
349680Slinton 
359680Slinton String cursource;
369680Slinton Lineno curline;
379680Slinton Lineno cursrcline;
389680Slinton 
399680Slinton #define LASTLINE 0		/* recognized by printlines */
409680Slinton 
419680Slinton #include "lists.h"
429680Slinton 
439680Slinton List sourcepath;
449680Slinton #endif
459680Slinton 
46*33335Sdonn #ifdef IRIS
47*33335Sdonn #   define re_comp regcmp
48*33335Sdonn #   define re_exec(buf) (regex(buf) != NULL)
49*33335Sdonn #endif
50*33335Sdonn 
5118233Slinton extern char *re_comp();
5218233Slinton 
539680Slinton private Lineno lastlinenum;
549680Slinton private String prevsource = nil;
559680Slinton 
569680Slinton /*
579680Slinton  * Data structure for indexing source seek addresses by line number.
589680Slinton  *
599680Slinton  * The constraints are:
609680Slinton  *
619680Slinton  *  we want an array so indexing is fast and easy
629680Slinton  *  we don't want to waste space for small files
639680Slinton  *  we don't want an upper bound on # of lines in a file
649680Slinton  *  we don't know how many lines there are
659680Slinton  *
669680Slinton  * The solution is a "dirty" hash table.  We have NSLOTS pointers to
679680Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
689680Slinton  * a particular line we find the slot, allocate space if necessary,
699680Slinton  * and then find its location within the pointed to array.
709680Slinton  */
719680Slinton 
7210617Slinton typedef long Seekaddr;
739680Slinton 
7418233Slinton #define NSLOTS 40
759680Slinton #define NLINESPERSLOT 500
769680Slinton 
779680Slinton #define slotno(line)    ((line) div NLINESPERSLOT)
789680Slinton #define index(line)	((line) mod NLINESPERSLOT)
799680Slinton #define slot_alloc()    newarr(Seekaddr, NLINESPERSLOT)
809680Slinton #define srcaddr(line)	seektab[slotno(line)][index(line)]
819680Slinton 
829680Slinton private File srcfp;
839680Slinton private Seekaddr *seektab[NSLOTS];
849680Slinton 
859680Slinton /*
8618233Slinton  * Determine if the current source file is available.
8718233Slinton  */
8818233Slinton 
8918233Slinton public boolean canReadSource ()
9018233Slinton {
9118233Slinton     boolean b;
9218233Slinton 
9318233Slinton     if (cursource == nil) {
9418233Slinton 	b = false;
9518233Slinton     } else if (cursource != prevsource) {
9618233Slinton 	skimsource();
9718233Slinton 	b = (boolean) (lastlinenum != 0);
9818233Slinton     } else {
9918233Slinton 	b = true;
10018233Slinton     }
10118233Slinton     return b;
10218233Slinton }
10318233Slinton 
10418233Slinton /*
1059680Slinton  * Print out the given lines from the source.
1069680Slinton  */
1079680Slinton 
1089680Slinton public printlines(l1, l2)
1099680Slinton Lineno l1, l2;
1109680Slinton {
1119680Slinton     register int c;
1129680Slinton     register Lineno i, lb, ub;
1139680Slinton     register File f;
1149680Slinton 
1159680Slinton     if (cursource == nil) {
1169680Slinton 	beginerrmsg();
1179680Slinton 	fprintf(stderr, "no source file\n");
1189680Slinton     } else {
1199680Slinton 	if (cursource != prevsource) {
1209680Slinton 	    skimsource();
1219680Slinton 	}
1229680Slinton 	if (lastlinenum == 0) {
1239680Slinton 	    beginerrmsg();
1249680Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
1259680Slinton 	} else {
12618233Slinton 	    lb = (l1 == LASTLINE) ? lastlinenum : l1;
12718233Slinton 	    ub = (l2 == LASTLINE) ? lastlinenum : l2;
1289680Slinton 	    if (lb < 1) {
1299680Slinton 		beginerrmsg();
1309680Slinton 		fprintf(stderr, "line number must be positive\n");
1319680Slinton 	    } else if (lb > lastlinenum) {
1329680Slinton 		beginerrmsg();
1339680Slinton 		if (lastlinenum == 1) {
1349680Slinton 		    fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
1359680Slinton 		} else {
1369680Slinton 		    fprintf(stderr, "\"%s\" has only %d lines\n",
1379680Slinton 			cursource, lastlinenum);
1389680Slinton 		}
1399680Slinton 	    } else if (ub < lb) {
1409680Slinton 		beginerrmsg();
1419680Slinton 		fprintf(stderr, "second number must be greater than first\n");
1429680Slinton 	    } else {
1439680Slinton 		if (ub > lastlinenum) {
1449680Slinton 		    ub = lastlinenum;
1459680Slinton 		}
1469680Slinton 		f = srcfp;
14710617Slinton 		fseek(f, srcaddr(lb), 0);
1489680Slinton 		for (i = lb; i <= ub; i++) {
1499680Slinton 		    printf("%5d   ", i);
1509680Slinton 		    while ((c = getc(f)) != '\n') {
1519680Slinton 			putchar(c);
1529680Slinton 		    }
1539680Slinton 		    putchar('\n');
1549680Slinton 		}
1559680Slinton 		cursrcline = ub + 1;
1569680Slinton 	    }
1579680Slinton 	}
1589680Slinton     }
1599680Slinton }
1609680Slinton 
1619680Slinton /*
16214337Slinton  * Search the sourcepath for a file.
1639680Slinton  */
1649680Slinton 
16514337Slinton static char fileNameBuf[1024];
16614337Slinton 
16714337Slinton public String findsource(filename)
1689680Slinton String filename;
1699680Slinton {
17014337Slinton     register String src, dir;
1719680Slinton 
17212608Slinton     if (filename[0] == '/') {
17314337Slinton 	src = filename;
17412608Slinton     } else {
17514337Slinton 	src = nil;
17612608Slinton 	foreach (String, dir, sourcepath)
17714337Slinton 	    sprintf(fileNameBuf, "%s/%s", dir, filename);
17816637Ssam 	    if (access(fileNameBuf, R_OK) == 0) {
17914337Slinton 		src = fileNameBuf;
18012608Slinton 		break;
18114337Slinton 	    }
18212608Slinton 	endfor
18312608Slinton     }
18414337Slinton     return src;
18514337Slinton }
18614337Slinton 
18714337Slinton /*
18814337Slinton  * Open a source file looking in the appropriate places.
18914337Slinton  */
19014337Slinton 
19114337Slinton public File opensource(filename)
19214337Slinton String filename;
19314337Slinton {
19414337Slinton     String s;
19514337Slinton     File f;
19614337Slinton 
19714337Slinton     s = findsource(filename);
19814337Slinton     if (s == nil) {
19914337Slinton 	f = nil;
20014337Slinton     } else {
20114337Slinton 	f = fopen(s, "r");
20214337Slinton     }
2039680Slinton     return f;
2049680Slinton }
2059680Slinton 
2069680Slinton /*
2079680Slinton  * Set the current source file.
2089680Slinton  */
2099680Slinton 
2109680Slinton public setsource(filename)
2119680Slinton String filename;
2129680Slinton {
2139680Slinton     if (filename != nil and filename != cursource) {
2149680Slinton 	prevsource = cursource;
2159680Slinton 	cursource = filename;
2169680Slinton 	cursrcline = 1;
2179680Slinton     }
2189680Slinton }
2199680Slinton 
2209680Slinton /*
2219680Slinton  * Read the source file getting seek pointers for each line.
2229680Slinton  */
2239680Slinton 
2249680Slinton private skimsource()
2259680Slinton {
2269680Slinton     register int c;
22710617Slinton     register Seekaddr count;
2289680Slinton     register File f;
2299680Slinton     register Lineno linenum;
2309680Slinton     register Seekaddr lastaddr;
2319680Slinton     register int slot;
2329680Slinton 
2339680Slinton     f = opensource(cursource);
2349680Slinton     if (f == nil) {
2359680Slinton 	lastlinenum = 0;
2369680Slinton     } else {
2379680Slinton 	if (prevsource != nil) {
2389680Slinton 	    free_seektab();
2399680Slinton 	    if (srcfp != nil) {
2409680Slinton 		fclose(srcfp);
2419680Slinton 	    }
2429680Slinton 	}
2439680Slinton 	prevsource = cursource;
2449680Slinton 	linenum = 0;
2459680Slinton 	count = 0;
2469680Slinton 	lastaddr = 0;
2479680Slinton 	while ((c = getc(f)) != EOF) {
2489680Slinton 	    ++count;
2499680Slinton 	    if (c == '\n') {
2509680Slinton 		slot = slotno(++linenum);
2519680Slinton 		if (slot >= NSLOTS) {
2529680Slinton 		    panic("skimsource: too many lines");
2539680Slinton 		}
2549680Slinton 		if (seektab[slot] == nil) {
2559680Slinton 		    seektab[slot] = slot_alloc();
2569680Slinton 		}
2579680Slinton 		seektab[slot][index(linenum)] = lastaddr;
2589680Slinton 		lastaddr = count;
2599680Slinton 	    }
2609680Slinton 	}
2619680Slinton 	lastlinenum = linenum;
2629680Slinton 	srcfp = f;
2639680Slinton     }
2649680Slinton }
2659680Slinton 
2669680Slinton /*
2679680Slinton  * Erase information and release space in the current seektab.
2689680Slinton  * This is in preparation for reading in seek pointers for a
2699680Slinton  * new file.  It is possible that seek pointers for all files
2709680Slinton  * should be kept around, but the current concern is space.
2719680Slinton  */
2729680Slinton 
2739680Slinton private free_seektab()
2749680Slinton {
2759680Slinton     register int slot;
2769680Slinton 
2779680Slinton     for (slot = 0; slot < NSLOTS; slot++) {
2789680Slinton 	if (seektab[slot] != nil) {
2799680Slinton 	    dispose(seektab[slot]);
2809680Slinton 	}
2819680Slinton     }
2829680Slinton }
2839680Slinton 
2849680Slinton /*
2859680Slinton  * Figure out current source position.
2869680Slinton  */
2879680Slinton 
2889680Slinton public getsrcpos()
2899680Slinton {
2909680Slinton     String filename;
2919680Slinton 
29211105Slinton     curline = srcline(pc);
29311105Slinton     filename = srcfilename(pc);
2949680Slinton     setsource(filename);
29511837Slinton     if (curline != 0) {
29611837Slinton 	cursrcline = curline;
29711837Slinton     }
2989680Slinton }
2999680Slinton 
3009680Slinton /*
3019680Slinton  * Print out the current source position.
3029680Slinton  */
3039680Slinton 
3049680Slinton public printsrcpos()
3059680Slinton {
3069680Slinton     printf("at line %d", curline);
3079680Slinton     if (nlhdr.nfiles > 1) {
3089680Slinton 	printf(" in file \"%s\"", cursource);
3099680Slinton     }
3109680Slinton }
31114337Slinton 
31214337Slinton #define DEF_EDITOR  "vi"
31314337Slinton 
31414337Slinton /*
31514337Slinton  * Invoke an editor on the given file.  Which editor to use might change
31614337Slinton  * installation to installation.  For now, we use "vi".  In any event,
31714337Slinton  * the environment variable "EDITOR" overrides any default.
31814337Slinton  */
31914337Slinton 
32014337Slinton public edit(filename)
32114337Slinton String filename;
32214337Slinton {
32314337Slinton     extern String getenv();
32414337Slinton     String ed, src, s;
32514337Slinton     Symbol f;
32614337Slinton     Address addr;
32714337Slinton     char lineno[10];
32814337Slinton 
32914337Slinton     ed = getenv("EDITOR");
33014337Slinton     if (ed == nil) {
33114337Slinton 	ed = DEF_EDITOR;
33214337Slinton     }
33314337Slinton     src = findsource((filename != nil) ? filename : cursource);
33414337Slinton     if (src == nil) {
33514337Slinton 	f = which(identname(filename, true));
33614337Slinton 	if (not isblock(f)) {
33714337Slinton 	    error("can't read \"%s\"", filename);
33814337Slinton 	}
33914337Slinton 	addr = firstline(f);
34014337Slinton 	if (addr == NOADDR) {
34114337Slinton 	    error("no source for \"%s\"", filename);
34214337Slinton 	}
34314337Slinton 	src = srcfilename(addr);
34414337Slinton 	s = findsource(src);
34514337Slinton 	if (s != nil) {
34614337Slinton 	    src = s;
34714337Slinton 	}
34814337Slinton 	sprintf(lineno, "+%d", srcline(addr));
34914337Slinton     } else {
35014337Slinton 	sprintf(lineno, "+1");
35114337Slinton     }
35218233Slinton     if (streq(ed, "vi") or streq(ed, "ex")) {
35318233Slinton 	call(ed, stdin, stdout, lineno, src, nil);
35418233Slinton     } else {
35518233Slinton 	call(ed, stdin, stdout, src, nil);
35618233Slinton     }
35714337Slinton }
35816637Ssam 
35916637Ssam /*
36018233Slinton  * Strip away portions of a given pattern not part of the regular expression.
36116637Ssam  */
36218233Slinton 
36318233Slinton private String getpattern (pattern)
36418233Slinton String pattern;
36516637Ssam {
36618233Slinton     register char *p, *r;
36718233Slinton 
36818233Slinton     p = pattern;
36918233Slinton     while (*p == ' ' or *p == '\t') {
37018233Slinton 	++p;
37118233Slinton     }
37218233Slinton     r = p;
37318233Slinton     while (*p != '\0') {
37418233Slinton 	++p;
37518233Slinton     }
37618233Slinton     --p;
37718233Slinton     if (*p == '\n') {
37818233Slinton 	*p = '\0';
37918233Slinton 	--p;
38018233Slinton     }
38118233Slinton     if (*p == *r) {
38218233Slinton 	*p = '\0';
38318233Slinton 	--p;
38418233Slinton     }
38518233Slinton     return r + 1;
38618233Slinton }
38718233Slinton 
38818233Slinton /*
38918233Slinton  * Search the current file for a regular expression.
39018233Slinton  */
39118233Slinton 
39218233Slinton public search (direction, pattern)
39318233Slinton char direction;
39418233Slinton String pattern;
39518233Slinton {
39618233Slinton     register String p;
39718233Slinton     register File f;
39818233Slinton     String re, err;
39918233Slinton     Lineno line;
40018233Slinton     boolean matched;
40118233Slinton     char buf[512];
40218233Slinton 
40318233Slinton     if (cursource == nil) {
40418233Slinton 	beginerrmsg();
40518233Slinton 	fprintf(stderr, "no source file\n");
40618233Slinton     } else {
40718233Slinton 	if (cursource != prevsource) {
40818233Slinton 	    skimsource();
40916637Ssam 	}
41016637Ssam 	if (lastlinenum == 0) {
41118233Slinton 	    beginerrmsg();
41218233Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
41318233Slinton 	} else {
41418233Slinton 	    re = getpattern(pattern);
41518233Slinton 	    /* circf = 0; */
41618233Slinton 	    if (re != nil and *re != '\0') {
41718233Slinton 		err = re_comp(re);
41818233Slinton 		if (err != nil) {
41918233Slinton 		    error(err);
42018233Slinton 		}
42118233Slinton 	    }
42218233Slinton 	    matched = false;
42318233Slinton 	    f = srcfp;
42418233Slinton 	    line = cursrcline;
42518233Slinton 	    do {
42618233Slinton 		if (direction == '/') {
42718233Slinton 		    ++line;
42818233Slinton 		    if (line > lastlinenum) {
42918233Slinton 			line = 1;
43018233Slinton 		    }
43116637Ssam 		} else {
43218233Slinton 		    --line;
43318233Slinton 		    if (line < 1) {
43418233Slinton 			line = lastlinenum;
43518233Slinton 		    }
43616637Ssam 		}
43716637Ssam 		fseek(f, srcaddr(line), L_SET);
43818233Slinton 		p = buf;
43918233Slinton 		*p = getc(f);
44018233Slinton 		while ((*p != '\n') and (*p != EOF)) {
44118233Slinton 		    ++p;
44218233Slinton 		    *p = getc(f);
44318233Slinton 		}
44416637Ssam 		*p = '\0';
44518233Slinton 		matched = (boolean) re_exec(buf);
44618233Slinton 	    } while (not matched and line != cursrcline);
44718233Slinton 	    if (not matched) {
44818233Slinton 		beginerrmsg();
44918233Slinton 		fprintf(stderr, "no match\n");
45018233Slinton 	    } else {
45118233Slinton 		printlines(line, line);
45218233Slinton 		cursrcline = line;
45318233Slinton 	    }
45418233Slinton 	}
45518233Slinton     }
45616637Ssam }
45718233Slinton 
458*33335Sdonn public integer srcwindowlen ()
459*33335Sdonn {
460*33335Sdonn     Node s;
461*33335Sdonn 
462*33335Sdonn     s = findvar(identname("$listwindow", true));
463*33335Sdonn     if (s == nil)
464*33335Sdonn 	return 10;
465*33335Sdonn     eval(s);
466*33335Sdonn     return pop(integer);
467*33335Sdonn }
468*33335Sdonn 
46918233Slinton /*
47018233Slinton  * Compute a small window around the given line.
47118233Slinton  */
47218233Slinton 
47318233Slinton public getsrcwindow (line, l1, l2)
47418233Slinton Lineno line, *l1, *l2;
47518233Slinton {
47618233Slinton     integer size;
47718233Slinton 
478*33335Sdonn     size = srcwindowlen();
47918233Slinton     *l1 = line - (size div 2);
48018233Slinton     if (*l1 < 1) {
48118233Slinton 	*l1 = 1;
48218233Slinton     }
48318233Slinton     *l2 = *l1 + size;
48418233Slinton     if (lastlinenum != LASTLINE and *l2 > lastlinenum) {
48518233Slinton 	*l2 = lastlinenum;
48618233Slinton     }
48718233Slinton }
488