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: }

Defined functions

canReadSource defined in line 79; used 1 times
edit defined in line 310; used 1 times
findsource defined in line 157; used 3 times
free_seektab defined in line 263; used 1 times
getpattern defined in line 353; used 1 times
getsrcwindow defined in line 452; used 1 times
opensource defined in line 181; used 2 times
printlines defined in line 98; used 6 times
printsrcpos defined in line 294; used 3 times
search defined in line 382; used 1 times
skimsource defined in line 214; used 3 times

Defined variables

curline defined in line 31; used 4 times
cursource defined in line 30; used 17 times
cursrcline defined in line 32; used 6 times
fileNameBuf defined in line 155; used 3 times
lastlinenum defined in line 43; used 17 times
prevsource defined in line 44; used 6 times
rcsid defined in line 11; never used
sccsid defined in line 8; never used
seektab defined in line 73; used 6 times

Defined typedef's

Lineno defined in line 28; used 8 times
Seekaddr defined in line 62; used 4 times

Defined macros

DEF_EDITOR defined in line 302; used 1 times
LASTLINE defined in line 34; used 3 times
NLINESPERSLOT defined in line 65; used 3 times
NSLOTS defined in line 64; used 3 times
index defined in line 68; used 2 times
slot_alloc defined in line 69; used 1 times
slotno defined in line 67; used 2 times
srcaddr defined in line 70; used 2 times
Last modified: 1985-05-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1945
Valid CSS Valid XHTML 1.0 Strict