xref: /csrg-svn/old/dbx/source.c (revision 18233)
19680Slinton /* Copyright (c) 1982 Regents of the University of California */
29680Slinton 
3*18233Slinton static	char sccsid[] = "@(#)source.c	1.12 (Berkeley) 03/01/85";
49680Slinton 
5*18233Slinton static char rcsid[] = "$Header: source.c,v 1.4 84/06/07 16:29:38 linton Exp $";
6*18233Slinton 
79680Slinton /*
89680Slinton  * Source file management.
99680Slinton  */
109680Slinton 
119680Slinton #include "defs.h"
129680Slinton #include "source.h"
139680Slinton #include "object.h"
149680Slinton #include "mappings.h"
159680Slinton #include "machine.h"
16*18233Slinton #include "keywords.h"
17*18233Slinton #include "tree.h"
18*18233Slinton #include "eval.h"
1916637Ssam #include <sys/file.h>
209680Slinton 
219680Slinton #ifndef public
229680Slinton typedef int Lineno;
239680Slinton 
249680Slinton String cursource;
259680Slinton Lineno curline;
269680Slinton Lineno cursrcline;
279680Slinton 
289680Slinton #define LASTLINE 0		/* recognized by printlines */
299680Slinton 
309680Slinton #include "lists.h"
319680Slinton 
329680Slinton List sourcepath;
339680Slinton #endif
349680Slinton 
35*18233Slinton extern char *re_comp();
36*18233Slinton 
379680Slinton private Lineno lastlinenum;
389680Slinton private String prevsource = nil;
399680Slinton 
409680Slinton /*
419680Slinton  * Data structure for indexing source seek addresses by line number.
429680Slinton  *
439680Slinton  * The constraints are:
449680Slinton  *
459680Slinton  *  we want an array so indexing is fast and easy
469680Slinton  *  we don't want to waste space for small files
479680Slinton  *  we don't want an upper bound on # of lines in a file
489680Slinton  *  we don't know how many lines there are
499680Slinton  *
509680Slinton  * The solution is a "dirty" hash table.  We have NSLOTS pointers to
519680Slinton  * arrays of NLINESPERSLOT addresses.  To find the source address of
529680Slinton  * a particular line we find the slot, allocate space if necessary,
539680Slinton  * and then find its location within the pointed to array.
549680Slinton  */
559680Slinton 
5610617Slinton typedef long Seekaddr;
579680Slinton 
58*18233Slinton #define NSLOTS 40
599680Slinton #define NLINESPERSLOT 500
609680Slinton 
619680Slinton #define slotno(line)    ((line) div NLINESPERSLOT)
629680Slinton #define index(line)	((line) mod NLINESPERSLOT)
639680Slinton #define slot_alloc()    newarr(Seekaddr, NLINESPERSLOT)
649680Slinton #define srcaddr(line)	seektab[slotno(line)][index(line)]
659680Slinton 
669680Slinton private File srcfp;
679680Slinton private Seekaddr *seektab[NSLOTS];
689680Slinton 
699680Slinton /*
70*18233Slinton  * Determine if the current source file is available.
71*18233Slinton  */
72*18233Slinton 
73*18233Slinton public boolean canReadSource ()
74*18233Slinton {
75*18233Slinton     boolean b;
76*18233Slinton 
77*18233Slinton     if (cursource == nil) {
78*18233Slinton 	b = false;
79*18233Slinton     } else if (cursource != prevsource) {
80*18233Slinton 	skimsource();
81*18233Slinton 	b = (boolean) (lastlinenum != 0);
82*18233Slinton     } else {
83*18233Slinton 	b = true;
84*18233Slinton     }
85*18233Slinton     return b;
86*18233Slinton }
87*18233Slinton 
88*18233Slinton /*
899680Slinton  * Print out the given lines from the source.
909680Slinton  */
919680Slinton 
929680Slinton public printlines(l1, l2)
939680Slinton Lineno l1, l2;
949680Slinton {
959680Slinton     register int c;
969680Slinton     register Lineno i, lb, ub;
979680Slinton     register File f;
989680Slinton 
999680Slinton     if (cursource == nil) {
1009680Slinton 	beginerrmsg();
1019680Slinton 	fprintf(stderr, "no source file\n");
1029680Slinton     } else {
1039680Slinton 	if (cursource != prevsource) {
1049680Slinton 	    skimsource();
1059680Slinton 	}
1069680Slinton 	if (lastlinenum == 0) {
1079680Slinton 	    beginerrmsg();
1089680Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
1099680Slinton 	} else {
110*18233Slinton 	    lb = (l1 == LASTLINE) ? lastlinenum : l1;
111*18233Slinton 	    ub = (l2 == LASTLINE) ? lastlinenum : l2;
1129680Slinton 	    if (lb < 1) {
1139680Slinton 		beginerrmsg();
1149680Slinton 		fprintf(stderr, "line number must be positive\n");
1159680Slinton 	    } else if (lb > lastlinenum) {
1169680Slinton 		beginerrmsg();
1179680Slinton 		if (lastlinenum == 1) {
1189680Slinton 		    fprintf(stderr, "\"%s\" has only 1 line\n", cursource);
1199680Slinton 		} else {
1209680Slinton 		    fprintf(stderr, "\"%s\" has only %d lines\n",
1219680Slinton 			cursource, lastlinenum);
1229680Slinton 		}
1239680Slinton 	    } else if (ub < lb) {
1249680Slinton 		beginerrmsg();
1259680Slinton 		fprintf(stderr, "second number must be greater than first\n");
1269680Slinton 	    } else {
1279680Slinton 		if (ub > lastlinenum) {
1289680Slinton 		    ub = lastlinenum;
1299680Slinton 		}
1309680Slinton 		f = srcfp;
13110617Slinton 		fseek(f, srcaddr(lb), 0);
1329680Slinton 		for (i = lb; i <= ub; i++) {
1339680Slinton 		    printf("%5d   ", i);
1349680Slinton 		    while ((c = getc(f)) != '\n') {
1359680Slinton 			putchar(c);
1369680Slinton 		    }
1379680Slinton 		    putchar('\n');
1389680Slinton 		}
1399680Slinton 		cursrcline = ub + 1;
1409680Slinton 	    }
1419680Slinton 	}
1429680Slinton     }
1439680Slinton }
1449680Slinton 
1459680Slinton /*
14614337Slinton  * Search the sourcepath for a file.
1479680Slinton  */
1489680Slinton 
14914337Slinton static char fileNameBuf[1024];
15014337Slinton 
15114337Slinton public String findsource(filename)
1529680Slinton String filename;
1539680Slinton {
15414337Slinton     register String src, dir;
1559680Slinton 
15612608Slinton     if (filename[0] == '/') {
15714337Slinton 	src = filename;
15812608Slinton     } else {
15914337Slinton 	src = nil;
16012608Slinton 	foreach (String, dir, sourcepath)
16114337Slinton 	    sprintf(fileNameBuf, "%s/%s", dir, filename);
16216637Ssam 	    if (access(fileNameBuf, R_OK) == 0) {
16314337Slinton 		src = fileNameBuf;
16412608Slinton 		break;
16514337Slinton 	    }
16612608Slinton 	endfor
16712608Slinton     }
16814337Slinton     return src;
16914337Slinton }
17014337Slinton 
17114337Slinton /*
17214337Slinton  * Open a source file looking in the appropriate places.
17314337Slinton  */
17414337Slinton 
17514337Slinton public File opensource(filename)
17614337Slinton String filename;
17714337Slinton {
17814337Slinton     String s;
17914337Slinton     File f;
18014337Slinton 
18114337Slinton     s = findsource(filename);
18214337Slinton     if (s == nil) {
18314337Slinton 	f = nil;
18414337Slinton     } else {
18514337Slinton 	f = fopen(s, "r");
18614337Slinton     }
1879680Slinton     return f;
1889680Slinton }
1899680Slinton 
1909680Slinton /*
1919680Slinton  * Set the current source file.
1929680Slinton  */
1939680Slinton 
1949680Slinton public setsource(filename)
1959680Slinton String filename;
1969680Slinton {
1979680Slinton     if (filename != nil and filename != cursource) {
1989680Slinton 	prevsource = cursource;
1999680Slinton 	cursource = filename;
2009680Slinton 	cursrcline = 1;
2019680Slinton     }
2029680Slinton }
2039680Slinton 
2049680Slinton /*
2059680Slinton  * Read the source file getting seek pointers for each line.
2069680Slinton  */
2079680Slinton 
2089680Slinton private skimsource()
2099680Slinton {
2109680Slinton     register int c;
21110617Slinton     register Seekaddr count;
2129680Slinton     register File f;
2139680Slinton     register Lineno linenum;
2149680Slinton     register Seekaddr lastaddr;
2159680Slinton     register int slot;
2169680Slinton 
2179680Slinton     f = opensource(cursource);
2189680Slinton     if (f == nil) {
2199680Slinton 	lastlinenum = 0;
2209680Slinton     } else {
2219680Slinton 	if (prevsource != nil) {
2229680Slinton 	    free_seektab();
2239680Slinton 	    if (srcfp != nil) {
2249680Slinton 		fclose(srcfp);
2259680Slinton 	    }
2269680Slinton 	}
2279680Slinton 	prevsource = cursource;
2289680Slinton 	linenum = 0;
2299680Slinton 	count = 0;
2309680Slinton 	lastaddr = 0;
2319680Slinton 	while ((c = getc(f)) != EOF) {
2329680Slinton 	    ++count;
2339680Slinton 	    if (c == '\n') {
2349680Slinton 		slot = slotno(++linenum);
2359680Slinton 		if (slot >= NSLOTS) {
2369680Slinton 		    panic("skimsource: too many lines");
2379680Slinton 		}
2389680Slinton 		if (seektab[slot] == nil) {
2399680Slinton 		    seektab[slot] = slot_alloc();
2409680Slinton 		}
2419680Slinton 		seektab[slot][index(linenum)] = lastaddr;
2429680Slinton 		lastaddr = count;
2439680Slinton 	    }
2449680Slinton 	}
2459680Slinton 	lastlinenum = linenum;
2469680Slinton 	srcfp = f;
2479680Slinton     }
2489680Slinton }
2499680Slinton 
2509680Slinton /*
2519680Slinton  * Erase information and release space in the current seektab.
2529680Slinton  * This is in preparation for reading in seek pointers for a
2539680Slinton  * new file.  It is possible that seek pointers for all files
2549680Slinton  * should be kept around, but the current concern is space.
2559680Slinton  */
2569680Slinton 
2579680Slinton private free_seektab()
2589680Slinton {
2599680Slinton     register int slot;
2609680Slinton 
2619680Slinton     for (slot = 0; slot < NSLOTS; slot++) {
2629680Slinton 	if (seektab[slot] != nil) {
2639680Slinton 	    dispose(seektab[slot]);
2649680Slinton 	}
2659680Slinton     }
2669680Slinton }
2679680Slinton 
2689680Slinton /*
2699680Slinton  * Figure out current source position.
2709680Slinton  */
2719680Slinton 
2729680Slinton public getsrcpos()
2739680Slinton {
2749680Slinton     String filename;
2759680Slinton 
27611105Slinton     curline = srcline(pc);
27711105Slinton     filename = srcfilename(pc);
2789680Slinton     setsource(filename);
27911837Slinton     if (curline != 0) {
28011837Slinton 	cursrcline = curline;
28111837Slinton     }
2829680Slinton }
2839680Slinton 
2849680Slinton /*
2859680Slinton  * Print out the current source position.
2869680Slinton  */
2879680Slinton 
2889680Slinton public printsrcpos()
2899680Slinton {
2909680Slinton     printf("at line %d", curline);
2919680Slinton     if (nlhdr.nfiles > 1) {
2929680Slinton 	printf(" in file \"%s\"", cursource);
2939680Slinton     }
2949680Slinton }
29514337Slinton 
29614337Slinton #define DEF_EDITOR  "vi"
29714337Slinton 
29814337Slinton /*
29914337Slinton  * Invoke an editor on the given file.  Which editor to use might change
30014337Slinton  * installation to installation.  For now, we use "vi".  In any event,
30114337Slinton  * the environment variable "EDITOR" overrides any default.
30214337Slinton  */
30314337Slinton 
30414337Slinton public edit(filename)
30514337Slinton String filename;
30614337Slinton {
30714337Slinton     extern String getenv();
30814337Slinton     String ed, src, s;
30914337Slinton     Symbol f;
31014337Slinton     Address addr;
31114337Slinton     char lineno[10];
31214337Slinton 
31314337Slinton     ed = getenv("EDITOR");
31414337Slinton     if (ed == nil) {
31514337Slinton 	ed = DEF_EDITOR;
31614337Slinton     }
31714337Slinton     src = findsource((filename != nil) ? filename : cursource);
31814337Slinton     if (src == nil) {
31914337Slinton 	f = which(identname(filename, true));
32014337Slinton 	if (not isblock(f)) {
32114337Slinton 	    error("can't read \"%s\"", filename);
32214337Slinton 	}
32314337Slinton 	addr = firstline(f);
32414337Slinton 	if (addr == NOADDR) {
32514337Slinton 	    error("no source for \"%s\"", filename);
32614337Slinton 	}
32714337Slinton 	src = srcfilename(addr);
32814337Slinton 	s = findsource(src);
32914337Slinton 	if (s != nil) {
33014337Slinton 	    src = s;
33114337Slinton 	}
33214337Slinton 	sprintf(lineno, "+%d", srcline(addr));
33314337Slinton     } else {
33414337Slinton 	sprintf(lineno, "+1");
33514337Slinton     }
336*18233Slinton     if (streq(ed, "vi") or streq(ed, "ex")) {
337*18233Slinton 	call(ed, stdin, stdout, lineno, src, nil);
338*18233Slinton     } else {
339*18233Slinton 	call(ed, stdin, stdout, src, nil);
340*18233Slinton     }
34114337Slinton }
34216637Ssam 
34316637Ssam /*
344*18233Slinton  * Strip away portions of a given pattern not part of the regular expression.
34516637Ssam  */
346*18233Slinton 
347*18233Slinton private String getpattern (pattern)
348*18233Slinton String pattern;
34916637Ssam {
350*18233Slinton     register char *p, *r;
351*18233Slinton 
352*18233Slinton     p = pattern;
353*18233Slinton     while (*p == ' ' or *p == '\t') {
354*18233Slinton 	++p;
355*18233Slinton     }
356*18233Slinton     r = p;
357*18233Slinton     while (*p != '\0') {
358*18233Slinton 	++p;
359*18233Slinton     }
360*18233Slinton     --p;
361*18233Slinton     if (*p == '\n') {
362*18233Slinton 	*p = '\0';
363*18233Slinton 	--p;
364*18233Slinton     }
365*18233Slinton     if (*p == *r) {
366*18233Slinton 	*p = '\0';
367*18233Slinton 	--p;
368*18233Slinton     }
369*18233Slinton     return r + 1;
370*18233Slinton }
371*18233Slinton 
372*18233Slinton /*
373*18233Slinton  * Search the current file for a regular expression.
374*18233Slinton  */
375*18233Slinton 
376*18233Slinton public search (direction, pattern)
377*18233Slinton char direction;
378*18233Slinton String pattern;
379*18233Slinton {
380*18233Slinton     register String p;
381*18233Slinton     register File f;
382*18233Slinton     String re, err;
383*18233Slinton     Lineno line;
384*18233Slinton     boolean matched;
385*18233Slinton     char buf[512];
386*18233Slinton 
387*18233Slinton     if (cursource == nil) {
388*18233Slinton 	beginerrmsg();
389*18233Slinton 	fprintf(stderr, "no source file\n");
390*18233Slinton     } else {
391*18233Slinton 	if (cursource != prevsource) {
392*18233Slinton 	    skimsource();
39316637Ssam 	}
39416637Ssam 	if (lastlinenum == 0) {
395*18233Slinton 	    beginerrmsg();
396*18233Slinton 	    fprintf(stderr, "couldn't read \"%s\"\n", cursource);
397*18233Slinton 	} else {
398*18233Slinton 	    re = getpattern(pattern);
399*18233Slinton 	    /* circf = 0; */
400*18233Slinton 	    if (re != nil and *re != '\0') {
401*18233Slinton 		err = re_comp(re);
402*18233Slinton 		if (err != nil) {
403*18233Slinton 		    error(err);
404*18233Slinton 		}
405*18233Slinton 	    }
406*18233Slinton 	    matched = false;
407*18233Slinton 	    f = srcfp;
408*18233Slinton 	    line = cursrcline;
409*18233Slinton 	    do {
410*18233Slinton 		if (direction == '/') {
411*18233Slinton 		    ++line;
412*18233Slinton 		    if (line > lastlinenum) {
413*18233Slinton 			line = 1;
414*18233Slinton 		    }
41516637Ssam 		} else {
416*18233Slinton 		    --line;
417*18233Slinton 		    if (line < 1) {
418*18233Slinton 			line = lastlinenum;
419*18233Slinton 		    }
42016637Ssam 		}
42116637Ssam 		fseek(f, srcaddr(line), L_SET);
422*18233Slinton 		p = buf;
423*18233Slinton 		*p = getc(f);
424*18233Slinton 		while ((*p != '\n') and (*p != EOF)) {
425*18233Slinton 		    ++p;
426*18233Slinton 		    *p = getc(f);
427*18233Slinton 		}
42816637Ssam 		*p = '\0';
429*18233Slinton 		matched = (boolean) re_exec(buf);
430*18233Slinton 	    } while (not matched and line != cursrcline);
431*18233Slinton 	    if (not matched) {
432*18233Slinton 		beginerrmsg();
433*18233Slinton 		fprintf(stderr, "no match\n");
434*18233Slinton 	    } else {
435*18233Slinton 		printlines(line, line);
436*18233Slinton 		cursrcline = line;
437*18233Slinton 	    }
438*18233Slinton 	}
439*18233Slinton     }
44016637Ssam }
441*18233Slinton 
442*18233Slinton /*
443*18233Slinton  * Compute a small window around the given line.
444*18233Slinton  */
445*18233Slinton 
446*18233Slinton public getsrcwindow (line, l1, l2)
447*18233Slinton Lineno line, *l1, *l2;
448*18233Slinton {
449*18233Slinton     Node s;
450*18233Slinton     integer size;
451*18233Slinton 
452*18233Slinton     s = findvar(identname("$listwindow", true));
453*18233Slinton     if (s == nil) {
454*18233Slinton 	size = 10;
455*18233Slinton     } else {
456*18233Slinton 	eval(s);
457*18233Slinton 	size = pop(integer);
458*18233Slinton     }
459*18233Slinton     *l1 = line - (size div 2);
460*18233Slinton     if (*l1 < 1) {
461*18233Slinton 	*l1 = 1;
462*18233Slinton     }
463*18233Slinton     *l2 = *l1 + size;
464*18233Slinton     if (lastlinenum != LASTLINE and *l2 > lastlinenum) {
465*18233Slinton 	*l2 = lastlinenum;
466*18233Slinton     }
467*18233Slinton }
468