/* Copyright (c) 1982 Regents of the University of California */
static char sccsid
[] = "@(#)source.c 1.12 (Berkeley) %G%";
static char rcsid
[] = "$Header: source.c,v 1.4 84/06/07 16:29:38 linton Exp $";
* Source file management.
#define LASTLINE 0 /* recognized by printlines */
private Lineno lastlinenum
;
private String prevsource
= nil
;
* Data structure for indexing source seek addresses by line number.
* we want an array so indexing is fast and easy
* we don't want to waste space for small files
* we don't want an upper bound on # of lines in a file
* we don't know how many lines there are
* The solution is a "dirty" hash table. We have NSLOTS pointers to
* arrays of NLINESPERSLOT addresses. To find the source address of
* a particular line we find the slot, allocate space if necessary,
* and then find its location within the pointed to array.
#define NLINESPERSLOT 500
#define slotno(line) ((line) div NLINESPERSLOT)
#define index(line) ((line) mod NLINESPERSLOT)
#define slot_alloc() newarr(Seekaddr, NLINESPERSLOT)
#define srcaddr(line) seektab[slotno(line)][index(line)]
private Seekaddr
*seektab
[NSLOTS
];
* Determine if the current source file is available.
public boolean
canReadSource ()
} else if (cursource
!= prevsource
) {
b
= (boolean
) (lastlinenum
!= 0);
* Print out the given lines from the source.
public printlines(l1
, l2
)
register Lineno i
, lb
, ub
;
fprintf(stderr
, "no source file\n");
if (cursource
!= prevsource
) {
fprintf(stderr
, "couldn't read \"%s\"\n", cursource
);
lb
= (l1
== LASTLINE
) ? lastlinenum
: l1
;
ub
= (l2
== LASTLINE
) ? lastlinenum
: l2
;
fprintf(stderr
, "line number must be positive\n");
} else if (lb
> lastlinenum
) {
fprintf(stderr
, "\"%s\" has only 1 line\n", cursource
);
fprintf(stderr
, "\"%s\" has only %d lines\n",
fprintf(stderr
, "second number must be greater than first\n");
fseek(f
, srcaddr(lb
), 0);
for (i
= lb
; i
<= ub
; i
++) {
while ((c
= getc(f
)) != '\n') {
* Search the sourcepath for a file.
static char fileNameBuf
[1024];
public String
findsource(filename
)
register String src
, dir
;
if (filename
[0] == '/') {
foreach (String
, dir
, sourcepath
)
sprintf(fileNameBuf
, "%s/%s", dir
, filename
);
if (access(fileNameBuf
, R_OK
) == 0) {
* Open a source file looking in the appropriate places.
public File
opensource(filename
)
s
= findsource(filename
);
* Set the current source file.
public setsource(filename
)
if (filename
!= nil
and filename
!= cursource
) {
* Read the source file getting seek pointers for each line.
register Seekaddr lastaddr
;
f
= opensource(cursource
);
while ((c
= getc(f
)) != EOF
) {
slot
= slotno(++linenum
);
panic("skimsource: too many lines");
if (seektab
[slot
] == nil
) {
seektab
[slot
] = slot_alloc();
seektab
[slot
][index(linenum
)] = lastaddr
;
* Erase information and release space in the current seektab.
* This is in preparation for reading in seek pointers for a
* new file. It is possible that seek pointers for all files
* should be kept around, but the current concern is space.
for (slot
= 0; slot
< NSLOTS
; slot
++) {
if (seektab
[slot
] != nil
) {
* Figure out current source position.
filename
= srcfilename(pc
);
* Print out the current source position.
printf("at line %d", curline
);
printf(" in file \"%s\"", cursource
);
* Invoke an editor on the given file. Which editor to use might change
* installation to installation. For now, we use "vi". In any event,
* the environment variable "EDITOR" overrides any default.
src
= findsource((filename
!= nil
) ? filename
: cursource
);
f
= which(identname(filename
, true));
error("can't read \"%s\"", filename
);
error("no source for \"%s\"", filename
);
sprintf(lineno
, "+%d", srcline(addr
));
if (streq(ed
, "vi") or streq(ed
, "ex")) {
call(ed
, stdin
, stdout
, lineno
, src
, nil
);
call(ed
, stdin
, stdout
, src
, nil
);
* Strip away portions of a given pattern not part of the regular expression.
private String
getpattern (pattern
)
while (*p
== ' ' or *p
== '\t') {
* Search the current file for a regular expression.
public search (direction
, pattern
)
fprintf(stderr
, "no source file\n");
if (cursource
!= prevsource
) {
fprintf(stderr
, "couldn't read \"%s\"\n", cursource
);
re
= getpattern(pattern
);
if (re
!= nil
and *re
!= '\0') {
if (line
> lastlinenum
) {
fseek(f
, srcaddr(line
), L_SET
);
while ((*p
!= '\n') and (*p
!= EOF
)) {
matched
= (boolean
) re_exec(buf
);
} while (not matched
and line
!= cursrcline
);
fprintf(stderr
, "no match\n");
* Compute a small window around the given line.
public getsrcwindow (line
, l1
, l2
)
s
= findvar(identname("$listwindow", true));
*l1
= line
- (size div
2);
if (lastlinenum
!= LASTLINE
and *l2
> lastlinenum
) {