xref: /csrg-svn/old/dbx/source.c (revision 21623)
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