xref: /csrg-svn/old/dbx/source.c (revision 14337)
19680Slinton /* Copyright (c) 1982 Regents of the University of California */
29680Slinton 
3*14337Slinton static char sccsid[] = "@(#)source.c 1.9 08/05/83";
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"
149680Slinton 
159680Slinton #ifndef public
169680Slinton typedef int Lineno;
179680Slinton 
189680Slinton String cursource;
199680Slinton Lineno curline;
209680Slinton Lineno cursrcline;
219680Slinton 
229680Slinton #define LASTLINE 0		/* recognized by printlines */
239680Slinton 
249680Slinton #include "lists.h"
259680Slinton 
269680Slinton List sourcepath;
279680Slinton #endif
289680Slinton 
299680Slinton private Lineno lastlinenum;
309680Slinton private String prevsource = nil;
319680Slinton 
329680Slinton /*
339680Slinton  * Data structure for indexing source seek addresses by line number.
349680Slinton  *
359680Slinton  * The constraints are:
369680Slinton  *
379680Slinton  *  we want an array so indexing is fast and easy
389680Slinton  *  we don't want to waste space for small files
399680Slinton  *  we don't want an upper bound on # of lines in a file
409680Slinton  *  we don't know how many lines there are
419680Slinton  *
429680Slinton  * The solution is a "dirty" hash table.  We have NSLOTS pointers to
439680Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
449680Slinton  * a particular line we find the slot, allocate space if necessary,
459680Slinton  * and then find its location within the pointed to array.
469680Slinton  */
479680Slinton 
4810617Slinton typedef long Seekaddr;
499680Slinton 
509680Slinton #define NSLOTS 20
519680Slinton #define NLINESPERSLOT 500
529680Slinton 
539680Slinton #define slotno(line)    ((line) div NLINESPERSLOT)
549680Slinton #define index(line)	((line) mod NLINESPERSLOT)
559680Slinton #define slot_alloc()    newarr(Seekaddr, NLINESPERSLOT)
569680Slinton #define srcaddr(line)	seektab[slotno(line)][index(line)]
579680Slinton 
589680Slinton private File srcfp;
599680Slinton private Seekaddr *seektab[NSLOTS];
609680Slinton 
619680Slinton /*
629680Slinton  * Print out the given lines from the source.
639680Slinton  */
649680Slinton 
659680Slinton public printlines(l1, l2)
669680Slinton Lineno l1, l2;
679680Slinton {
689680Slinton     register int c;
699680Slinton     register Lineno i, lb, ub;
709680Slinton     register File f;
719680Slinton 
729680Slinton     if (cursource == nil) {
739680Slinton 	beginerrmsg();
749680Slinton 	fprintf(stderr, "no source file\n");
759680Slinton     } else {
769680Slinton 	if (cursource != prevsource) {
779680Slinton 	    skimsource();
789680Slinton 	}
799680Slinton 	if (lastlinenum == 0) {
809680Slinton 	    beginerrmsg();
819680Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
829680Slinton 	} else {
839680Slinton 	    lb = (l1 == 0) ? lastlinenum : l1;
849680Slinton 	    ub = (l2 == 0) ? lastlinenum : l2;
859680Slinton 	    if (lb < 1) {
869680Slinton 		beginerrmsg();
879680Slinton 		fprintf(stderr, "line number must be positive\n");
889680Slinton 	    } else if (lb > lastlinenum) {
899680Slinton 		beginerrmsg();
909680Slinton 		if (lastlinenum == 1) {
919680Slinton 		    fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
929680Slinton 		} else {
939680Slinton 		    fprintf(stderr, "\"%s\" has only %d lines\n",
949680Slinton 			cursource, lastlinenum);
959680Slinton 		}
969680Slinton 	    } else if (ub < lb) {
979680Slinton 		beginerrmsg();
989680Slinton 		fprintf(stderr, "second number must be greater than first\n");
999680Slinton 	    } else {
1009680Slinton 		if (ub > lastlinenum) {
1019680Slinton 		    ub = lastlinenum;
1029680Slinton 		}
1039680Slinton 		f = srcfp;
10410617Slinton 		fseek(f, srcaddr(lb), 0);
1059680Slinton 		for (i = lb; i <= ub; i++) {
1069680Slinton 		    printf("%5d   ", i);
1079680Slinton 		    while ((c = getc(f)) != '\n') {
1089680Slinton 			putchar(c);
1099680Slinton 		    }
1109680Slinton 		    putchar('\n');
1119680Slinton 		}
1129680Slinton 		cursrcline = ub + 1;
1139680Slinton 	    }
1149680Slinton 	}
1159680Slinton     }
1169680Slinton }
1179680Slinton 
1189680Slinton /*
119*14337Slinton  * Search the sourcepath for a file.
1209680Slinton  */
1219680Slinton 
122*14337Slinton static char fileNameBuf[1024];
123*14337Slinton 
124*14337Slinton public String findsource(filename)
1259680Slinton String filename;
1269680Slinton {
127*14337Slinton     register File f;
128*14337Slinton     register String src, dir;
1299680Slinton 
13012608Slinton     if (filename[0] == '/') {
131*14337Slinton 	src = filename;
13212608Slinton     } else {
133*14337Slinton 	src = nil;
13412608Slinton 	foreach (String, dir, sourcepath)
135*14337Slinton 	    sprintf(fileNameBuf, "%s/%s", dir, filename);
136*14337Slinton 	    f = fopen(fileNameBuf, "r");
13712608Slinton 	    if (f != nil) {
138*14337Slinton 		fclose(f);
139*14337Slinton 		src = fileNameBuf;
14012608Slinton 		break;
141*14337Slinton 	    }
14212608Slinton 	endfor
14312608Slinton     }
144*14337Slinton     return src;
145*14337Slinton }
146*14337Slinton 
147*14337Slinton /*
148*14337Slinton  * Open a source file looking in the appropriate places.
149*14337Slinton  */
150*14337Slinton 
151*14337Slinton public File opensource(filename)
152*14337Slinton String filename;
153*14337Slinton {
154*14337Slinton     String s;
155*14337Slinton     File f;
156*14337Slinton 
157*14337Slinton     s = findsource(filename);
158*14337Slinton     if (s == nil) {
159*14337Slinton 	f = nil;
160*14337Slinton     } else {
161*14337Slinton 	f = fopen(s, "r");
162*14337Slinton     }
1639680Slinton     return f;
1649680Slinton }
1659680Slinton 
1669680Slinton /*
1679680Slinton  * Set the current source file.
1689680Slinton  */
1699680Slinton 
1709680Slinton public setsource(filename)
1719680Slinton String filename;
1729680Slinton {
1739680Slinton     if (filename != nil and filename != cursource) {
1749680Slinton 	prevsource = cursource;
1759680Slinton 	cursource = filename;
1769680Slinton 	cursrcline = 1;
1779680Slinton     }
1789680Slinton }
1799680Slinton 
1809680Slinton /*
1819680Slinton  * Read the source file getting seek pointers for each line.
1829680Slinton  */
1839680Slinton 
1849680Slinton private skimsource()
1859680Slinton {
1869680Slinton     register int c;
18710617Slinton     register Seekaddr count;
1889680Slinton     register File f;
1899680Slinton     register Lineno linenum;
1909680Slinton     register Seekaddr lastaddr;
1919680Slinton     register int slot;
1929680Slinton 
1939680Slinton     f = opensource(cursource);
1949680Slinton     if (f == nil) {
1959680Slinton 	lastlinenum = 0;
1969680Slinton     } else {
1979680Slinton 	if (prevsource != nil) {
1989680Slinton 	    free_seektab();
1999680Slinton 	    if (srcfp != nil) {
2009680Slinton 		fclose(srcfp);
2019680Slinton 	    }
2029680Slinton 	}
2039680Slinton 	prevsource = cursource;
2049680Slinton 	linenum = 0;
2059680Slinton 	count = 0;
2069680Slinton 	lastaddr = 0;
2079680Slinton 	while ((c = getc(f)) != EOF) {
2089680Slinton 	    ++count;
2099680Slinton 	    if (c == '\n') {
2109680Slinton 		slot = slotno(++linenum);
2119680Slinton 		if (slot >= NSLOTS) {
2129680Slinton 		    panic("skimsource: too many lines");
2139680Slinton 		}
2149680Slinton 		if (seektab[slot] == nil) {
2159680Slinton 		    seektab[slot] = slot_alloc();
2169680Slinton 		}
2179680Slinton 		seektab[slot][index(linenum)] = lastaddr;
2189680Slinton 		lastaddr = count;
2199680Slinton 	    }
2209680Slinton 	}
2219680Slinton 	lastlinenum = linenum;
2229680Slinton 	srcfp = f;
2239680Slinton     }
2249680Slinton }
2259680Slinton 
2269680Slinton /*
2279680Slinton  * Erase information and release space in the current seektab.
2289680Slinton  * This is in preparation for reading in seek pointers for a
2299680Slinton  * new file.  It is possible that seek pointers for all files
2309680Slinton  * should be kept around, but the current concern is space.
2319680Slinton  */
2329680Slinton 
2339680Slinton private free_seektab()
2349680Slinton {
2359680Slinton     register int slot;
2369680Slinton 
2379680Slinton     for (slot = 0; slot < NSLOTS; slot++) {
2389680Slinton 	if (seektab[slot] != nil) {
2399680Slinton 	    dispose(seektab[slot]);
2409680Slinton 	}
2419680Slinton     }
2429680Slinton }
2439680Slinton 
2449680Slinton /*
2459680Slinton  * Figure out current source position.
2469680Slinton  */
2479680Slinton 
2489680Slinton public getsrcpos()
2499680Slinton {
2509680Slinton     String filename;
2519680Slinton 
25211105Slinton     curline = srcline(pc);
25311105Slinton     filename = srcfilename(pc);
2549680Slinton     setsource(filename);
25511837Slinton     if (curline != 0) {
25611837Slinton 	cursrcline = curline;
25711837Slinton     }
2589680Slinton }
2599680Slinton 
2609680Slinton /*
2619680Slinton  * Print out the current source position.
2629680Slinton  */
2639680Slinton 
2649680Slinton public printsrcpos()
2659680Slinton {
2669680Slinton     printf("at line %d", curline);
2679680Slinton     if (nlhdr.nfiles > 1) {
2689680Slinton 	printf(" in file \"%s\"", cursource);
2699680Slinton     }
2709680Slinton }
271*14337Slinton 
272*14337Slinton #define DEF_EDITOR  "vi"
273*14337Slinton 
274*14337Slinton /*
275*14337Slinton  * Invoke an editor on the given file.  Which editor to use might change
276*14337Slinton  * installation to installation.  For now, we use "vi".  In any event,
277*14337Slinton  * the environment variable "EDITOR" overrides any default.
278*14337Slinton  */
279*14337Slinton 
280*14337Slinton public edit(filename)
281*14337Slinton String filename;
282*14337Slinton {
283*14337Slinton     extern String getenv();
284*14337Slinton     String ed, src, s;
285*14337Slinton     Symbol f;
286*14337Slinton     Address addr;
287*14337Slinton     char lineno[10];
288*14337Slinton 
289*14337Slinton     ed = getenv("EDITOR");
290*14337Slinton     if (ed == nil) {
291*14337Slinton 	ed = DEF_EDITOR;
292*14337Slinton     }
293*14337Slinton     src = findsource((filename != nil) ? filename : cursource);
294*14337Slinton     if (src == nil) {
295*14337Slinton 	f = which(identname(filename, true));
296*14337Slinton 	if (not isblock(f)) {
297*14337Slinton 	    error("can't read \"%s\"", filename);
298*14337Slinton 	}
299*14337Slinton 	addr = firstline(f);
300*14337Slinton 	if (addr == NOADDR) {
301*14337Slinton 	    error("no source for \"%s\"", filename);
302*14337Slinton 	}
303*14337Slinton 	src = srcfilename(addr);
304*14337Slinton 	s = findsource(src);
305*14337Slinton 	if (s != nil) {
306*14337Slinton 	    src = s;
307*14337Slinton 	}
308*14337Slinton 	sprintf(lineno, "+%d", srcline(addr));
309*14337Slinton     } else {
310*14337Slinton 	sprintf(lineno, "+1");
311*14337Slinton     }
312*14337Slinton     call(ed, stdin, stdout, lineno, src, nil);
313*14337Slinton }
314