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