1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)source.c 1.8 05/20/83"; 4 5 /* 6 * Source file management. 7 */ 8 9 #include "defs.h" 10 #include "source.h" 11 #include "object.h" 12 #include "mappings.h" 13 #include "machine.h" 14 15 #ifndef public 16 typedef int Lineno; 17 18 String cursource; 19 Lineno curline; 20 Lineno cursrcline; 21 22 #define LASTLINE 0 /* recognized by printlines */ 23 24 #include "lists.h" 25 26 List sourcepath; 27 #endif 28 29 private Lineno lastlinenum; 30 private String prevsource = nil; 31 32 /* 33 * Data structure for indexing source seek addresses by line number. 34 * 35 * The constraints are: 36 * 37 * we want an array so indexing is fast and easy 38 * we don't want to waste space for small files 39 * we don't want an upper bound on # of lines in a file 40 * we don't know how many lines there are 41 * 42 * The solution is a "dirty" hash table. We have NSLOTS pointers to 43 * arrays of NLINESPERSLOT addresses. To find the source address of 44 * a particular line we find the slot, allocate space if necessary, 45 * and then find its location within the pointed to array. 46 */ 47 48 typedef long Seekaddr; 49 50 #define NSLOTS 20 51 #define NLINESPERSLOT 500 52 53 #define slotno(line) ((line) div NLINESPERSLOT) 54 #define index(line) ((line) mod NLINESPERSLOT) 55 #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 56 #define srcaddr(line) seektab[slotno(line)][index(line)] 57 58 private File srcfp; 59 private Seekaddr *seektab[NSLOTS]; 60 61 /* 62 * Print out the given lines from the source. 63 */ 64 65 public printlines(l1, l2) 66 Lineno l1, l2; 67 { 68 register int c; 69 register Lineno i, lb, ub; 70 register File f; 71 72 if (cursource == nil) { 73 beginerrmsg(); 74 fprintf(stderr, "no source file\n"); 75 } else { 76 if (cursource != prevsource) { 77 skimsource(); 78 } 79 if (lastlinenum == 0) { 80 beginerrmsg(); 81 fprintf(stderr, "couldn't read \"%s\"\n", cursource); 82 } else { 83 lb = (l1 == 0) ? lastlinenum : l1; 84 ub = (l2 == 0) ? lastlinenum : l2; 85 if (lb < 1) { 86 beginerrmsg(); 87 fprintf(stderr, "line number must be positive\n"); 88 } else if (lb > lastlinenum) { 89 beginerrmsg(); 90 if (lastlinenum == 1) { 91 fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 92 } else { 93 fprintf(stderr, "\"%s\" has only %d lines\n", 94 cursource, lastlinenum); 95 } 96 } else if (ub < lb) { 97 beginerrmsg(); 98 fprintf(stderr, "second number must be greater than first\n"); 99 } else { 100 if (ub > lastlinenum) { 101 ub = lastlinenum; 102 } 103 f = srcfp; 104 fseek(f, srcaddr(lb), 0); 105 for (i = lb; i <= ub; i++) { 106 printf("%5d ", i); 107 while ((c = getc(f)) != '\n') { 108 putchar(c); 109 } 110 putchar('\n'); 111 } 112 cursrcline = ub + 1; 113 } 114 } 115 } 116 } 117 118 /* 119 * Open a source file looking in the appropriate places. 120 */ 121 122 public File opensource(filename) 123 String filename; 124 { 125 register String dir; 126 char buf[256]; 127 File f; 128 129 f = nil; 130 if (filename[0] == '/') { 131 f = fopen(filename, "r"); 132 } else { 133 foreach (String, dir, sourcepath) 134 sprintf(buf, "%s/%s", dir, filename); 135 f = fopen(buf, "r"); 136 if (f != nil) { 137 break; 138 } 139 endfor 140 } 141 return f; 142 } 143 144 /* 145 * Set the current source file. 146 */ 147 148 public setsource(filename) 149 String filename; 150 { 151 if (filename != nil and filename != cursource) { 152 prevsource = cursource; 153 cursource = filename; 154 cursrcline = 1; 155 } 156 } 157 158 /* 159 * Read the source file getting seek pointers for each line. 160 */ 161 162 private skimsource() 163 { 164 register int c; 165 register Seekaddr count; 166 register File f; 167 register Lineno linenum; 168 register Seekaddr lastaddr; 169 register int slot; 170 171 f = opensource(cursource); 172 if (f == nil) { 173 lastlinenum = 0; 174 } else { 175 if (prevsource != nil) { 176 free_seektab(); 177 if (srcfp != nil) { 178 fclose(srcfp); 179 } 180 } 181 prevsource = cursource; 182 linenum = 0; 183 count = 0; 184 lastaddr = 0; 185 while ((c = getc(f)) != EOF) { 186 ++count; 187 if (c == '\n') { 188 slot = slotno(++linenum); 189 if (slot >= NSLOTS) { 190 panic("skimsource: too many lines"); 191 } 192 if (seektab[slot] == nil) { 193 seektab[slot] = slot_alloc(); 194 } 195 seektab[slot][index(linenum)] = lastaddr; 196 lastaddr = count; 197 } 198 } 199 lastlinenum = linenum; 200 srcfp = f; 201 } 202 } 203 204 /* 205 * Erase information and release space in the current seektab. 206 * This is in preparation for reading in seek pointers for a 207 * new file. It is possible that seek pointers for all files 208 * should be kept around, but the current concern is space. 209 */ 210 211 private free_seektab() 212 { 213 register int slot; 214 215 for (slot = 0; slot < NSLOTS; slot++) { 216 if (seektab[slot] != nil) { 217 dispose(seektab[slot]); 218 } 219 } 220 } 221 222 /* 223 * Figure out current source position. 224 */ 225 226 public getsrcpos() 227 { 228 String filename; 229 230 curline = srcline(pc); 231 filename = srcfilename(pc); 232 setsource(filename); 233 if (curline != 0) { 234 cursrcline = curline; 235 } 236 } 237 238 /* 239 * Print out the current source position. 240 */ 241 242 public printsrcpos() 243 { 244 printf("at line %d", curline); 245 if (nlhdr.nfiles > 1) { 246 printf(" in file \"%s\"", cursource); 247 } 248 } 249