1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)source.c 1.7 04/25/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 foreach (String, dir, sourcepath) 131 sprintf(buf, "%s/%s", dir, filename); 132 f = fopen(buf, "r"); 133 if (f != nil) { 134 break; 135 } 136 endfor 137 return f; 138 } 139 140 /* 141 * Set the current source file. 142 */ 143 144 public setsource(filename) 145 String filename; 146 { 147 if (filename != nil and filename != cursource) { 148 prevsource = cursource; 149 cursource = filename; 150 cursrcline = 1; 151 } 152 } 153 154 /* 155 * Read the source file getting seek pointers for each line. 156 */ 157 158 private skimsource() 159 { 160 register int c; 161 register Seekaddr count; 162 register File f; 163 register Lineno linenum; 164 register Seekaddr lastaddr; 165 register int slot; 166 167 f = opensource(cursource); 168 if (f == nil) { 169 lastlinenum = 0; 170 } else { 171 if (prevsource != nil) { 172 free_seektab(); 173 if (srcfp != nil) { 174 fclose(srcfp); 175 } 176 } 177 prevsource = cursource; 178 linenum = 0; 179 count = 0; 180 lastaddr = 0; 181 while ((c = getc(f)) != EOF) { 182 ++count; 183 if (c == '\n') { 184 slot = slotno(++linenum); 185 if (slot >= NSLOTS) { 186 panic("skimsource: too many lines"); 187 } 188 if (seektab[slot] == nil) { 189 seektab[slot] = slot_alloc(); 190 } 191 seektab[slot][index(linenum)] = lastaddr; 192 lastaddr = count; 193 } 194 } 195 lastlinenum = linenum; 196 srcfp = f; 197 } 198 } 199 200 /* 201 * Erase information and release space in the current seektab. 202 * This is in preparation for reading in seek pointers for a 203 * new file. It is possible that seek pointers for all files 204 * should be kept around, but the current concern is space. 205 */ 206 207 private free_seektab() 208 { 209 register int slot; 210 211 for (slot = 0; slot < NSLOTS; slot++) { 212 if (seektab[slot] != nil) { 213 dispose(seektab[slot]); 214 } 215 } 216 } 217 218 /* 219 * Figure out current source position. 220 */ 221 222 public getsrcpos() 223 { 224 String filename; 225 226 curline = srcline(pc); 227 filename = srcfilename(pc); 228 setsource(filename); 229 if (curline != 0) { 230 cursrcline = curline; 231 } 232 } 233 234 /* 235 * Print out the current source position. 236 */ 237 238 public printsrcpos() 239 { 240 printf("at line %d", curline); 241 if (nlhdr.nfiles > 1) { 242 printf(" in file \"%s\"", cursource); 243 } 244 } 245