Annotation of 43BSD/ucb/dbx/source.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.