xref: /csrg-svn/old/dbx/source.c (revision 16637)
19680Slinton /* Copyright (c) 1982 Regents of the University of California */
29680Slinton 
3*16637Ssam static	char sccsid[] = "@(#)source.c	1.11 (Berkeley) 06/23/84";
49680Slinton 
59680Slinton /*
69680Slinton  * Source file management.
79680Slinton  */
89680Slinton 
99680Slinton #include "defs.h"
109680Slinton #include "source.h"
119680Slinton #include "object.h"
129680Slinton #include "mappings.h"
139680Slinton #include "machine.h"
14*16637Ssam #include <sys/file.h>
159680Slinton 
169680Slinton #ifndef public
179680Slinton typedef int Lineno;
189680Slinton 
199680Slinton String cursource;
209680Slinton Lineno curline;
219680Slinton Lineno cursrcline;
229680Slinton 
239680Slinton #define LASTLINE 0		/* recognized by printlines */
249680Slinton 
259680Slinton #include "lists.h"
269680Slinton 
279680Slinton List sourcepath;
289680Slinton #endif
299680Slinton 
309680Slinton private Lineno lastlinenum;
319680Slinton private String prevsource = nil;
329680Slinton 
339680Slinton /*
349680Slinton  * Data structure for indexing source seek addresses by line number.
359680Slinton  *
369680Slinton  * The constraints are:
379680Slinton  *
389680Slinton  *  we want an array so indexing is fast and easy
399680Slinton  *  we don't want to waste space for small files
409680Slinton  *  we don't want an upper bound on # of lines in a file
419680Slinton  *  we don't know how many lines there are
429680Slinton  *
439680Slinton  * The solution is a "dirty" hash table.  We have NSLOTS pointers to
449680Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
459680Slinton  * a particular line we find the slot, allocate space if necessary,
469680Slinton  * and then find its location within the pointed to array.
479680Slinton  */
489680Slinton 
4910617Slinton typedef long Seekaddr;
509680Slinton 
519680Slinton #define NSLOTS 20
529680Slinton #define NLINESPERSLOT 500
539680Slinton 
549680Slinton #define slotno(line)    ((line) div NLINESPERSLOT)
559680Slinton #define index(line)	((line) mod NLINESPERSLOT)
569680Slinton #define slot_alloc()    newarr(Seekaddr, NLINESPERSLOT)
579680Slinton #define srcaddr(line)	seektab[slotno(line)][index(line)]
589680Slinton 
599680Slinton private File srcfp;
609680Slinton private Seekaddr *seektab[NSLOTS];
619680Slinton 
629680Slinton /*
639680Slinton  * Print out the given lines from the source.
649680Slinton  */
659680Slinton 
669680Slinton public printlines(l1, l2)
679680Slinton Lineno l1, l2;
689680Slinton {
699680Slinton     register int c;
709680Slinton     register Lineno i, lb, ub;
719680Slinton     register File f;
729680Slinton 
739680Slinton     if (cursource == nil) {
749680Slinton 	beginerrmsg();
759680Slinton 	fprintf(stderr, "no source file\n");
769680Slinton     } else {
779680Slinton 	if (cursource != prevsource) {
789680Slinton 	    skimsource();
799680Slinton 	}
809680Slinton 	if (lastlinenum == 0) {
819680Slinton 	    beginerrmsg();
829680Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
839680Slinton 	} else {
849680Slinton 	    lb = (l1 == 0) ? lastlinenum : l1;
859680Slinton 	    ub = (l2 == 0) ? lastlinenum : l2;
869680Slinton 	    if (lb < 1) {
879680Slinton 		beginerrmsg();
889680Slinton 		fprintf(stderr, "line number must be positive\n");
899680Slinton 	    } else if (lb > lastlinenum) {
909680Slinton 		beginerrmsg();
919680Slinton 		if (lastlinenum == 1) {
929680Slinton 		    fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
939680Slinton 		} else {
949680Slinton 		    fprintf(stderr, "\"%s\" has only %d lines\n",
959680Slinton 			cursource, lastlinenum);
969680Slinton 		}
979680Slinton 	    } else if (ub < lb) {
989680Slinton 		beginerrmsg();
999680Slinton 		fprintf(stderr, "second number must be greater than first\n");
1009680Slinton 	    } else {
1019680Slinton 		if (ub > lastlinenum) {
1029680Slinton 		    ub = lastlinenum;
1039680Slinton 		}
1049680Slinton 		f = srcfp;
10510617Slinton 		fseek(f, srcaddr(lb), 0);
1069680Slinton 		for (i = lb; i <= ub; i++) {
1079680Slinton 		    printf("%5d   ", i);
1089680Slinton 		    while ((c = getc(f)) != '\n') {
1099680Slinton 			putchar(c);
1109680Slinton 		    }
1119680Slinton 		    putchar('\n');
1129680Slinton 		}
1139680Slinton 		cursrcline = ub + 1;
1149680Slinton 	    }
1159680Slinton 	}
1169680Slinton     }
1179680Slinton }
1189680Slinton 
1199680Slinton /*
12014337Slinton  * Search the sourcepath for a file.
1219680Slinton  */
1229680Slinton 
12314337Slinton static char fileNameBuf[1024];
12414337Slinton 
12514337Slinton public String findsource(filename)
1269680Slinton String filename;
1279680Slinton {
12814337Slinton     register String src, dir;
1299680Slinton 
13012608Slinton     if (filename[0] == '/') {
13114337Slinton 	src = filename;
13212608Slinton     } else {
13314337Slinton 	src = nil;
13412608Slinton 	foreach (String, dir, sourcepath)
13514337Slinton 	    sprintf(fileNameBuf, "%s/%s", dir, filename);
136*16637Ssam 	    if (access(fileNameBuf, R_OK) == 0) {
13714337Slinton 		src = fileNameBuf;
13812608Slinton 		break;
13914337Slinton 	    }
14012608Slinton 	endfor
14112608Slinton     }
14214337Slinton     return src;
14314337Slinton }
14414337Slinton 
14514337Slinton /*
14614337Slinton  * Open a source file looking in the appropriate places.
14714337Slinton  */
14814337Slinton 
14914337Slinton public File opensource(filename)
15014337Slinton String filename;
15114337Slinton {
15214337Slinton     String s;
15314337Slinton     File f;
15414337Slinton 
15514337Slinton     s = findsource(filename);
15614337Slinton     if (s == nil) {
15714337Slinton 	f = nil;
15814337Slinton     } else {
15914337Slinton 	f = fopen(s, "r");
16014337Slinton     }
1619680Slinton     return f;
1629680Slinton }
1639680Slinton 
1649680Slinton /*
1659680Slinton  * Set the current source file.
1669680Slinton  */
1679680Slinton 
1689680Slinton public setsource(filename)
1699680Slinton String filename;
1709680Slinton {
1719680Slinton     if (filename != nil and filename != cursource) {
1729680Slinton 	prevsource = cursource;
1739680Slinton 	cursource = filename;
1749680Slinton 	cursrcline = 1;
1759680Slinton     }
1769680Slinton }
1779680Slinton 
1789680Slinton /*
1799680Slinton  * Read the source file getting seek pointers for each line.
1809680Slinton  */
1819680Slinton 
1829680Slinton private skimsource()
1839680Slinton {
1849680Slinton     register int c;
18510617Slinton     register Seekaddr count;
1869680Slinton     register File f;
1879680Slinton     register Lineno linenum;
1889680Slinton     register Seekaddr lastaddr;
1899680Slinton     register int slot;
1909680Slinton 
1919680Slinton     f = opensource(cursource);
1929680Slinton     if (f == nil) {
1939680Slinton 	lastlinenum = 0;
1949680Slinton     } else {
1959680Slinton 	if (prevsource != nil) {
1969680Slinton 	    free_seektab();
1979680Slinton 	    if (srcfp != nil) {
1989680Slinton 		fclose(srcfp);
1999680Slinton 	    }
2009680Slinton 	}
2019680Slinton 	prevsource = cursource;
2029680Slinton 	linenum = 0;
2039680Slinton 	count = 0;
2049680Slinton 	lastaddr = 0;
2059680Slinton 	while ((c = getc(f)) != EOF) {
2069680Slinton 	    ++count;
2079680Slinton 	    if (c == '\n') {
2089680Slinton 		slot = slotno(++linenum);
2099680Slinton 		if (slot >= NSLOTS) {
2109680Slinton 		    panic("skimsource: too many lines");
2119680Slinton 		}
2129680Slinton 		if (seektab[slot] == nil) {
2139680Slinton 		    seektab[slot] = slot_alloc();
2149680Slinton 		}
2159680Slinton 		seektab[slot][index(linenum)] = lastaddr;
2169680Slinton 		lastaddr = count;
2179680Slinton 	    }
2189680Slinton 	}
2199680Slinton 	lastlinenum = linenum;
2209680Slinton 	srcfp = f;
2219680Slinton     }
2229680Slinton }
2239680Slinton 
2249680Slinton /*
2259680Slinton  * Erase information and release space in the current seektab.
2269680Slinton  * This is in preparation for reading in seek pointers for a
2279680Slinton  * new file.  It is possible that seek pointers for all files
2289680Slinton  * should be kept around, but the current concern is space.
2299680Slinton  */
2309680Slinton 
2319680Slinton private free_seektab()
2329680Slinton {
2339680Slinton     register int slot;
2349680Slinton 
2359680Slinton     for (slot = 0; slot < NSLOTS; slot++) {
2369680Slinton 	if (seektab[slot] != nil) {
2379680Slinton 	    dispose(seektab[slot]);
2389680Slinton 	}
2399680Slinton     }
2409680Slinton }
2419680Slinton 
2429680Slinton /*
2439680Slinton  * Figure out current source position.
2449680Slinton  */
2459680Slinton 
2469680Slinton public getsrcpos()
2479680Slinton {
2489680Slinton     String filename;
2499680Slinton 
25011105Slinton     curline = srcline(pc);
25111105Slinton     filename = srcfilename(pc);
2529680Slinton     setsource(filename);
25311837Slinton     if (curline != 0) {
25411837Slinton 	cursrcline = curline;
25511837Slinton     }
2569680Slinton }
2579680Slinton 
2589680Slinton /*
2599680Slinton  * Print out the current source position.
2609680Slinton  */
2619680Slinton 
2629680Slinton public printsrcpos()
2639680Slinton {
2649680Slinton     printf("at line %d", curline);
2659680Slinton     if (nlhdr.nfiles > 1) {
2669680Slinton 	printf(" in file \"%s\"", cursource);
2679680Slinton     }
2689680Slinton }
26914337Slinton 
27014337Slinton #define DEF_EDITOR  "vi"
27114337Slinton 
27214337Slinton /*
27314337Slinton  * Invoke an editor on the given file.  Which editor to use might change
27414337Slinton  * installation to installation.  For now, we use "vi".  In any event,
27514337Slinton  * the environment variable "EDITOR" overrides any default.
27614337Slinton  */
27714337Slinton 
27814337Slinton public edit(filename)
27914337Slinton String filename;
28014337Slinton {
28114337Slinton     extern String getenv();
28214337Slinton     String ed, src, s;
28314337Slinton     Symbol f;
28414337Slinton     Address addr;
28514337Slinton     char lineno[10];
28614337Slinton 
28714337Slinton     ed = getenv("EDITOR");
28814337Slinton     if (ed == nil) {
28914337Slinton 	ed = DEF_EDITOR;
29014337Slinton     }
29114337Slinton     src = findsource((filename != nil) ? filename : cursource);
29214337Slinton     if (src == nil) {
29314337Slinton 	f = which(identname(filename, true));
29414337Slinton 	if (not isblock(f)) {
29514337Slinton 	    error("can't read \"%s\"", filename);
29614337Slinton 	}
29714337Slinton 	addr = firstline(f);
29814337Slinton 	if (addr == NOADDR) {
29914337Slinton 	    error("no source for \"%s\"", filename);
30014337Slinton 	}
30114337Slinton 	src = srcfilename(addr);
30214337Slinton 	s = findsource(src);
30314337Slinton 	if (s != nil) {
30414337Slinton 	    src = s;
30514337Slinton 	}
30614337Slinton 	sprintf(lineno, "+%d", srcline(addr));
30714337Slinton     } else {
30814337Slinton 	sprintf(lineno, "+1");
30914337Slinton     }
31014337Slinton     call(ed, stdin, stdout, lineno, src, nil);
31114337Slinton }
312*16637Ssam 
313*16637Ssam #include "re.h"
314*16637Ssam /*
315*16637Ssam  * Search the current file with
316*16637Ssam  * a regular expression.
317*16637Ssam  */
318*16637Ssam public search(forward, re)
319*16637Ssam 	Boolean forward;
320*16637Ssam 	String re;
321*16637Ssam {
322*16637Ssam 	register String p;
323*16637Ssam 	register File f;
324*16637Ssam 	register Lineno line;
325*16637Ssam 	Lineno l1, l2;
326*16637Ssam 	Boolean matched;
327*16637Ssam 	Char buf[512];
328*16637Ssam 
329*16637Ssam 	if (cursource == nil) {
330*16637Ssam 		beginerrmsg();
331*16637Ssam 		fprintf(stderr, "No source file.\n");
332*16637Ssam 		return;
333*16637Ssam 	}
334*16637Ssam 	if (cursource != prevsource)
335*16637Ssam 		skimsource();
336*16637Ssam 	if (lastlinenum == 0) {
337*16637Ssam 		beginerrmsg();
338*16637Ssam 		fprintf(stderr, "Couldn't read \"%s\"\n", cursource);
339*16637Ssam 		return;
340*16637Ssam 	}
341*16637Ssam 	circf = 0;
342*16637Ssam 	if (re != nil && *re != '\0')
343*16637Ssam 		recompile(re);
344*16637Ssam 	matched = false;
345*16637Ssam 	f = srcfp;
346*16637Ssam 	line = cursrcline;
347*16637Ssam 	do {
348*16637Ssam 		if (forward) {
349*16637Ssam 			line++;
350*16637Ssam 			if (line > lastlinenum)
351*16637Ssam 				line = 1;
352*16637Ssam 		} else {
353*16637Ssam 			line--;
354*16637Ssam 			if (line < 1)
355*16637Ssam 				line = lastlinenum;
356*16637Ssam 		}
357*16637Ssam 		fseek(f, srcaddr(line), L_SET);
358*16637Ssam 		for (p = buf; (*p = getc(f)) != '\n'; p++)
359*16637Ssam 			if (*p == EOF)
360*16637Ssam 				error("Unexpected EOF.");
361*16637Ssam 		*p = '\0';
362*16637Ssam 		matched = (Boolean)rematch(buf);
363*16637Ssam 		if (matched)
364*16637Ssam 			break;
365*16637Ssam 	} while (line != cursrcline);
366*16637Ssam 	if (!matched)
367*16637Ssam 		error("No match");
368*16637Ssam #define	WINDOW	10		/* should be used globally */
369*16637Ssam 	l1 = line - WINDOW / 2;
370*16637Ssam 	if (l1 < 1)
371*16637Ssam 		l1 = 1;
372*16637Ssam 	l2 = line + WINDOW / 2;
373*16637Ssam 	if (l2 > lastlinenum)
374*16637Ssam 		l2 = lastlinenum;
375*16637Ssam 	printlines(l1, l2);
376*16637Ssam 	cursrcline = line;	/* override printlines */
377*16637Ssam }
378