|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)source.c 5.1 (Berkeley) 5/31/85"; ! 9: #endif not lint ! 10: ! 11: static char rcsid[] = "$Header: source.c,v 1.4 84/06/07 16:29:38 linton Exp $"; ! 12: ! 13: /* ! 14: * Source file management. ! 15: */ ! 16: ! 17: #include "defs.h" ! 18: #include "source.h" ! 19: #include "object.h" ! 20: #include "mappings.h" ! 21: #include "machine.h" ! 22: #include "keywords.h" ! 23: #include "tree.h" ! 24: #include "eval.h" ! 25: #include <sys/file.h> ! 26: ! 27: #ifndef public ! 28: typedef int Lineno; ! 29: ! 30: String cursource; ! 31: Lineno curline; ! 32: Lineno cursrcline; ! 33: ! 34: #define LASTLINE 0 /* recognized by printlines */ ! 35: ! 36: #include "lists.h" ! 37: ! 38: List sourcepath; ! 39: #endif ! 40: ! 41: extern char *re_comp(); ! 42: ! 43: private Lineno lastlinenum; ! 44: private String prevsource = nil; ! 45: ! 46: /* ! 47: * Data structure for indexing source seek addresses by line number. ! 48: * ! 49: * The constraints are: ! 50: * ! 51: * we want an array so indexing is fast and easy ! 52: * we don't want to waste space for small files ! 53: * we don't want an upper bound on # of lines in a file ! 54: * we don't know how many lines there are ! 55: * ! 56: * The solution is a "dirty" hash table. We have NSLOTS pointers to ! 57: * arrays of NLINESPERSLOT addresses. To find the source address of ! 58: * a particular line we find the slot, allocate space if necessary, ! 59: * and then find its location within the pointed to array. ! 60: */ ! 61: ! 62: typedef long Seekaddr; ! 63: ! 64: #define NSLOTS 40 ! 65: #define NLINESPERSLOT 500 ! 66: ! 67: #define slotno(line) ((line) div NLINESPERSLOT) ! 68: #define index(line) ((line) mod NLINESPERSLOT) ! 69: #define slot_alloc() newarr(Seekaddr, NLINESPERSLOT) ! 70: #define srcaddr(line) seektab[slotno(line)][index(line)] ! 71: ! 72: private File srcfp; ! 73: private Seekaddr *seektab[NSLOTS]; ! 74: ! 75: /* ! 76: * Determine if the current source file is available. ! 77: */ ! 78: ! 79: public boolean canReadSource () ! 80: { ! 81: boolean b; ! 82: ! 83: if (cursource == nil) { ! 84: b = false; ! 85: } else if (cursource != prevsource) { ! 86: skimsource(); ! 87: b = (boolean) (lastlinenum != 0); ! 88: } else { ! 89: b = true; ! 90: } ! 91: return b; ! 92: } ! 93: ! 94: /* ! 95: * Print out the given lines from the source. ! 96: */ ! 97: ! 98: public printlines(l1, l2) ! 99: Lineno l1, l2; ! 100: { ! 101: register int c; ! 102: register Lineno i, lb, ub; ! 103: register File f; ! 104: ! 105: if (cursource == nil) { ! 106: beginerrmsg(); ! 107: fprintf(stderr, "no source file\n"); ! 108: } else { ! 109: if (cursource != prevsource) { ! 110: skimsource(); ! 111: } ! 112: if (lastlinenum == 0) { ! 113: beginerrmsg(); ! 114: fprintf(stderr, "couldn't read \"%s\"\n", cursource); ! 115: } else { ! 116: lb = (l1 == LASTLINE) ? lastlinenum : l1; ! 117: ub = (l2 == LASTLINE) ? lastlinenum : l2; ! 118: if (lb < 1) { ! 119: beginerrmsg(); ! 120: fprintf(stderr, "line number must be positive\n"); ! 121: } else if (lb > lastlinenum) { ! 122: beginerrmsg(); ! 123: if (lastlinenum == 1) { ! 124: fprintf(stderr, "\"%s\" has only 1 line\n", cursource); ! 125: } else { ! 126: fprintf(stderr, "\"%s\" has only %d lines\n", ! 127: cursource, lastlinenum); ! 128: } ! 129: } else if (ub < lb) { ! 130: beginerrmsg(); ! 131: fprintf(stderr, "second number must be greater than first\n"); ! 132: } else { ! 133: if (ub > lastlinenum) { ! 134: ub = lastlinenum; ! 135: } ! 136: f = srcfp; ! 137: fseek(f, srcaddr(lb), 0); ! 138: for (i = lb; i <= ub; i++) { ! 139: printf("%5d ", i); ! 140: while ((c = getc(f)) != '\n') { ! 141: putchar(c); ! 142: } ! 143: putchar('\n'); ! 144: } ! 145: cursrcline = ub + 1; ! 146: } ! 147: } ! 148: } ! 149: } ! 150: ! 151: /* ! 152: * Search the sourcepath for a file. ! 153: */ ! 154: ! 155: static char fileNameBuf[1024]; ! 156: ! 157: public String findsource(filename) ! 158: String filename; ! 159: { ! 160: register String src, dir; ! 161: ! 162: if (filename[0] == '/') { ! 163: src = filename; ! 164: } else { ! 165: src = nil; ! 166: foreach (String, dir, sourcepath) ! 167: sprintf(fileNameBuf, "%s/%s", dir, filename); ! 168: if (access(fileNameBuf, R_OK) == 0) { ! 169: src = fileNameBuf; ! 170: break; ! 171: } ! 172: endfor ! 173: } ! 174: return src; ! 175: } ! 176: ! 177: /* ! 178: * Open a source file looking in the appropriate places. ! 179: */ ! 180: ! 181: public File opensource(filename) ! 182: String filename; ! 183: { ! 184: String s; ! 185: File f; ! 186: ! 187: s = findsource(filename); ! 188: if (s == nil) { ! 189: f = nil; ! 190: } else { ! 191: f = fopen(s, "r"); ! 192: } ! 193: return f; ! 194: } ! 195: ! 196: /* ! 197: * Set the current source file. ! 198: */ ! 199: ! 200: public setsource(filename) ! 201: String filename; ! 202: { ! 203: if (filename != nil and filename != cursource) { ! 204: prevsource = cursource; ! 205: cursource = filename; ! 206: cursrcline = 1; ! 207: } ! 208: } ! 209: ! 210: /* ! 211: * Read the source file getting seek pointers for each line. ! 212: */ ! 213: ! 214: private skimsource() ! 215: { ! 216: register int c; ! 217: register Seekaddr count; ! 218: register File f; ! 219: register Lineno linenum; ! 220: register Seekaddr lastaddr; ! 221: register int slot; ! 222: ! 223: f = opensource(cursource); ! 224: if (f == nil) { ! 225: lastlinenum = 0; ! 226: } else { ! 227: if (prevsource != nil) { ! 228: free_seektab(); ! 229: if (srcfp != nil) { ! 230: fclose(srcfp); ! 231: } ! 232: } ! 233: prevsource = cursource; ! 234: linenum = 0; ! 235: count = 0; ! 236: lastaddr = 0; ! 237: while ((c = getc(f)) != EOF) { ! 238: ++count; ! 239: if (c == '\n') { ! 240: slot = slotno(++linenum); ! 241: if (slot >= NSLOTS) { ! 242: panic("skimsource: too many lines"); ! 243: } ! 244: if (seektab[slot] == nil) { ! 245: seektab[slot] = slot_alloc(); ! 246: } ! 247: seektab[slot][index(linenum)] = lastaddr; ! 248: lastaddr = count; ! 249: } ! 250: } ! 251: lastlinenum = linenum; ! 252: srcfp = f; ! 253: } ! 254: } ! 255: ! 256: /* ! 257: * Erase information and release space in the current seektab. ! 258: * This is in preparation for reading in seek pointers for a ! 259: * new file. It is possible that seek pointers for all files ! 260: * should be kept around, but the current concern is space. ! 261: */ ! 262: ! 263: private free_seektab() ! 264: { ! 265: register int slot; ! 266: ! 267: for (slot = 0; slot < NSLOTS; slot++) { ! 268: if (seektab[slot] != nil) { ! 269: dispose(seektab[slot]); ! 270: } ! 271: } ! 272: } ! 273: ! 274: /* ! 275: * Figure out current source position. ! 276: */ ! 277: ! 278: public getsrcpos() ! 279: { ! 280: String filename; ! 281: ! 282: curline = srcline(pc); ! 283: filename = srcfilename(pc); ! 284: setsource(filename); ! 285: if (curline != 0) { ! 286: cursrcline = curline; ! 287: } ! 288: } ! 289: ! 290: /* ! 291: * Print out the current source position. ! 292: */ ! 293: ! 294: public printsrcpos() ! 295: { ! 296: printf("at line %d", curline); ! 297: if (nlhdr.nfiles > 1) { ! 298: printf(" in file \"%s\"", cursource); ! 299: } ! 300: } ! 301: ! 302: #define DEF_EDITOR "vi" ! 303: ! 304: /* ! 305: * Invoke an editor on the given file. Which editor to use might change ! 306: * installation to installation. For now, we use "vi". In any event, ! 307: * the environment variable "EDITOR" overrides any default. ! 308: */ ! 309: ! 310: public edit(filename) ! 311: String filename; ! 312: { ! 313: extern String getenv(); ! 314: String ed, src, s; ! 315: Symbol f; ! 316: Address addr; ! 317: char lineno[10]; ! 318: ! 319: ed = getenv("EDITOR"); ! 320: if (ed == nil) { ! 321: ed = DEF_EDITOR; ! 322: } ! 323: src = findsource((filename != nil) ? filename : cursource); ! 324: if (src == nil) { ! 325: f = which(identname(filename, true)); ! 326: if (not isblock(f)) { ! 327: error("can't read \"%s\"", filename); ! 328: } ! 329: addr = firstline(f); ! 330: if (addr == NOADDR) { ! 331: error("no source for \"%s\"", filename); ! 332: } ! 333: src = srcfilename(addr); ! 334: s = findsource(src); ! 335: if (s != nil) { ! 336: src = s; ! 337: } ! 338: sprintf(lineno, "+%d", srcline(addr)); ! 339: } else { ! 340: sprintf(lineno, "+1"); ! 341: } ! 342: if (streq(ed, "vi") or streq(ed, "ex")) { ! 343: call(ed, stdin, stdout, lineno, src, nil); ! 344: } else { ! 345: call(ed, stdin, stdout, src, nil); ! 346: } ! 347: } ! 348: ! 349: /* ! 350: * Strip away portions of a given pattern not part of the regular expression. ! 351: */ ! 352: ! 353: private String getpattern (pattern) ! 354: String pattern; ! 355: { ! 356: register char *p, *r; ! 357: ! 358: p = pattern; ! 359: while (*p == ' ' or *p == '\t') { ! 360: ++p; ! 361: } ! 362: r = p; ! 363: while (*p != '\0') { ! 364: ++p; ! 365: } ! 366: --p; ! 367: if (*p == '\n') { ! 368: *p = '\0'; ! 369: --p; ! 370: } ! 371: if (*p == *r) { ! 372: *p = '\0'; ! 373: --p; ! 374: } ! 375: return r + 1; ! 376: } ! 377: ! 378: /* ! 379: * Search the current file for a regular expression. ! 380: */ ! 381: ! 382: public search (direction, pattern) ! 383: char direction; ! 384: String pattern; ! 385: { ! 386: register String p; ! 387: register File f; ! 388: String re, err; ! 389: Lineno line; ! 390: boolean matched; ! 391: char buf[512]; ! 392: ! 393: if (cursource == nil) { ! 394: beginerrmsg(); ! 395: fprintf(stderr, "no source file\n"); ! 396: } else { ! 397: if (cursource != prevsource) { ! 398: skimsource(); ! 399: } ! 400: if (lastlinenum == 0) { ! 401: beginerrmsg(); ! 402: fprintf(stderr, "couldn't read \"%s\"\n", cursource); ! 403: } else { ! 404: re = getpattern(pattern); ! 405: /* circf = 0; */ ! 406: if (re != nil and *re != '\0') { ! 407: err = re_comp(re); ! 408: if (err != nil) { ! 409: error(err); ! 410: } ! 411: } ! 412: matched = false; ! 413: f = srcfp; ! 414: line = cursrcline; ! 415: do { ! 416: if (direction == '/') { ! 417: ++line; ! 418: if (line > lastlinenum) { ! 419: line = 1; ! 420: } ! 421: } else { ! 422: --line; ! 423: if (line < 1) { ! 424: line = lastlinenum; ! 425: } ! 426: } ! 427: fseek(f, srcaddr(line), L_SET); ! 428: p = buf; ! 429: *p = getc(f); ! 430: while ((*p != '\n') and (*p != EOF)) { ! 431: ++p; ! 432: *p = getc(f); ! 433: } ! 434: *p = '\0'; ! 435: matched = (boolean) re_exec(buf); ! 436: } while (not matched and line != cursrcline); ! 437: if (not matched) { ! 438: beginerrmsg(); ! 439: fprintf(stderr, "no match\n"); ! 440: } else { ! 441: printlines(line, line); ! 442: cursrcline = line; ! 443: } ! 444: } ! 445: } ! 446: } ! 447: ! 448: /* ! 449: * Compute a small window around the given line. ! 450: */ ! 451: ! 452: public getsrcwindow (line, l1, l2) ! 453: Lineno line, *l1, *l2; ! 454: { ! 455: Node s; ! 456: integer size; ! 457: ! 458: s = findvar(identname("$listwindow", true)); ! 459: if (s == nil) { ! 460: size = 10; ! 461: } else { ! 462: eval(s); ! 463: size = pop(integer); ! 464: } ! 465: *l1 = line - (size div 2); ! 466: if (*l1 < 1) { ! 467: *l1 = 1; ! 468: } ! 469: *l2 = *l1 + size; ! 470: if (lastlinenum != LASTLINE and *l2 > lastlinenum) { ! 471: *l2 = lastlinenum; ! 472: } ! 473: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.