1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)source.c 1.9 8/5/83"; 4 5 static char rcsid[] = "$Header: source.c,v 1.3 84/03/27 10:23:58 linton Exp $"; 6 7 /* 8 * Source file management. 9 */ 10 11 #include "defs.h" 12 #include "source.h" 13 #include "object.h" 14 #include "mappings.h" 15 #include "machine.h" 16 17 #ifndef public 18 typedef int Lineno; 19 20 String cursource; 21 Lineno curline; 22 Lineno cursrcline; 23 24 #define LASTLINE 0 /* recognized by printlines */ 25 26 #include "lists.h" 27 28 List sourcepath; 29 #endif 30 31 private Lineno lastlinenum; 32 private String prevsource = nil; 33 34 /* 35 * Data structure for indexing source seek addresses by line number. 36 * 37 * The constraints are: 38 * 39 * we want an array so indexing is fast and easy 40 * we don't want to waste space for small files 41 * we don't want an upper bound on # of lines in a file 42 * we don't know how many lines there are 43 * 44 * The solution is a "dirty" hash table. We have NSLOTS pointers to 45 * arrays of NLINESPERSLOT addresses. To find the source address of 46 * a particular line we find the slot, allocate space if necessary, 47 * and then find its location within the pointed to array. 48 */ 49 50 typedef long Seekaddr; 51 52 #define NSLOTS 20 53 #define NLINESPERSLOT 500 54 55 #define slotno(line) ((line) div NLINESPERSLOT) 56 #define index(line) ((line) mod NLINESPERSLOT) 57 #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) 58 #define srcaddr(line) seektab[slotno(line)][index(line)] 59 60 private File srcfp; 61 private Seekaddr *seektab[NSLOTS]; 62 63 /* 64 * Print out the given lines from the source. 65 */ 66 67 public printlines(l1, l2) 68 Lineno l1, l2; 69 { 70 register int c; 71 register Lineno i, lb, ub; 72 register File f; 73 74 if (cursource == nil) { 75 beginerrmsg(); 76 fprintf(stderr, "no source file\n"); 77 } else { 78 if (cursource != prevsource) { 79 skimsource(); 80 } 81 if (lastlinenum == 0) { 82 beginerrmsg(); 83 fprintf(stderr, "couldn't read \"%s\"\n", cursource); 84 } else { 85 lb = (l1 == 0) ? lastlinenum : l1; 86 ub = (l2 == 0) ? lastlinenum : l2; 87 if (lb < 1) { 88 beginerrmsg(); 89 fprintf(stderr, "line number must be positive\n"); 90 } else if (lb > lastlinenum) { 91 beginerrmsg(); 92 if (lastlinenum == 1) { 93 fprintf(stderr, "\"%s\" has only 1 line\n", cursource); 94 } else { 95 fprintf(stderr, "\"%s\" has only %d lines\n", 96 cursource, lastlinenum); 97 } 98 } else if (ub < lb) { 99 beginerrmsg(); 100 fprintf(stderr, "second number must be greater than first\n"); 101 } else { 102 if (ub > lastlinenum) { 103 ub = lastlinenum; 104 } 105 f = srcfp; 106 fseek(f, srcaddr(lb), 0); 107 for (i = lb; i <= ub; i++) { 108 printf("%5d ", i); 109 while ((c = getc(f)) != '\n') { 110 putchar(c); 111 } 112 putchar('\n'); 113 } 114 cursrcline = ub + 1; 115 } 116 } 117 } 118 } 119 120 /* 121 * Search the sourcepath for a file. 122 */ 123 124 static char fileNameBuf[1024]; 125 126 public String findsource(filename) 127 String filename; 128 { 129 register File f; 130 register String src, dir; 131 132 if (filename[0] == '/') { 133 src = filename; 134 } else { 135 src = nil; 136 foreach (String, dir, sourcepath) 137 sprintf(fileNameBuf, "%s/%s", dir, filename); 138 f = fopen(fileNameBuf, "r"); 139 if (f != nil) { 140 fclose(f); 141 src = fileNameBuf; 142 break; 143 } 144 endfor 145 } 146 return src; 147 } 148 149 /* 150 * Open a source file looking in the appropriate places. 151 */ 152 153 public File opensource(filename) 154 String filename; 155 { 156 String s; 157 File f; 158 159 s = findsource(filename); 160 if (s == nil) { 161 f = nil; 162 } else { 163 f = fopen(s, "r"); 164 } 165 return f; 166 } 167 168 /* 169 * Set the current source file. 170 */ 171 172 public setsource(filename) 173 String filename; 174 { 175 if (filename != nil and filename != cursource) { 176 prevsource = cursource; 177 cursource = filename; 178 cursrcline = 1; 179 } 180 } 181 182 /* 183 * Read the source file getting seek pointers for each line. 184 */ 185 186 private skimsource() 187 { 188 register int c; 189 register Seekaddr count; 190 register File f; 191 register Lineno linenum; 192 register Seekaddr lastaddr; 193 register int slot; 194 195 f = opensource(cursource); 196 if (f == nil) { 197 lastlinenum = 0; 198 } else { 199 if (prevsource != nil) { 200 free_seektab(); 201 if (srcfp != nil) { 202 fclose(srcfp); 203 } 204 } 205 prevsource = cursource; 206 linenum = 0; 207 count = 0; 208 lastaddr = 0; 209 while ((c = getc(f)) != EOF) { 210 ++count; 211 if (c == '\n') { 212 slot = slotno(++linenum); 213 if (slot >= NSLOTS) { 214 panic("skimsource: too many lines"); 215 } 216 if (seektab[slot] == nil) { 217 seektab[slot] = slot_alloc(); 218 } 219 seektab[slot][index(linenum)] = lastaddr; 220 lastaddr = count; 221 } 222 } 223 lastlinenum = linenum; 224 srcfp = f; 225 } 226 } 227 228 /* 229 * Erase information and release space in the current seektab. 230 * This is in preparation for reading in seek pointers for a 231 * new file. It is possible that seek pointers for all files 232 * should be kept around, but the current concern is space. 233 */ 234 235 private free_seektab() 236 { 237 register int slot; 238 239 for (slot = 0; slot < NSLOTS; slot++) { 240 if (seektab[slot] != nil) { 241 dispose(seektab[slot]); 242 } 243 } 244 } 245 246 /* 247 * Figure out current source position. 248 */ 249 250 public getsrcpos() 251 { 252 String filename; 253 254 curline = srcline(pc); 255 filename = srcfilename(pc); 256 setsource(filename); 257 if (curline != 0) { 258 cursrcline = curline; 259 } 260 } 261 262 /* 263 * Print out the current source position. 264 */ 265 266 public printsrcpos() 267 { 268 printf("at line %d", curline); 269 if (nlhdr.nfiles > 1) { 270 printf(" in file \"%s\"", cursource); 271 } 272 } 273 274 #define DEF_EDITOR "vi" 275 276 /* 277 * Invoke an editor on the given file. Which editor to use might change 278 * installation to installation. For now, we use "vi". In any event, 279 * the environment variable "EDITOR" overrides any default. 280 */ 281 282 public edit(filename) 283 String filename; 284 { 285 extern String getenv(); 286 String ed, src, s; 287 Symbol f; 288 Address addr; 289 char lineno[10]; 290 291 ed = getenv("EDITOR"); 292 if (ed == nil) { 293 ed = DEF_EDITOR; 294 } 295 src = findsource((filename != nil) ? filename : cursource); 296 if (src == nil) { 297 f = which(identname(filename, true)); 298 if (not isblock(f)) { 299 error("can't read \"%s\"", filename); 300 } 301 addr = firstline(f); 302 if (addr == NOADDR) { 303 error("no source for \"%s\"", filename); 304 } 305 src = srcfilename(addr); 306 s = findsource(src); 307 if (s != nil) { 308 src = s; 309 } 310 sprintf(lineno, "+%d", srcline(addr)); 311 } else { 312 sprintf(lineno, "+1"); 313 } 314 call(ed, stdin, stdout, lineno, src, nil); 315 } 316