Annotation of 43BSD/contrib/jove/io.c, revision 1.1.1.1

1.1       root        1: /*************************************************************************
                      2:  * This program is copyright (C) 1985, 1986 by Jonathan Payne.  It is    *
                      3:  * provided to you without charge for use only on a licensed Unix        *
                      4:  * system.  You may copy JOVE provided that this notice is included with *
                      5:  * the copy.  You may not sell copies of this program or versions        *
                      6:  * modified for use on microcomputer systems, unless the copies are      *
                      7:  * included with a Unix system distribution and the source is provided.  *
                      8:  *************************************************************************/
                      9: 
                     10: #include "jove.h"
                     11: #include "io.h"
                     12: #include "termcap.h"
                     13: 
                     14: #ifdef IPROCS
                     15: #      include <signal.h>
                     16: #endif
                     17: 
                     18: #include <sys/stat.h>
                     19: #include <sys/file.h>
                     20: #include <errno.h>
                     21: 
                     22: long   io_chars;               /* number of chars in this open_file */
                     23: int    io_lines;               /* number of lines in this open_file */
                     24: private int    tellall;        /* display file io info? */
                     25: 
                     26: #ifdef VMUNIX
                     27: char   iobuff[LBSIZE],
                     28:        genbuf[LBSIZE],
                     29:        linebuf[LBSIZE];
                     30: #else
                     31: char   *iobuff,
                     32:        *genbuf,
                     33:        *linebuf;
                     34: #endif
                     35: 
                     36: #ifdef BACKUPFILES
                     37: int    BkupOnWrite = 0;
                     38: #endif
                     39: 
                     40: close_file(fp)
                     41: File   *fp;
                     42: {
                     43:        if (fp) {
                     44:                f_close(fp);
                     45:                if (tellall != QUIET)
                     46:                        add_mess(" %d lines, %D characters.",
                     47:                                 io_lines,
                     48:                                 io_chars);
                     49:        }
                     50: }
                     51: 
                     52: /* Write the region from line1/char1 to line2/char2 to FP.  This
                     53:    never CLOSES the file since we don't know if we want to. */
                     54: 
                     55: int    EndWNewline = 1;
                     56: 
                     57: putreg(fp, line1, char1, line2, char2, makesure)
                     58: register File  *fp;
                     59: Line   *line1,
                     60:        *line2;
                     61: {
                     62:        register int    c;
                     63:        register char   *lp;
                     64: 
                     65:        if (makesure)
                     66:                (void) fixorder(&line1, &char1, &line2, &char2);
                     67:        while (line1 != line2->l_next) {
                     68:                lp = lcontents(line1) + char1;
                     69:                if (line1 == line2)
                     70:                        fputnchar(lp, (char2 - char1), fp);
                     71:                else while (c = *lp++) {
                     72:                        putc(c, fp);
                     73:                        io_chars++;
                     74:                }
                     75:                if (line1 != line2) {
                     76:                        io_lines++;
                     77:                        io_chars++;
                     78:                        putc('\n', fp);
                     79:                }
                     80:                line1 = line1->l_next;
                     81:                char1 = 0;
                     82:        }
                     83:        flush(fp);
                     84: }
                     85: 
                     86: read_file(file, is_insert)
                     87: char   *file;
                     88: {
                     89:        Bufpos  save;
                     90:        File    *fp;
                     91: 
                     92:        if (!is_insert) {
                     93:                curbuf->b_ntbf = 0;
                     94:                set_ino(curbuf);
                     95:        }
                     96:        fp = open_file(file, iobuff, F_READ, !COMPLAIN, !QUIET);
                     97:        if (fp == NIL) {
                     98:                if (!is_insert && errno == ENOENT)
                     99:                        s_mess("(new file)");
                    100:                else
                    101:                        s_mess(IOerr("open", file));
                    102:                return;
                    103:        }
                    104:        DOTsave(&save);
                    105:        dofread(fp);
                    106:        SetDot(&save);
                    107:        if (is_insert && io_chars > 0)
                    108:                modify();
                    109:        getDOT();
                    110:        close_file(fp);
                    111: }
                    112: 
                    113: dofread(fp)
                    114: register File  *fp;
                    115: {
                    116:        char    end[LBSIZE];
                    117:        int     xeof = 0;
                    118:        Line    *savel = curline;
                    119:        int     savec = curchar;
                    120: 
                    121:        strcpy(end, linebuf + curchar);
                    122:        xeof = f_gets(fp, linebuf + curchar, LBSIZE - curchar);
                    123:        SavLine(curline, linebuf);
                    124:        if (!xeof) do {
                    125:                xeof = f_gets(fp, linebuf, LBSIZE);
                    126:                curline = listput(curbuf, curline);
                    127:                curline->l_dline = putline(linebuf) | DIRTY;
                    128:        } while (!xeof);
                    129:        linecopy(linebuf, (curchar = strlen(linebuf)), end);
                    130:        SavLine(curline, linebuf);
                    131:        IFixMarks(savel, savec, curline, curchar);
                    132: }
                    133: 
                    134: SaveFile()
                    135: {
                    136:        if (IsModified(curbuf)) {
                    137:                if (curbuf->b_fname == 0)
                    138:                        WriteFile();
                    139:                else {
                    140:                        filemunge(curbuf->b_fname);
                    141:                        chk_mtime(curbuf->b_fname, "save");
                    142:                        file_write(curbuf->b_fname, 0);
                    143:                        unmodify();
                    144:                }
                    145:        } else
                    146:                message("No changes need to be written.");
                    147: }
                    148: 
                    149: char   *HomeDir;       /* home directory */
                    150: int    HomeLen = -1;   /* length of home directory string */
                    151: 
                    152: #ifndef CHDIR
                    153: 
                    154: char *
                    155: pr_name(fname)
                    156: char   *fname;
                    157: {
                    158:        if (fname == 0)
                    159:                return 0;
                    160: 
                    161:        if (strncmp(fname, HomeDir, HomeLen) == 0) {
                    162:                static char     name_buf[100];
                    163: 
                    164:                sprintf(name_buf, "~%s", fname + HomeLen);
                    165:                return name_buf;
                    166:        }
                    167: 
                    168:        return fname;
                    169: }
                    170: 
                    171: #else
                    172: 
                    173: #define NDIRS  5
                    174: 
                    175: private char   *DirStack[NDIRS] = {0};
                    176: private int    DirSP = 0;      /* Directory stack pointer */
                    177: #define PWD    (DirStack[DirSP])
                    178: 
                    179: char *
                    180: pwd()
                    181: {
                    182:        return PWD;
                    183: }
                    184: 
                    185: char *
                    186: pr_name(fname)
                    187: char   *fname;
                    188: {
                    189:        int     n;
                    190: 
                    191:        if (fname == 0)
                    192:                return 0;
                    193:        n = numcomp(fname, PWD);
                    194: 
                    195:        if ((PWD[n] == 0) &&    /* Matched to end of PWD */
                    196:            (fname[n] == '/'))
                    197:                return fname + n + 1;
                    198: 
                    199:        if (strcmp(HomeDir, "/") != 0 && strncmp(fname, HomeDir, HomeLen) == 0) {
                    200:                static char     name_buf[100];
                    201: 
                    202:                sprintf(name_buf, "~%s", fname + HomeLen);
                    203:                return name_buf;
                    204:        }
                    205: 
                    206:        return fname;   /* return entire path name */
                    207: }
                    208: 
                    209: Chdir()
                    210: {
                    211:        char    dirbuf[FILESIZE];
                    212: 
                    213:        (void) ask_file(PWD, dirbuf);
                    214:        if (chdir(dirbuf) == -1) {
                    215:                s_mess("cd: cannot change into %s.", dirbuf);
                    216:                return;
                    217:        }
                    218:        UpdModLine++;
                    219:        setCWD(dirbuf);
                    220: }
                    221: 
                    222: #ifndef JOB_CONTROL
                    223: char *
                    224: getwd()
                    225: {
                    226:        Buffer  *old = curbuf;
                    227:        char    *ret_val;
                    228: 
                    229:        SetBuf(do_select((Window *) 0, "pwd-output"));
                    230:        curbuf->b_type = B_PROCESS;
                    231:        (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", "pwd", 0);
                    232:        ToFirst();
                    233:        ret_val = sprint(linebuf);
                    234:        SetBuf(old);
                    235:        return ret_val;
                    236: }
                    237: #endif
                    238: 
                    239: setCWD(d)
                    240: char   *d;
                    241: {
                    242:        if (PWD == 0)
                    243:                PWD = malloc((unsigned) strlen(d) + 1);
                    244:        else {
                    245:                extern char     *ralloc();
                    246: 
                    247:                PWD = ralloc(PWD, strlen(d) + 1);
                    248:        }
                    249:        strcpy(PWD, d);
                    250: }
                    251: 
                    252: getCWD()
                    253: {
                    254:        char    *cwd = getenv("CWD");
                    255: #ifdef JOB_CONTROL
                    256:        extern char     *getwd();
                    257:        char    pathname[FILESIZE];
                    258: #endif
                    259: 
                    260:        if (cwd == 0)
                    261: #ifdef JOB_CONTROL
                    262:                cwd = getwd(pathname);
                    263: #else
                    264:                cwd = getwd();
                    265: #endif
                    266: 
                    267:        setCWD(cwd);
                    268: }      
                    269: 
                    270: prDIRS()
                    271: {
                    272:        register int    i;
                    273: 
                    274:        s_mess(": %f ");
                    275:        for (i = DirSP; i >= 0; i--)
                    276:                add_mess("%s ", pr_name(DirStack[i]));
                    277: }
                    278: 
                    279: prCWD()
                    280: {
                    281:        s_mess(": %f => \"%s\"", PWD);
                    282: }
                    283: 
                    284: Pushd()
                    285: {
                    286:        char    *newdir,
                    287:                dirbuf[FILESIZE];
                    288: 
                    289:        newdir = ask_file(NullStr, dirbuf);     /* Parses directories ... */
                    290:        UpdModLine++;
                    291:        if (*newdir == 0) {     /* Wants to swap top two entries */
                    292:                char    *old_top;
                    293: 
                    294:                if (DirSP == 0)
                    295:                        complain("pushd: no other directory.");
                    296:                old_top = PWD;
                    297:                DirStack[DirSP] = DirStack[DirSP - 1];
                    298:                DirStack[DirSP - 1] = old_top;
                    299:                (void) chdir(PWD);
                    300:        } else {
                    301:                if (chdir(dirbuf) == -1) {
                    302:                        s_mess("pushd: cannot change into %s.", dirbuf);
                    303:                        return;
                    304:                }
                    305: 
                    306:                if (DirSP + 1 >= NDIRS)
                    307:                        complain("pushd: full stack; max of %d pushes.", NDIRS);
                    308:                DirSP++;
                    309:                setCWD(dirbuf);
                    310:        }
                    311:        prDIRS();
                    312: }
                    313: 
                    314: Popd()
                    315: {
                    316:        if (DirSP == 0)
                    317:                complain("popd: directory stack is empty.");
                    318:        UpdModLine++;
                    319:        free(PWD);
                    320:        PWD = 0;
                    321:        DirSP--;
                    322:        (void) chdir(PWD);      /* If this doesn't work, we's in deep shit. */
                    323:        prDIRS();
                    324: }
                    325: 
                    326: private char *
                    327: dbackup(base, offset, c)
                    328: register char  *base,
                    329:                *offset,
                    330:                c;
                    331: {
                    332:        while (offset > base && *--offset != c)
                    333:                ;
                    334:        return offset;
                    335: }
                    336: 
                    337: dfollow(file, into)
                    338: char   *file,
                    339:        *into;
                    340: {
                    341:        char    *dp,
                    342:                *sp;
                    343: 
                    344:        if (*file == '/') {             /* Absolute pathname */
                    345:                strcpy(into, "/");
                    346:                file++;
                    347:        } else
                    348:                strcpy(into, PWD);
                    349:        dp = into + strlen(into);
                    350: 
                    351:        sp = file;
                    352:        do {
                    353:                if (*file == 0)
                    354:                        break;
                    355:                if (sp = index(file, '/'))
                    356:                        *sp = 0;
                    357:                if (strcmp(file, ".") == 0)
                    358:                        ;       /* So it will get to the end of the loop */
                    359:                else if (strcmp(file, "..") == 0) {
                    360:                        *(dp = dbackup(into, dp, '/')) = 0;
                    361:                        if (dp == into)
                    362:                                strcpy(into, "/"), dp = into + 1;
                    363:                } else {
                    364:                        if (into[strlen(into) - 1] != '/')
                    365:                                (void) strcat(into, "/");
                    366:                        (void) strcat(into, file);
                    367:                        dp += strlen(file);     /* stay at the end */
                    368:                }
                    369:                file = sp + 1;
                    370:        } while (sp != 0);
                    371: }
                    372: 
                    373: #endif CHDIR
                    374: 
                    375: get_hdir(user, buf)
                    376: register char  *user,
                    377:                *buf;
                    378: {
                    379:        char    fbuf[LBSIZE],
                    380:                pattern[100];
                    381:        register int    u_len;
                    382:        File    *fp;
                    383: 
                    384:        u_len = strlen(user);
                    385:        fp = open_file("/etc/passwd", fbuf, F_READ, COMPLAIN, QUIET);
                    386:        sprintf(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
                    387:        while (f_gets(fp, genbuf, LBSIZE) != EOF)
                    388:                if ((strncmp(genbuf, user, u_len) == 0) &&
                    389:                    (LookingAt(pattern, genbuf, 0))) {
                    390:                        putmatch(1, buf, FILESIZE);
                    391:                        close_file(fp);
                    392:                        return;
                    393:                }
                    394:        f_close(fp);
                    395:        complain("[unknown user: %s]", user);
                    396: }
                    397: 
                    398: PathParse(name, intobuf)
                    399: char   *name,
                    400:        *intobuf;
                    401: {
                    402:        char    localbuf[FILESIZE];
                    403: 
                    404:        intobuf[0] = localbuf[0] = '\0';
                    405:        if (*name == '\0')
                    406:                return;
                    407:        if (*name == '~') {
                    408:                if (name[1] == '/' || name[1] == '\0') {
                    409:                        strcpy(localbuf, HomeDir);
                    410:                        name++;
                    411:                } else {
                    412:                        char    *uendp = index(name, '/'),
                    413:                                unamebuf[30];
                    414: 
                    415:                        if (uendp == 0)
                    416:                                uendp = name + strlen(name);
                    417:                        name = name + 1;
                    418:                        null_ncpy(unamebuf, name, uendp - name);
                    419:                        get_hdir(unamebuf, localbuf);
                    420:                        name = uendp;
                    421:                }
                    422:        } else if (*name == '\\')
                    423:                name++;
                    424:        (void) strcat(localbuf, name);
                    425: #ifdef CHDIR
                    426:        dfollow(localbuf, intobuf);
                    427: #else
                    428:        strcpy(intobuf, localbuf);
                    429: #endif
                    430: }
                    431: 
                    432: filemunge(newname)
                    433: char   *newname;
                    434: {
                    435:        struct stat     stbuf;
                    436: 
                    437:        if (newname == 0)
                    438:                return;
                    439:        if (stat(newname, &stbuf))
                    440:                return;
                    441:        if ((stbuf.st_ino != curbuf->b_ino) &&
                    442:            ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
                    443:            (strcmp(newname, curbuf->b_fname) != 0)) {
                    444:                rbell();
                    445:                confirm("\"%s\" already exists; overwrite it? ", newname);
                    446:        }
                    447: }
                    448: 
                    449: WrtReg()
                    450: {
                    451:        DoWriteReg(0);
                    452: }
                    453: 
                    454: AppReg()
                    455: {
                    456:        DoWriteReg(1);
                    457: }
                    458: 
                    459: int    CreatMode = DFLT_MODE;
                    460: 
                    461: DoWriteReg(app)
                    462: {
                    463:        char    fnamebuf[FILESIZE],
                    464:                *fname;
                    465:        Mark    *mp = CurMark();
                    466:        File    *fp;
                    467: 
                    468:        /* Won't get here if there isn't a Mark */
                    469:        fname = ask_file((char *) 0, fnamebuf);
                    470: 
                    471: #ifdef BACKUPFILES
                    472:        if (!app) {
                    473:                filemunge(fname);
                    474: 
                    475:                if (BkupOnWrite)
                    476:                        file_backup(fname);
                    477:        }
                    478: #else
                    479:        if (!app)
                    480:                filemunge(fname);
                    481: #endif
                    482: 
                    483:        fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
                    484:        putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
                    485:        close_file(fp);
                    486: }
                    487: 
                    488: int    OkayBadChars = 0;
                    489: 
                    490: WriteFile()
                    491: {
                    492:        char    *fname,
                    493:                fnamebuf[FILESIZE];
                    494: 
                    495:        fname = ask_file(curbuf->b_fname, fnamebuf);
                    496:        /* Don't allow bad characters when creating new files. */
                    497:        if (!OkayBadChars && strcmp(curbuf->b_fname, fnamebuf) != 0) {
                    498:                static char     *badchars = "!$^&*()~`{}\"'\\|<>? ";
                    499:                register char   *cp = fnamebuf;
                    500:                register int    c;
                    501: 
                    502:                while (c = *cp++)
                    503:                        if (c < ' ' || c == '\177' || index(badchars, c))
                    504:                                complain("'%p': bad character in filename.", c);
                    505:        }
                    506: 
                    507:        chk_mtime(fname, "write");
                    508:        filemunge(fname);
                    509:        if (curbuf->b_type != B_IPROCESS)
                    510:                curbuf->b_type = B_FILE;  /* In case it wasn't before. */
                    511:        setfname(curbuf, fname);
                    512:        file_write(fname, 0);
                    513:        unmodify();
                    514: }
                    515: 
                    516: File *
                    517: open_file(fname, buf, how, ifbad, loudness)
                    518: register char  *fname;
                    519: char   *buf;
                    520: register int   how;
                    521: {
                    522:        register File   *fp;
                    523: 
                    524:        io_chars = 0;
                    525:        io_lines = 0;
                    526:        tellall = loudness;
                    527: 
                    528:        fp = f_open(fname, how, buf, LBSIZE);
                    529:        if (fp == NIL) {
                    530:                 message(IOerr((how == F_READ) ? "open" : "create", fname));
                    531:                if (ifbad == COMPLAIN)
                    532:                        complain((char *) 0);
                    533:        } else {
                    534:                int     readonly = FALSE;
                    535: 
                    536:                if (access(fname, W_OK) == -1 && errno != ENOENT)
                    537:                        readonly = TRUE;
                    538:                                                         
                    539:                if (loudness != QUIET)
                    540:                        f_mess("\"%s\"%s", pr_name(fname),
                    541:                                   readonly ? " [Read only]" : NullStr);
                    542:        }
                    543:        return fp;
                    544: }
                    545: 
                    546: /* Check to see if the file has been modified since it was
                    547:    last written.  If so, make sure they know what they're
                    548:    doing.
                    549: 
                    550:    I hate to use another stat(), but to use confirm we gotta
                    551:    do this before we open the file. */
                    552: 
                    553: chk_mtime(fname, how)
                    554: char   *fname,
                    555:        *how;
                    556: {
                    557:        struct stat     stbuf;
                    558:        Buffer  *b;
                    559:        char    *mesg = "Shall I go ahead and %s anyway? ";
                    560: 
                    561:        if ((curbuf->b_mtime != 0) &&           /* if we care ... */
                    562:            (b = file_exists(fname)) &&         /* we already have this file */
                    563:            (b == curbuf) &&                    /* and it's the current buffer */
                    564:            (stat(fname, &stbuf) != -1) &&      /* and we can stat it */
                    565:            (stbuf.st_mtime != b->b_mtime)) {   /* and there's trouble. */
                    566:                rbell();
                    567:                redisplay();    /* Ring that bell! */
                    568:                TOstart("Warning", TRUE);
                    569:                Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname));
                    570:                Typeout("visited or saved.  Probably someone else is editing");
                    571:                Typeout("your file at the same time.  Type \"y\" if I should");
                    572:                Typeout("%s anyway.", how);
                    573:                f_mess(mesg, how);
                    574:                TOstop();
                    575:                confirm(mesg, how);
                    576:        }
                    577: }
                    578: 
                    579: file_write(fname, app)
                    580: char   *fname;
                    581: {
                    582:        File    *fp;
                    583: 
                    584: #ifdef BACKUPFILES
                    585:        if (!app && BkupOnWrite)
                    586:                file_backup(fname);
                    587: #endif
                    588: 
                    589:        fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, COMPLAIN, !QUIET);
                    590: 
                    591:        if (EndWNewline) {      /* Make sure file ends with a newLine */
                    592:                Bufpos  save;
                    593: 
                    594:                DOTsave(&save);
                    595:                ToLast();
                    596:                if (length(curline))    /* Not a blank Line */
                    597:                        DoTimes(LineInsert(), 1);       /* Make it blank */
                    598:                SetDot(&save);
                    599:        }
                    600:        putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
                    601:        set_ino(curbuf);
                    602:        close_file(fp);
                    603: }
                    604: 
                    605: ReadFile()
                    606: {
                    607:        char    *fname,
                    608:                fnamebuf[FILESIZE];
                    609: 
                    610:        fname = ask_file(curbuf->b_fname, fnamebuf);
                    611:        chk_mtime(fname, "read");
                    612: 
                    613:        if (IsModified(curbuf)) {
                    614:                char    *y_or_n;
                    615:                int     c;
                    616: 
                    617:                for (;;) {
                    618:                        rbell();
                    619:                        y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
                    620:                        c = Upper(*y_or_n);
                    621:                        if (c == 'Y' || c == 'N')
                    622:                                break;
                    623:                }                       
                    624:                if (c == 'Y')
                    625:                        SaveFile();
                    626:        }
                    627: 
                    628:        unmodify();
                    629:        initlist(curbuf);
                    630:        setfname(curbuf, fname);
                    631:        read_file(fname, 0);
                    632: }
                    633: 
                    634: InsFile()
                    635: {
                    636:        char    *fname,
                    637:                fnamebuf[FILESIZE];
                    638: 
                    639:        fname = ask_file(curbuf->b_fname, fnamebuf);
                    640:        read_file(fname, 1);
                    641: }
                    642: 
                    643: #include "temp.h"
                    644: 
                    645: int    DOLsave = 0;    /* Do Lsave flag.  If lines aren't being save
                    646:                           when you think they should have been, this
                    647:                           flag is probably not being set, or is being
                    648:                           cleared before lsave() was called. */
                    649: 
                    650: int    nleft,          /* Number of good characters left in current block */
                    651:        tmpfd;
                    652: disk_line      tline;  /* Pointer to end of tmp file */
                    653: 
                    654: char   *tfname;
                    655: 
                    656: tmpinit()
                    657: {
                    658:        tfname = mktemp(TMPFILE);
                    659:        (void) close(creat(tfname, 0600));
                    660:        tmpfd = open(tfname, 2);
                    661:        if (tmpfd == -1) {
                    662:                printf("%s?\n", tfname);
                    663:                finish(0);
                    664:        }
                    665:        block_init();
                    666:        tline = 2;
                    667: }
                    668: 
                    669: tmpclose()
                    670: {
                    671:        (void) close(tmpfd);
                    672:        tmpfd = -1;
                    673:        (void) unlink(tfname);
                    674: }
                    675: 
                    676: /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
                    677:    long. */
                    678: 
                    679: int    Jr_Len;         /* Length of Just Read Line. */
                    680: 
                    681: char *
                    682: getline(tl, buf)
                    683: disk_line      tl;
                    684: char   *buf;
                    685: {
                    686:        register char   *bp,
                    687:                        *lp;
                    688:        register int    nl;
                    689: 
                    690:        lp = buf;
                    691:        bp = getblock(tl, READ);
                    692:        nl = nleft;
                    693:        tl &= ~OFFMSK;
                    694: 
                    695:        while (*lp++ = *bp++) {
                    696:                if (--nl == 0) {
                    697:                        /* += INCRMT moves tl to the next block in
                    698:                           the tmp file. */
                    699:                        bp = getblock(tl += INCRMT, READ);
                    700:                        nl = nleft;
                    701:                }
                    702:        }
                    703:        Jr_Len = (lp - buf) - 1;
                    704: 
                    705:        return buf;
                    706: }
                    707: 
                    708: /* Put `buf' and return the disk address */
                    709: 
                    710: int    nretries = 0;
                    711: 
                    712: disk_line
                    713: putline(buf)
                    714: char   *buf;
                    715: {
                    716:        register char   *bp,
                    717:                        *lp;
                    718:        register int    nl;
                    719:        disk_line       tl;
                    720: 
                    721:        lp = buf;
                    722:        tl = tline;
                    723:        bp = getblock(tl, WRITE);
                    724:        nl = nleft;
                    725:        tl &= ~OFFMSK;
                    726:        while (*bp = *lp++) {
                    727:                if (*bp++ == '\n') {
                    728:                        *--bp = 0;
                    729:                        break;
                    730:                }
                    731:                if (--nl == 0) {
                    732:                        tline = (tl += INCRMT);
                    733:                        bp = getblock(tl, WRITE);
                    734:                        lp = buf;       /* start over ... */
                    735:                        nretries++;
                    736:                        nl = nleft;
                    737:                }
                    738:        }
                    739:        tl = tline;
                    740:        tline += (((lp - buf) + BNDRY - 1) >> SHFT) & 077776;
                    741: 
                    742:        return tl;
                    743: }
                    744: 
                    745: typedef struct block {
                    746:        short   b_dirty,
                    747:                b_bno;
                    748:        char    b_buf[BUFSIZ];
                    749:        struct block
                    750:                *b_LRUnext,
                    751:                *b_LRUprev,
                    752:                *b_HASHnext;
                    753: } Block;
                    754: 
                    755: #define HASHSIZE       7       /* Primes work best (so I'm told) */
                    756: #define B_HASH(bno)    (bno % HASHSIZE)
                    757: 
                    758: private Block  b_cache[NBUF],
                    759:                *bht[HASHSIZE] = {0},           /* Block hash table */
                    760:                *f_block = 0,
                    761:                *l_block = 0;
                    762: private int    max_bno = -1,
                    763:                NBlocks;
                    764: 
                    765: private
                    766: block_init()
                    767: {
                    768:        register Block  *bp,    /* Block pointer */
                    769:                        **hp;   /* Hash pointer */
                    770:        register short  bno;
                    771: 
                    772:        for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
                    773:                NBlocks++;
                    774:                bp->b_dirty = 0;
                    775:                bp->b_bno = bno;
                    776:                if (l_block == 0)
                    777:                        l_block = bp;
                    778:                bp->b_LRUprev = 0;
                    779:                bp->b_LRUnext = f_block;
                    780:                if (f_block != 0)
                    781:                        f_block->b_LRUprev = bp;
                    782:                f_block = bp;
                    783: 
                    784:                bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
                    785:                *hp = bp;
                    786:        }
                    787: }
                    788: 
                    789: private Block *
                    790: lookup(bno)
                    791: register short bno;
                    792: {
                    793:        register Block  *bp;
                    794: 
                    795:        for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
                    796:                if (bp->b_bno == bno)
                    797:                        break;
                    798:        return bp;
                    799: }
                    800: 
                    801: private
                    802: LRUunlink(b)
                    803: register Block *b;
                    804: {
                    805:        if (b->b_LRUprev == 0)
                    806:                f_block = b->b_LRUnext;
                    807:        else
                    808:                b->b_LRUprev->b_LRUnext = b->b_LRUnext;
                    809:        if (b->b_LRUnext == 0)
                    810:                l_block = b->b_LRUprev;
                    811:        else
                    812:                b->b_LRUnext->b_LRUprev = b->b_LRUprev;
                    813: }
                    814: 
                    815: private Block *
                    816: b_unlink(bp)
                    817: register Block *bp;
                    818: {
                    819:        register Block  *hp,
                    820:                        *prev = 0;
                    821: 
                    822:        LRUunlink(bp);
                    823:        /* Now that we have the block, we remove it from its position
                    824:           in the hash table, so we can THEN put it somewhere else with
                    825:           it's new block assignment. */
                    826: 
                    827:        for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
                    828:                if (hp == bp)
                    829:                        break;
                    830:        if (hp == 0) {
                    831:                printf("\rBlock %d missing!", bp->b_bno);
                    832:                finish(0);
                    833:        }
                    834:        if (prev)
                    835:                prev->b_HASHnext = hp->b_HASHnext;
                    836:        else
                    837:                bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
                    838: 
                    839:        if (bp->b_dirty) {      /* Do, now, the delayed write */
                    840:                blkio(bp, write);
                    841:                bp->b_dirty = 0;
                    842:        }
                    843: 
                    844:        return bp;
                    845: }
                    846: 
                    847: /* Get a block which contains at least part of the line with the address
                    848:    atl.  Returns a pointer to the block and sets the global variable
                    849:    nleft (number of good characters left in the buffer). */
                    850: 
                    851: char *
                    852: getblock(atl, iof)
                    853: disk_line      atl;
                    854: {
                    855:        register int    bno,
                    856:                        off;
                    857:        register Block  *bp;
                    858:        static Block    *lastb = 0;
                    859: 
                    860:        bno = (atl >> OFFBTS) & BLKMSK;
                    861:        off = (atl << SHFT) & LBTMSK;
                    862:        if (bno >= NMBLKS)
                    863:                error("Tmp file too large.  Get help!");
                    864:        nleft = BUFSIZ - off;
                    865:        if (lastb != 0 && lastb->b_bno == bno)
                    866:                return lastb->b_buf + off;
                    867: 
                    868:        /* The requested block already lives in memory, so we move
                    869:           it to the end of the LRU list (making it Most Recently Used)
                    870:           and then return a pointer to it. */
                    871: 
                    872:        if (bp = lookup(bno)) {
                    873:                if (bp != l_block) {
                    874:                        LRUunlink(bp);
                    875:                        if (l_block == 0)
                    876:                                f_block = l_block = bp;
                    877:                        else
                    878:                                l_block->b_LRUnext = bp;
                    879:                        bp->b_LRUprev = l_block;
                    880:                        l_block = bp;
                    881:                        bp->b_LRUnext = 0;
                    882:                }
                    883:                if (bp->b_bno > max_bno)
                    884:                        max_bno = bp->b_bno;
                    885:                bp->b_dirty |= iof;
                    886:                lastb = bp;
                    887:                return bp->b_buf + off;
                    888:        }
                    889: 
                    890:        /* The block we want doesn't reside in memory so we take the
                    891:           least recently used clean block (if there is one) and use
                    892:           it.  */
                    893: 
                    894:        bp = f_block;
                    895:        if (bp->b_dirty)        /* The best block is dirty ... */
                    896:                SyncTmp();
                    897: 
                    898:        bp = b_unlink(bp);
                    899:        if (l_block == 0)
                    900:                l_block = f_block = bp;
                    901:        else
                    902:                l_block->b_LRUnext = bp;        /* Place it at the end ... */
                    903:        bp->b_LRUprev = l_block;
                    904:        l_block = bp;
                    905:        bp->b_LRUnext = 0;              /* so it's Most Recently Used */
                    906: 
                    907:        bp->b_dirty = iof;
                    908:        bp->b_bno = bno;
                    909:        bp->b_HASHnext = bht[B_HASH(bno)];
                    910:        bht[B_HASH(bno)] = bp;
                    911: 
                    912:        /* Get the current contents of the block UNLESS this is a new
                    913:           block that's never been looked at before, i.e., it's past
                    914:           the end of the tmp file. */
                    915: 
                    916:        if (bp->b_bno <= max_bno)
                    917:                blkio(bp, read);
                    918:        else
                    919:                max_bno = bno;
                    920: 
                    921:        lastb = bp;
                    922:        return bp->b_buf + off;
                    923: }
                    924: 
                    925: char *
                    926: lbptr(line)
                    927: Line   *line;
                    928: {
                    929:        return getblock(line->l_dline, READ);
                    930: }
                    931: 
                    932: private
                    933: blkio(b, iofcn)
                    934: register Block *b;
                    935: register int   (*iofcn)();
                    936: {
                    937:        (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * BUFSIZ, 0);
                    938:        if ((*iofcn)(tmpfd, b->b_buf, BUFSIZ) != BUFSIZ)
                    939:                error("Tmp file %s error.", (iofcn == read) ? "read" : "write");
                    940: }
                    941: 
                    942: SyncTmp()
                    943: {
                    944:        register Block  *b;
                    945: 
                    946:        for (b = f_block; b != 0; b = b->b_LRUnext)
                    947:                if (b->b_dirty) {
                    948:                        blkio(b, write);
                    949:                        b->b_dirty = 0;
                    950:                }
                    951: }
                    952: 
                    953: /* save the current contents of linebuf, if it has changed */
                    954: 
                    955: lsave()
                    956: {
                    957:        if (curbuf == 0 || !DOLsave)    /* Nothing modified recently */
                    958:                return;
                    959: 
                    960:        if (strcmp(lbptr(curline), linebuf) != 0)
                    961:                SavLine(curline, linebuf);      /* Put linebuf on the disk. */
                    962:        DOLsave = 0;
                    963: }
                    964: 
                    965: #ifdef BACKUPFILES
                    966: file_backup(fname)
                    967: char *fname;
                    968: {
                    969:        char *s;
                    970:        register int    i;
                    971:        int     fd1,
                    972:                fd2;
                    973:        char    tmp1[BUFSIZ],
                    974:                tmp2[BUFSIZ];
                    975:        
                    976:        strcpy(tmp1, fname);
                    977:        
                    978:        if ((s = rindex(tmp1, '/')) == NULL)
                    979:                sprintf(tmp2, "#%s", fname);
                    980:        else {
                    981:                *s++ = NULL;
                    982:                sprintf(tmp2, "%s/#%s", tmp1, s);
                    983:        }
                    984: 
                    985:        if ((fd1 = open(fname, 0)) < 0)
                    986:                return;
                    987: 
                    988:        if ((fd2 = creat(tmp2, CreatMode)) < 0) {
                    989:                (void) close(fd1);
                    990:                return;
                    991:        }
                    992: 
                    993:        while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
                    994:                write(fd2, tmp1, i);
                    995: 
                    996: #ifdef BSD4_2
                    997:        (void) fsync(fd2);
                    998: #endif
                    999:        (void) close(fd2);
                   1000:        (void) close(fd1);
                   1001: }
                   1002: #endif

unix.superglobalmegacorp.com

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