/* Copyright (c) 1982 Regents of the University of California */
static char sccsid
[] = "@(#)source.c 1.4 %G%";
* 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
];
* 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
== 0) ? lastlinenum
: l1
;
ub
= (l2
== 0) ? 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') {
* Open a source file looking in the appropriate places.
public File
opensource(filename
)
foreach (String
, dir
, sourcepath
)
sprintf(buf
, "%s/%s", dir
, 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.
* Have to use "pc - 1" because pc is the address of the next instruction
* rather than the current one.
curline
= srcline(pc
- 1);
filename
= srcfilename(pc
- 1);
* Print out the current source position.
printf("at line %d", curline
);
printf(" in file \"%s\"", cursource
);