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

1.1       root        1: /***************************************************************************
                      2:  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
                      3:  * is provided to you without charge, and with no warranty.  You may give  *
                      4:  * away copies of JOVE, including sources, provided that this notice is    *
                      5:  * included in all the files.                                              *
                      6:  ***************************************************************************/
                      7: 
                      8: #include "jove.h"
                      9: #include "list.h"
                     10: #include "fp.h"
                     11: #include "termcap.h"
                     12: #include "ctype.h"
                     13: #include "disp.h"
                     14: #include "scandir.h"
                     15: 
                     16: 
                     17: #ifdef IPROCS
                     18: # include <signal.h>
                     19: #endif
                     20: 
                     21: #ifdef MAC
                     22: # include "mac.h"
                     23: #else
                     24: # include <sys/stat.h>
                     25: #endif
                     26: 
                     27: #ifdef UNIX
                     28: # include <sys/file.h>
                     29: #endif
                     30: 
                     31: #ifdef MSDOS
                     32: # include <fcntl.h>
                     33: # include <io.h>
                     34: # include <direct.h>
                     35: # include <dos.h>
                     36: #endif /* MSDOS */
                     37: 
                     38: #include <errno.h>
                     39: 
                     40: private struct block
                     41:        *b_unlink proto((struct block *)),
                     42:        *lookup proto((/*int*/short));
                     43: 
                     44: private char
                     45:        *dbackup proto((char *, char *, int)),
                     46: #if defined(MSDOS)
                     47:        *fixpath proto((char *)),
                     48: #endif
                     49:        *getblock proto((daddr, int));
                     50: 
                     51: private void
                     52: #if defined(MSDOS)
                     53:        abspath proto((char *, char *)),
                     54: #endif
                     55:        fake_blkio proto((struct block *, int (*)())),
                     56:        DoWriteReg proto((int app)),
                     57:        LRUunlink proto((struct block *)),
                     58:        file_backup proto((char *fname)),
                     59:        real_blkio proto((struct block *, int (*)())),
                     60:        dfollow proto((char *, char *));
                     61: 
                     62: #if defined(MSDOS)
                     63: private int
                     64:        Dchdir proto((char *));
                     65: #endif
                     66: 
                     67: #ifndef W_OK
                     68: # define W_OK  2
                     69: # define F_OK  0
                     70: #endif
                     71: 
                     72: #define        READ    0
                     73: #define        WRITE   1       /* block operation read or write */
                     74: 
                     75: long   io_chars;               /* number of chars in this open_file */
                     76: int    io_lines;               /* number of lines in this open_file */
                     77: 
                     78: #if defined(VMUNIX) || defined(MSDOS)
                     79: char   iobuff[LBSIZE],
                     80:        genbuf[LBSIZE],
                     81:        linebuf[LBSIZE];
                     82: #else
                     83: char   *iobuff,
                     84:        *genbuf,
                     85:        *linebuf;
                     86: #endif
                     87: 
                     88: #ifdef BACKUPFILES
                     89: int    BkupOnWrite = 0;
                     90: #endif
                     91: 
                     92: void
                     93: close_file(fp)
                     94: File   *fp;
                     95: {
                     96:        if (fp) {
                     97:                if (fp->f_flags & F_TELLALL)
                     98:                        add_mess(" %d lines, %D characters.",
                     99:                                 io_lines,
                    100:                                 io_chars);
                    101:                f_close(fp);
                    102:        }
                    103: }
                    104: 
                    105: /* Write the region from line1/char1 to line2/char2 to FP.  This
                    106:    never CLOSES the file since we don't know if we want to. */
                    107: 
                    108: int    EndWNewline = 1;
                    109: 
                    110: void
                    111: putreg(fp, line1, char1, line2, char2, makesure)
                    112: register File  *fp;
                    113: Line   *line1,
                    114:        *line2;
                    115: int    char1,
                    116:        char2,
                    117:        makesure;
                    118: {
                    119:        register int    c;
                    120:        register char   *lp;
                    121: 
                    122:        if (makesure)
                    123:                (void) fixorder(&line1, &char1, &line2, &char2);
                    124:        while (line1 != line2->l_next) {
                    125:                lp = lcontents(line1) + char1;
                    126:                if (line1 == line2) {
                    127:                        fputnchar(lp, (char2 - char1), fp);
                    128:                        io_chars += (char2 - char1);
                    129:                } else {
                    130:                        while ((c = *lp++) != '\0') {
                    131:                                jputc(c, fp);
                    132:                                io_chars += 1;
                    133:                        }
                    134:                }
                    135:                if (line1 != line2) {
                    136:                        io_lines += 1;
                    137:                        io_chars += 1;
                    138: #ifdef MSDOS
                    139:                        jputc('\r', fp);
                    140: #endif /* MSDOS */
                    141:                        jputc('\n', fp);
                    142:                }
                    143:                line1 = line1->l_next;
                    144:                char1 = 0;
                    145:        }
                    146:        flush(fp);
                    147: }
                    148: 
                    149: private void
                    150: dofread(fp)
                    151: register File  *fp;
                    152: {
                    153:        char    end[LBSIZE];
                    154:        int     xeof = 0;
                    155:        Line    *savel = curline;
                    156:        int     savec = curchar;
                    157: 
                    158:        strcpy(end, linebuf + curchar);
                    159:        xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar));
                    160:        SavLine(curline, linebuf);
                    161:        if (!xeof) do {
                    162:                curline = listput(curbuf, curline);
                    163:                xeof = f_getputl(curline, fp);
                    164:        } while (!xeof);
                    165:        getDOT();
                    166:        linecopy(linebuf, (curchar = strlen(linebuf)), end);
                    167:        SavLine(curline, linebuf);
                    168:        IFixMarks(savel, savec, curline, curchar);
                    169: }
                    170: 
                    171: void
                    172: read_file(file, is_insert)
                    173: char   *file;
                    174: int    is_insert;
                    175: {
                    176:        Bufpos  save;
                    177:        File    *fp;
                    178: 
                    179:        if (is_insert == NO)
                    180:                curbuf->b_ntbf = NO;
                    181:        fp = open_file(file, iobuff, F_READ, NO, NO);
                    182:        if (fp == NIL) {
                    183:                if (!is_insert && errno == ENOENT)
                    184:                        s_mess("(new file)");
                    185:                else
                    186:                        s_mess(IOerr("open", file));
                    187:                return;
                    188:        }
                    189:        if (is_insert == NO) {
                    190:                set_ino(curbuf);
                    191:                if (fp->f_flags & F_READONLY) {
                    192:                        set_arg_value(1);
                    193:                } else {
                    194:                        set_arg_value(0);
                    195:                }
                    196:                TogMinor(ReadOnly);
                    197:        }
                    198: 
                    199:        DOTsave(&save);
                    200:        dofread(fp);
                    201:        if (is_insert && io_chars > 0) {
                    202:                modify();
                    203:                set_mark();
                    204:        }
                    205:        SetDot(&save);
                    206:        getDOT();
                    207:        close_file(fp);
                    208: }
                    209: 
                    210: void
                    211: SaveFile()
                    212: {
                    213:        if (IsModified(curbuf)) {
                    214:                if (curbuf->b_fname == 0)
                    215:                        WriteFile();
                    216:                else {
                    217:                        filemunge(curbuf->b_fname);
                    218: #if !defined(MAC) && !defined(MSDOS)
                    219:                        chk_mtime(curbuf, curbuf->b_fname, "save");
                    220: #endif
                    221:                        file_write(curbuf->b_fname, 0);
                    222:                }
                    223:        } else
                    224:                message("No changes need to be written.");
                    225: }
                    226: 
                    227: char   *HomeDir;       /* home directory */
                    228: size_t HomeLen;        /* length of home directory string */
                    229: 
                    230: private List           *DirStack = 0;
                    231: #define dir_name(dp)   ((char *) list_data(dp))
                    232: #define PWD_PTR                (list_data(DirStack))
                    233: #define PWD            ((char *) PWD_PTR)
                    234: 
                    235: char *
                    236: pwd()
                    237: {
                    238:        return (char *) PWD_PTR;
                    239: }
                    240: 
                    241: char *
                    242: pr_name(fname, okay_home)
                    243: char   *fname;
                    244: int    okay_home;
                    245: {
                    246:        int     n;
                    247: 
                    248:        if (fname == 0)
                    249:                return 0;
                    250:        n = numcomp(fname, PWD);
                    251: 
                    252:        if ((PWD[n] == 0) &&    /* Matched to end of PWD */
                    253:            (fname[n] == '/'))
                    254:                return fname + n + 1;
                    255: 
                    256:        if (okay_home && strcmp(HomeDir, "/") != 0 &&
                    257:            strncmp(fname, HomeDir, HomeLen) == 0 &&
                    258:            fname[HomeLen] == '/') {
                    259:                static char     name_buf[100];
                    260: 
                    261:                swritef(name_buf, "~%s", fname + HomeLen);
                    262:                return name_buf;
                    263:        }
                    264: 
                    265:        return fname;   /* return entire path name */
                    266: }
                    267: 
                    268: #ifdef MSDOS
                    269: extern unsigned int fmask;
                    270: #endif /* MSDOS */
                    271: 
                    272: void
                    273: Chdir()
                    274: {
                    275:        char    dirbuf[FILESIZE];
                    276: 
                    277: #ifdef MSDOS
                    278:        fmask = 0x10;
                    279: #endif
                    280:        (void) ask_file((char *) 0, PWD, dirbuf);
                    281: #ifdef MSDOS
                    282:        fmask = 0x13;
                    283:        if (Dchdir(dirbuf) == -1)
                    284: #else
                    285:        if (chdir(dirbuf) == -1)
                    286: #endif
                    287:        {
                    288:                s_mess("cd: cannot change into %s.", dirbuf);
                    289:                return;
                    290:        }
                    291:        UpdModLine = YES;
                    292:        setCWD(dirbuf);
                    293:        prCWD();
                    294: #ifdef MAC
                    295:        Bufchange++;
                    296: #endif
                    297: }
                    298: 
                    299: #if defined(UNIX)
                    300: 
                    301: #  if !defined(BSD4_2)
                    302: char *
                    303: getwd(buffer)
                    304: char   *buffer;
                    305: {
                    306:        Buffer  *old = curbuf;
                    307:        char    *ret_val;
                    308: 
                    309:        SetBuf(do_select((Window *) 0, "pwd-output"));
                    310:        curbuf->b_type = B_PROCESS;
                    311:        (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0);
                    312:        ToFirst();
                    313:        strcpy(buffer, linebuf);
                    314:        SetBuf(old);
                    315:        return buffer;
                    316: }
                    317: #  endif       /* not BSD4_2 */
                    318: 
                    319: /* Check if dn is the name of the current working directory
                    320:    and that it is in cannonical form */
                    321: 
                    322: int
                    323: chkCWD(dn)
                    324: char   *dn;
                    325: {
                    326:        char    filebuf[FILESIZE];
                    327:        struct stat     dnstat,
                    328:                        dotstat;
                    329: 
                    330:        if (dn[0] != '/')
                    331:                return FALSE;           /* need absolute pathname */
                    332:        PathParse(dn, filebuf);
                    333:        return stat(filebuf, &dnstat) == 0 &&
                    334:               stat(".", &dotstat) == 0 &&
                    335:               dnstat.st_dev == dotstat.st_dev &&
                    336:               dnstat.st_ino == dotstat.st_ino;
                    337: }
                    338: 
                    339: #endif /* UNIX */
                    340: 
                    341: void
                    342: setCWD(d)
                    343: char   *d;
                    344: {
                    345:        if (DirStack == NIL)
                    346:                list_push(&DirStack, (Element *) 0);
                    347:        if (PWD == 0)
                    348:                PWD_PTR = (Element *) emalloc((size_t) (strlen(d) + 1));
                    349:        else
                    350:                PWD_PTR = (Element *) ralloc(PWD, strlen(d) + 1);
                    351:        strcpy(PWD, d);
                    352: }
                    353: 
                    354: void
                    355: getCWD()
                    356: {
                    357:        char    *cwd;
                    358:        char    pathname[FILESIZE];
                    359: #if defined(UNIX) && defined(JOB_CONTROL)
                    360:        extern char     *getwd();
                    361: #endif
                    362: #if defined(MSDOS)
                    363:        extern char     *getcwd();
                    364: #endif
                    365: 
                    366: #ifndef MSDOS
                    367:        cwd = getenv("CWD");
                    368:        if (cwd == 0 || !chkCWD(cwd)) {
                    369:                cwd = getenv("PWD");
                    370:                if (cwd == 0 || !chkCWD(cwd))
                    371:                        cwd = getwd(pathname);
                    372:        }
                    373: #else /* MSDOS */
                    374:                cwd = fixpath(getcwd(pathname, FILESIZE));
                    375: #endif /* MSDOS */
                    376:        setCWD(cwd);
                    377: }
                    378: 
                    379: void
                    380: prDIRS()
                    381: {
                    382:        register List   *lp;
                    383: 
                    384:        s_mess(": %f ");
                    385:        for (lp = DirStack; lp != NIL; lp = list_next(lp))
                    386:                add_mess("%s ", pr_name(dir_name(lp), YES));
                    387: }
                    388: 
                    389: void
                    390: prCWD()
                    391: {
                    392:        s_mess(": %f => \"%s\"", PWD);
                    393: }
                    394: 
                    395: void
                    396: Pushd()
                    397: {
                    398:        char    *newdir,
                    399:                dirbuf[FILESIZE];
                    400: 
                    401: #ifdef MSDOS
                    402:        fmask = 0x10;
                    403: #endif
                    404:        newdir = ask_file((char *) 0, NullStr, dirbuf);
                    405: #ifdef MSDOS
                    406:        fmask = 0x13;
                    407: #endif
                    408:        UpdModLine = YES;
                    409:        if (*newdir == 0) {     /* Wants to swap top two entries */
                    410:                char    *old_top;
                    411: 
                    412:                if (list_next(DirStack) == NIL)
                    413:                        complain("pushd: no other directory.");
                    414:                old_top = PWD;
                    415:                list_data(DirStack) = (Element *) dir_name(list_next(DirStack));
                    416:                list_data(list_next(DirStack)) = (Element *) old_top;
                    417: #ifdef MSDOS
                    418:                (void) Dchdir(PWD);
                    419: #else
                    420:                (void) chdir(PWD);
                    421: #endif
                    422:        } else {
                    423: #ifdef MSDOS
                    424:                if (Dchdir(dirbuf) == -1)
                    425: #else
                    426:                if (chdir(dirbuf) == -1)
                    427: #endif
                    428:                {
                    429:                        s_mess("pushd: cannot change into %s.", dirbuf);
                    430:                        return;
                    431:                }
                    432:                (void) list_push(&DirStack, (Element *) 0);
                    433:                setCWD(dirbuf);
                    434:        }
                    435:        prDIRS();
                    436: }
                    437: 
                    438: void
                    439: Popd()
                    440: {
                    441:        if (list_next(DirStack) == NIL)
                    442:                complain("popd: directory stack is empty.");
                    443:        UpdModLine = YES;
                    444:        free((char *) list_pop(&DirStack));
                    445: #ifdef MSDOS
                    446:        (void) Dchdir(PWD);     /* If this doesn't work, we's in deep shit. */
                    447: #else
                    448:        (void) chdir(PWD);      /* If this doesn't work, we's in deep shit. */
                    449: #endif
                    450:        prDIRS();
                    451: }
                    452: 
                    453: private char *
                    454: dbackup(base, offset, c)
                    455: register char  *base,
                    456:                *offset;
                    457: register int   c;
                    458: {
                    459:        while (offset > base && *--offset != c)
                    460:                ;
                    461:        return offset;
                    462: }
                    463: 
                    464: private void
                    465: dfollow(file, into)
                    466: char   *file,
                    467:        *into;
                    468: {
                    469:        char    *dp,
                    470: #ifdef MSDOS
                    471:                filefix[FILESIZE],
                    472: #endif
                    473:                *sp;
                    474: 
                    475: #ifndef MSDOS
                    476:        if (*file == '/') {             /* Absolute pathname */
                    477:                strcpy(into, "/");
                    478:                file += 1;
                    479: #ifdef apollo
                    480:                /* handle apollo "//..." */
                    481:                if (*file == '/') {
                    482:                        strcpy(into+1, "/");
                    483:                        file += 1;
                    484:                }
                    485: #endif
                    486:        } else
                    487:                strcpy(into, PWD);
                    488: #else
                    489:        abspath(file, filefix);         /* convert to absolute pathname */
                    490:        strcpy(into, filefix);          /* and forget about drives      */
                    491:        into[3] = 0;
                    492:        into = &(into[2]);
                    493:        file = &(filefix[3]);
                    494: #endif
                    495:        dp = into + strlen(into);
                    496: 
                    497:        sp = file;
                    498:        do {
                    499:                if (*file == 0)
                    500:                        break;
                    501:                if ((sp = strchr(file, '/')) != '\0')
                    502:                        *sp = 0;
                    503:                if (strcmp(file, ".") == 0)
                    504:                        ;       /* So it will get to the end of the loop */
                    505:                else if (strcmp(file, "..") == 0) {
                    506:                        *(dp = dbackup(into, dp, '/')) = 0;
                    507:                        if (dp == into)
                    508:                                strcpy(into, "/"), dp = into + 1;
                    509:                } else {
                    510:                        if (into[strlen(into) - 1] != '/')
                    511:                                (void) strcat(into, "/"), dp += 1;
                    512:                        (void) strcat(into, file);
                    513:                        dp += strlen(file);     /* stay at the end */
                    514:                }
                    515:                file = sp + 1;
                    516:        } while (sp != 0);
                    517: }
                    518: 
                    519: #if defined(UNIX)
                    520: 
                    521: # if defined(YP_PASSWD)
                    522: 
                    523: #include <pwd.h>
                    524: 
                    525: private void
                    526: get_hdir(user, buf)
                    527: register char  *user,
                    528:                *buf;
                    529: {
                    530:        struct passwd   *p;
                    531: 
                    532:        p = getpwnam(user);
                    533:        endpwent();
                    534:        if (p == NULL) {
                    535:                add_mess(" [unknown user: %s]", user);
                    536:                SitFor(7);
                    537:                complain((char *) 0);
                    538:                /* NOTREACHED */
                    539:        }
                    540:        strcpy(buf, p->pw_dir);
                    541: }
                    542: 
                    543: #else
                    544: 
                    545: private
                    546: get_hdir(user, buf)
                    547: register char  *user,
                    548:                *buf;
                    549: {
                    550:        char    fbuf[LBSIZE],
                    551:                pattern[100];
                    552:        register int    u_len;
                    553:        File    *fp;
                    554: 
                    555:        u_len = strlen(user);
                    556:        fp = open_file("/etc/passwd", fbuf, F_READ, YES, YES);
                    557:        swritef(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
                    558:        while (f_gets(fp, genbuf, LBSIZE) != EOF)
                    559:                if ((strncmp(genbuf, user, u_len) == 0) &&
                    560:                    (LookingAt(pattern, genbuf, 0))) {
                    561:                        putmatch(1, buf, FILESIZE);
                    562:                        close_file(fp);
                    563:                        return;
                    564:                }
                    565:        close_file(fp);
                    566:        add_mess(" [unknown user: %s]", user);
                    567:        SitFor(7);
                    568:        complain((char *) 0);
                    569: }
                    570: 
                    571: #endif /* YP_PASSWD */
                    572: #endif /* UNIX */
                    573: 
                    574: void
                    575: PathParse(name, intobuf)
                    576: char   *name,
                    577:        *intobuf;
                    578: {
                    579:        char    localbuf[FILESIZE];
                    580: 
                    581:        intobuf[0] = localbuf[0] = '\0';
                    582:        if (*name == '\0')
                    583:                return;
                    584:        if (*name == '~') {
                    585:                if (name[1] == '/' || name[1] == '\0') {
                    586:                        strcpy(localbuf, HomeDir);
                    587:                        name += 1;
                    588:                }
                    589: #if !(defined(MSDOS) || defined(MAC))  /* may add for mac in future */
                    590:                else {
                    591:                        char    *uendp = strchr(name, '/'),
                    592:                                unamebuf[30];
                    593: 
                    594:                        if (uendp == 0)
                    595:                                uendp = name + strlen(name);
                    596:                        name += 1;
                    597:                        null_ncpy(unamebuf, name, (size_t) (uendp - name));
                    598:                        get_hdir(unamebuf, localbuf);
                    599:                        name = uendp;
                    600:                }
                    601: #endif
                    602:        }
                    603: #ifndef MSDOS
                    604:        else if (*name == '\\')
                    605:                name += 1;
                    606: #endif /* MSDOS */
                    607:        (void) strcat(localbuf, name);
                    608:        dfollow(localbuf, intobuf);
                    609: }
                    610: 
                    611: void
                    612: filemunge(newname)
                    613: char   *newname;
                    614: {
                    615:        struct stat     stbuf;
                    616: 
                    617:        if (newname == 0)
                    618:                return;
                    619:        if (stat(newname, &stbuf))
                    620:                return;
                    621: #ifndef MSDOS
                    622:        if (((stbuf.st_dev != curbuf->b_dev) ||
                    623:             (stbuf.st_ino != curbuf->b_ino)) &&
                    624: #else /* MSDOS */
                    625:        if ( /* (stbuf.st_ino != curbuf->b_ino) && */
                    626: #endif /* MSDOS */
                    627: #ifndef MAC
                    628:            ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
                    629: #endif
                    630:            (curbuf->b_fname==NIL || strcmp(newname, curbuf->b_fname) != 0)) {
                    631:                rbell();
                    632:                confirm("\"%s\" already exists; overwrite it? ", newname);
                    633:        }
                    634: }
                    635: 
                    636: void
                    637: WrtReg()
                    638: {
                    639:        DoWriteReg(NO);
                    640: }
                    641: 
                    642: void
                    643: AppReg()
                    644: {
                    645:        DoWriteReg(YES);
                    646: }
                    647: 
                    648: int    CreatMode = DFLT_MODE;
                    649: 
                    650: private void
                    651: DoWriteReg(app)
                    652: int    app;
                    653: {
                    654:        char    fnamebuf[FILESIZE],
                    655:                *fname;
                    656:        Mark    *mp = CurMark();
                    657:        File    *fp;
                    658: 
                    659:        /* Won't get here if there isn't a Mark */
                    660:        fname = ask_file((char *) 0, (char *) 0, fnamebuf);
                    661: 
                    662: #ifdef BACKUPFILES
                    663:        if (app == NO) {
                    664:                filemunge(fname);
                    665: 
                    666:                if (BkupOnWrite)
                    667:                        file_backup(fname);
                    668:        }
                    669: #else
                    670:        if (!app)
                    671:                filemunge(fname);
                    672: #endif
                    673: 
                    674:        fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
                    675:        putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
                    676:        close_file(fp);
                    677: }
                    678: 
                    679: int    OkayBadChars = 0;
                    680: 
                    681: void
                    682: WriteFile()
                    683: {
                    684:        char    *fname,
                    685:                fnamebuf[FILESIZE];
                    686: #ifdef MAC
                    687:        if (Macmode) {
                    688:                if(!(fname = pfile(fnamebuf))) return;
                    689:        }
                    690:        else
                    691: #endif /* MAC */
                    692: 
                    693:        fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
                    694:        /* Don't allow bad characters when creating new files. */
                    695:        if (!OkayBadChars
                    696:        && (curbuf->b_fname==NIL || strcmp(curbuf->b_fname, fnamebuf) != 0))
                    697:        {
                    698: #ifdef UNIX
                    699:                static char     *badchars = "!$^&*()~`{}\"'\\|<>? ";
                    700: #endif /* UNIX */
                    701: #ifdef MSDOS
                    702:                static char     *badchars = "*|<>? ";
                    703: #endif /* MSDOS */
                    704: #ifdef MAC
                    705:                static char *badchars = ":";
                    706: #endif /* MAC */
                    707:                register char   *cp = fnamebuf;
                    708:                register int    c;
                    709: 
                    710:                while ((c = *cp++ & CHARMASK) != '\0')  /* avoid sign extension... */
                    711:                        if (c < ' ' || c == '\177' || strchr(badchars, c))
                    712:                                complain("'%p': bad character in filename.", c);
                    713:        }
                    714: 
                    715: #if !defined(MAC) && !defined(MSDOS)
                    716:        chk_mtime(curbuf, fname, "write");
                    717: #endif
                    718:        filemunge(fname);
                    719:        curbuf->b_type = B_FILE;        /* in case it wasn't before */
                    720:        setfname(curbuf, fname);
                    721:        file_write(fname, 0);
                    722: }
                    723: 
                    724: /* Open file FNAME supplying the buffer IO routine with buffer BUF.
                    725:    HOW is F_READ, F_WRITE or F_APPEND.  IFBAD == COMPLAIN means that
                    726:    if we fail at opening the file, call complain.  LOUDNESS says
                    727:    whether or not to print the "reading ..." message on the message
                    728:    line.
                    729: 
                    730:    NOTE:  This opens the pr_name(fname, NO) of fname.  That is, FNAME
                    731:          is usually an entire pathname, which can be slow when the
                    732:          pathname is long and there are lots of symbolic links along
                    733:          the way (which has become very common in my experience).  So,
                    734:          this speeds up opens file names in the local directory.  It
                    735:          will not speed up things like "../scm/foo.scm" simple because
                    736:          by the time we get here that's already been expanded to an
                    737:          absolute pathname.  But this is a start.
                    738:    */
                    739: 
                    740: File *
                    741: open_file(fname, buf, how, complainifbad, quiet)
                    742: register char  *fname;
                    743: char   *buf;
                    744: register int   how;
                    745: int    complainifbad,
                    746:        quiet;
                    747: {
                    748:        register File   *fp;
                    749: 
                    750:        io_chars = 0;
                    751:        io_lines = 0;
                    752: 
                    753:        fp = f_open(pr_name(fname, NO), how, buf, LBSIZE);
                    754:        if (fp == NIL) {
                    755:                message(IOerr((how == F_READ) ? "open" : "create", fname));
                    756:                if (complainifbad)
                    757:                        complain((char *) 0);
                    758:        } else {
                    759:                int     rd_only = FALSE;
                    760: #ifndef MAC
                    761:                if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) {
                    762:                        rd_only = TRUE;
                    763:                        fp->f_flags |= F_READONLY;
                    764:                }
                    765: #endif
                    766:                if (!quiet) {
                    767:                        fp->f_flags |= F_TELLALL;
                    768:                        f_mess("\"%s\"%s", pr_name(fname, YES),
                    769:                                   rd_only ? " [Read only]" : NullStr);
                    770:                }
                    771:        }
                    772:        return fp;
                    773: }
                    774: 
                    775: #ifndef MSDOS
                    776: /* Check to see if the file has been modified since it was
                    777:    last written.  If so, make sure they know what they're
                    778:    doing.
                    779: 
                    780:    I hate to use another stat(), but to use confirm we gotta
                    781:    do this before we open the file.
                    782: 
                    783:    NOTE: This stats FNAME after converting it to a path-relative
                    784:         name.  I can't see why this would cause a problem ...
                    785:    */
                    786: 
                    787: void
                    788: chk_mtime(thisbuf, fname, how)
                    789: Buffer *thisbuf;
                    790: char   *fname,
                    791:        *how;
                    792: {
                    793:        struct stat     stbuf;
                    794:        Buffer  *b;
                    795:        char    *mesg = "Shall I go ahead and %s anyway? ";
                    796: 
                    797:        if ((thisbuf->b_mtime != 0) &&          /* if we care ... */
                    798:            ((b = file_exists(fname)) != NIL) &&                /* we already have this file */
                    799:            (b == thisbuf) &&                   /* and it's the current buffer */
                    800:            (stat(pr_name(fname, NO), &stbuf) != -1) && /* and we can stat it */
                    801:            (stbuf.st_mtime != b->b_mtime)) {   /* and there's trouble. */
                    802:                rbell();
                    803:                redisplay();    /* Ring that bell! */
                    804:                TOstart("Warning", TRUE);
                    805:                Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES));
                    806:                Typeout("visited or saved.  Probably someone else is editing");
                    807:                Typeout("your file at the same time.");
                    808:                if (how) {
                    809:                        Typeout("");
                    810:                        Typeout("Type \"y\" if I should %s, anyway.", how);
                    811:                        f_mess(mesg, how);
                    812:                }
                    813:                TOstop();
                    814:                if (how)
                    815:                        confirm(mesg, how);
                    816:        }
                    817: }
                    818: 
                    819: #endif /* MSDOS */
                    820: 
                    821: void
                    822: file_write(fname, app)
                    823: char   *fname;
                    824: int    app;
                    825: {
                    826:        File    *fp;
                    827: 
                    828: #ifdef BACKUPFILES
                    829:        if (!app && BkupOnWrite)
                    830:                file_backup(fname);
                    831: #endif
                    832: 
                    833:        fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
                    834: 
                    835:        if (EndWNewline) {      /* Make sure file ends with a newLine */
                    836:                Bufpos  save;
                    837: 
                    838:                DOTsave(&save);
                    839:                ToLast();
                    840:                if (length(curline))    /* Not a blank Line */
                    841:                        LineInsert(1);
                    842:                SetDot(&save);
                    843:        }
                    844:        putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
                    845:        close_file(fp);
                    846:        set_ino(curbuf);
                    847:        unmodify();
                    848: }
                    849: 
                    850: void
                    851: ReadFile()
                    852: {
                    853:        Buffer  *bp;
                    854:        char    *fname,
                    855:                fnamebuf[FILESIZE];
                    856:        int     lineno;
                    857: 
                    858: #ifdef MAC
                    859:        if(Macmode) {
                    860:                if(!(fname = gfile(fnamebuf))) return;
                    861:        }
                    862:        else
                    863: #endif /* MAC */
                    864:        fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
                    865: #if !(defined(MSDOS) || defined(MAC))
                    866:        chk_mtime(curbuf, fname, "read");
                    867: #endif /* MSDOS || MAC */
                    868: 
                    869:        if (IsModified(curbuf)) {
                    870:                char    *y_or_n;
                    871:                int     c;
                    872: 
                    873:                for (;;) {
                    874:                        rbell();
                    875:                        y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
                    876:                        c = CharUpcase(*y_or_n);
                    877:                        if (c == 'Y' || c == 'N')
                    878:                                break;
                    879:                }
                    880:                if (c == 'Y')
                    881:                        SaveFile();
                    882:        }
                    883: 
                    884:        if ((bp = file_exists(fnamebuf)) != NIL &&
                    885:            (bp == curbuf))
                    886:                lineno = pnt_line() - 1;
                    887:        else
                    888:                lineno = 0;
                    889: 
                    890:        unmodify();
                    891:        initlist(curbuf);
                    892:        setfname(curbuf, fname);
                    893:        read_file(fname, 0);
                    894:        SetLine(next_line(curbuf->b_first, lineno));
                    895: }
                    896: 
                    897: void
                    898: InsFile()
                    899: {
                    900:        char    *fname,
                    901:                fnamebuf[FILESIZE];
                    902: #ifdef MAC
                    903:        if(Macmode) {
                    904:                if(!(fname = gfile(fnamebuf))) return;
                    905:        }
                    906:        else
                    907: #endif /* MAC */
                    908:        fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
                    909:        read_file(fname, 1);
                    910: }
                    911: 
                    912: #include "temp.h"
                    913: 
                    914: int    DOLsave = 0;    /* Do Lsave flag.  If lines aren't being saved
                    915:                           when you think they should have been, this
                    916:                           flag is probably not being set, or is being
                    917:                           cleared before lsave() was called. */
                    918: 
                    919: private int    nleft,  /* number of good characters left in current block */
                    920:                tmpfd = -1;
                    921: daddr  DFree = 1;  /* pointer to end of tmp file */
                    922: private char   *tfname;
                    923: 
                    924: void
                    925: tmpinit()
                    926: {
                    927:        char    buf[FILESIZE];
                    928: 
                    929: #ifdef MAC
                    930:        swritef(buf, "%s/%s", HomeDir, d_tempfile);
                    931: #else
                    932:        swritef(buf, "%s/%s", TmpFilePath, d_tempfile);
                    933: #endif
                    934:        tfname = copystr(buf);
                    935:        tfname = mktemp(tfname);
                    936:        (void) close(creat(tfname, 0600));
                    937: #ifndef MSDOS
                    938:        tmpfd = open(tfname, 2);
                    939: #else /* MSDOS */
                    940:        tmpfd = open(tfname, 0x8002);   /* MSDOS fix    */
                    941: #endif /* MSDOS */
                    942:        if (tmpfd == -1)
                    943:                complain("Warning: cannot create tmp file!");
                    944: }
                    945: 
                    946: void
                    947: tmpclose()
                    948: {
                    949:        if (tmpfd == -1)
                    950:                return;
                    951:        (void) close(tmpfd);
                    952:        tmpfd = -1;
                    953:        (void) unlink(tfname);
                    954: }
                    955: 
                    956: /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE
                    957:    long */
                    958: 
                    959: int    Jr_Len;         /* length of Just Read Line */
                    960: 
                    961: #ifdef MAC     /* The Lighspeed compiler can't copy with static here */
                    962:        char    *getblock();
                    963: #else
                    964: private char   *getblock();
                    965: #endif
                    966: void
                    967: getline(addr, buf)
                    968: daddr  addr;
                    969: register char  *buf;
                    970: {
                    971:        register char   *bp,
                    972:                        *lp;
                    973: 
                    974:        lp = buf;
                    975:        bp = getblock(addr >> 1, READ);
                    976:        do ; while ((*lp++ = *bp++) != '\0');
                    977:        Jr_Len = (lp - buf) - 1;
                    978: }
                    979: 
                    980: /* Put `buf' and return the disk address */
                    981: 
                    982: daddr
                    983: putline(buf)
                    984: char   *buf;
                    985: {
                    986:        register char   *bp,
                    987:                        *lp;
                    988:        register int    nl;
                    989:        daddr   free_ptr;
                    990: 
                    991:        lp = buf;
                    992:        free_ptr = DFree;
                    993:        bp = getblock(free_ptr, WRITE);
                    994:        nl = nleft;
                    995:        free_ptr = blk_round(free_ptr);
                    996:        while ((*bp = *lp++) != '\0') {
                    997:                if (*bp++ == '\n') {
                    998:                        *--bp = 0;
                    999:                        break;
                   1000:                }
                   1001:                if (--nl == 0) {
                   1002:                        free_ptr = forward_block(free_ptr);
                   1003:                        DFree = free_ptr;
                   1004:                        bp = getblock(free_ptr, WRITE);
                   1005:                        lp = buf;       /* start over ... */
                   1006:                        nl = nleft;
                   1007:                }
                   1008:        }
                   1009:        free_ptr = DFree;
                   1010:        DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
                   1011:                 /* (lp - buf) includes the null */
                   1012:        return (free_ptr << 1);
                   1013: }
                   1014: 
                   1015: /* The theory is that critical section of code inside this procedure
                   1016:    will never cause a problem to occur.  Basically, we need to ensure
                   1017:    that two blocks are in memory at the same time, but I think that
                   1018:    this can never screw up. */
                   1019: 
                   1020: #define lockblock(addr)
                   1021: #define unlockblock(addr)
                   1022: 
                   1023: daddr
                   1024: f_getputl(line, fp)
                   1025: Line   *line;
                   1026: register File  *fp;
                   1027: {
                   1028:        register char   *bp;
                   1029:        register int    c,
                   1030:                        nl,
                   1031:                        room = LBSIZE;
                   1032:        daddr   free_ptr;
                   1033:        char            *base;
                   1034: #ifdef MSDOS
                   1035:        char crleft = 0;
                   1036: #endif /* MSDOS */
                   1037: 
                   1038:        free_ptr = DFree;
                   1039:        base = bp = getblock(free_ptr, WRITE);
                   1040:        nl = nleft;
                   1041:        free_ptr = blk_round(free_ptr);
                   1042:        while (--room > 0) {
                   1043: #ifdef MSDOS
                   1044:                if (crleft) {
                   1045:                   c = crleft;
                   1046:                   crleft = 0;
                   1047:                } else
                   1048: #endif /* MSDOS */
                   1049:                c = jgetc(fp);
                   1050:                if (c == EOF || c == '\n')
                   1051:                        break;
                   1052: #ifdef MSDOS
                   1053:                if (c == '\r')
                   1054:                    if ((crleft = jgetc(fp)) == '\n') {
                   1055:                            crleft = 0;
                   1056:                            break;
                   1057:                        }
                   1058: #endif /* MSDOS */
                   1059:                if (--nl == 0) {
                   1060:                        char    *newbp;
                   1061:                        size_t  nbytes;
                   1062: 
                   1063:                        lockblock(free_ptr);
                   1064:                        DFree = free_ptr = forward_block(free_ptr);
                   1065:                        nbytes = bp - base;
                   1066:                        newbp = getblock(free_ptr, WRITE);
                   1067:                        nl = nleft;
                   1068:                        byte_copy(base, newbp, nbytes);
                   1069:                        bp = newbp + nbytes;
                   1070:                        base = newbp;
                   1071:                        unlockblock(free_ptr);
                   1072:                }
                   1073:                *bp++ = c;
                   1074:        }
                   1075:        *bp++ = '\0';
                   1076:        free_ptr = DFree;
                   1077:        DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
                   1078:        line->l_dline = (free_ptr << 1);
                   1079:        if (room == 0) {
                   1080:                add_mess(" [Line too long]");
                   1081:                rbell();
                   1082:                return EOF;
                   1083:        }
                   1084:        if (c == EOF) {
                   1085:                if (--bp != base)
                   1086:                        add_mess(" [Incomplete last line]");
                   1087:                return EOF;
                   1088:        }
                   1089:        io_lines += 1;
                   1090:        return 0;
                   1091: }
                   1092: 
                   1093: typedef struct block {
                   1094:        short   b_dirty,
                   1095:                b_bno;
                   1096:        char    b_buf[JBUFSIZ];
                   1097:        struct block
                   1098:                *b_LRUnext,
                   1099:                *b_LRUprev,
                   1100:                *b_HASHnext;
                   1101: } Block;
                   1102: 
                   1103: #define HASHSIZE       7       /* Primes work best (so I'm told) */
                   1104: #define B_HASH(bno)    ((bno) % HASHSIZE)
                   1105: 
                   1106: #ifdef MAC
                   1107: private Block  *b_cache,
                   1108: #else
                   1109: private Block  b_cache[NBUF],
                   1110: #endif
                   1111:                *bht[HASHSIZE],         /* Block hash table. Must be zero initially */
                   1112:                *f_block = 0,
                   1113:                *l_block = 0;
                   1114: private int    max_bno = -1,
                   1115:                NBlocks;
                   1116: 
                   1117: #ifdef MAC
                   1118: void (*blkio)();
                   1119: #else
                   1120: private void   (*blkio) proto((Block *, int (*)()));
                   1121: #endif /* MAC */
                   1122: 
                   1123: #ifdef MAC
                   1124: make_cache()   /* Only 32K of static space on Mac, so... */
                   1125: {
                   1126:        return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1);
                   1127: }
                   1128: #endif /* MAC */
                   1129: 
                   1130: extern int read(), write();
                   1131: 
                   1132: private void
                   1133: real_blkio(b, iofcn)
                   1134: register Block *b;
                   1135: #if defined(MAC) || defined(IBMPC)
                   1136: register int   (*iofcn)();
                   1137: #else
                   1138: register int   (*iofcn) proto((int, UnivPtr, size_t));
                   1139: #endif /* MAC */
                   1140: {
                   1141:        (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * JBUFSIZ, 0);
                   1142:        if ((*iofcn)(tmpfd, b->b_buf, (size_t)JBUFSIZ) != JBUFSIZ)
                   1143:                error("[Tmp file %s error; to continue editing would be dangerous]",
                   1144:                        (iofcn == read) ? "READ" : "WRITE");
                   1145: }
                   1146: 
                   1147: private void
                   1148: fake_blkio(b, iofcn)
                   1149: register Block *b;
                   1150: register int   (*iofcn)();
                   1151: {
                   1152:        tmpinit();
                   1153:        blkio = real_blkio;
                   1154:        real_blkio(b, iofcn);
                   1155: }
                   1156: 
                   1157: void
                   1158: d_cache_init()
                   1159: {
                   1160:        register Block  *bp,    /* Block pointer */
                   1161:                        **hp;   /* Hash pointer */
                   1162:        register short  bno;
                   1163: 
                   1164:        for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
                   1165:                NBlocks += 1;
                   1166:                bp->b_dirty = 0;
                   1167:                bp->b_bno = bno;
                   1168:                if (l_block == 0)
                   1169:                        l_block = bp;
                   1170:                bp->b_LRUprev = 0;
                   1171:                bp->b_LRUnext = f_block;
                   1172:                if (f_block != 0)
                   1173:                        f_block->b_LRUprev = bp;
                   1174:                f_block = bp;
                   1175: 
                   1176:                bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
                   1177:                *hp = bp;
                   1178:        }
                   1179:        blkio = fake_blkio;
                   1180: }
                   1181: 
                   1182: void
                   1183: SyncTmp()
                   1184: {
                   1185:        register Block  *b;
                   1186: #ifdef IBMPC
                   1187:        register int    bno = 0;
                   1188: 
                   1189:        /* sync the blocks in order, for file systems that don't allow
                   1190:           holes (MSDOS).  Perhaps this benefits floppy-based file systems. */
                   1191: 
                   1192:        for (bno = 0; bno <= max_bno; ) {
                   1193:                if ((b = lookup(bno++)) && b->b_dirty) {
                   1194:                        (*blkio)(b, write);
                   1195:                        b->b_dirty = 0;
                   1196:                }
                   1197:        }
                   1198: #else
                   1199:        for (b = f_block; b != 0; b = b->b_LRUnext)
                   1200:                if (b->b_dirty) {
                   1201:                        (*blkio)(b, write);
                   1202:                        b->b_dirty = 0;
                   1203:                }
                   1204: #endif
                   1205: }
                   1206: 
                   1207: private Block *
                   1208: lookup(bno)
                   1209: register short bno;
                   1210: {
                   1211:        register Block  *bp;
                   1212: 
                   1213:        for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
                   1214:                if (bp->b_bno == bno)
                   1215:                        break;
                   1216:        return bp;
                   1217: }
                   1218: 
                   1219: private void
                   1220: LRUunlink(b)
                   1221: register Block *b;
                   1222: {
                   1223:        if (b->b_LRUprev == 0)
                   1224:                f_block = b->b_LRUnext;
                   1225:        else
                   1226:                b->b_LRUprev->b_LRUnext = b->b_LRUnext;
                   1227:        if (b->b_LRUnext == 0)
                   1228:                l_block = b->b_LRUprev;
                   1229:        else
                   1230:                b->b_LRUnext->b_LRUprev = b->b_LRUprev;
                   1231: }
                   1232: 
                   1233: private Block *
                   1234: b_unlink(bp)
                   1235: register Block *bp;
                   1236: {
                   1237:        register Block  *hp,
                   1238:                        *prev = 0;
                   1239: 
                   1240:        LRUunlink(bp);
                   1241:        /* Now that we have the block, we remove it from its position
                   1242:           in the hash table, so we can THEN put it somewhere else with
                   1243:           it's new block assignment. */
                   1244: 
                   1245:        for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
                   1246:                if (hp == bp)
                   1247:                        break;
                   1248:        if (hp == 0) {
                   1249:                writef("\rBlock %d missing!", bp->b_bno);
                   1250:                finish(0);
                   1251:        }
                   1252:        if (prev)
                   1253:                prev->b_HASHnext = hp->b_HASHnext;
                   1254:        else
                   1255:                bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
                   1256: 
                   1257:        if (bp->b_dirty) {      /* do, now, the delayed write */
                   1258:                (*blkio)(bp, write);
                   1259:                bp->b_dirty = 0;
                   1260:        }
                   1261: 
                   1262:        return bp;
                   1263: }
                   1264: 
                   1265: /* Get a block which contains at least part of the line with the address
                   1266:    atl.  Returns a pointer to the block and sets the global variable
                   1267:    nleft (number of good characters left in the buffer). */
                   1268: 
                   1269: private char *
                   1270: getblock(atl, iof)
                   1271: daddr  atl;
                   1272: int    iof;
                   1273: {
                   1274:        register int    bno,
                   1275:                        off;
                   1276:        register Block  *bp;
                   1277:        static Block    *lastb = 0;
                   1278: 
                   1279:        bno = da_to_bno(atl);
                   1280:        off = da_to_off(atl);
                   1281:        if (da_too_huge(atl))
                   1282:                error("Tmp file too large.  Get help!");
                   1283:        nleft = JBUFSIZ - off;
                   1284:        if (lastb != 0 && lastb->b_bno == bno) {
                   1285:                lastb->b_dirty |= iof;
                   1286:                return lastb->b_buf + off;
                   1287:        }
                   1288: 
                   1289:        /* The requested block already lives in memory, so we move
                   1290:           it to the end of the LRU list (making it Most Recently Used)
                   1291:           and then return a pointer to it. */
                   1292:        if ((bp = lookup(bno)) != NIL) {
                   1293:                if (bp != l_block) {
                   1294:                        LRUunlink(bp);
                   1295:                        if (l_block == 0)
                   1296:                                f_block = l_block = bp;
                   1297:                        else
                   1298:                                l_block->b_LRUnext = bp;
                   1299:                        bp->b_LRUprev = l_block;
                   1300:                        l_block = bp;
                   1301:                        bp->b_LRUnext = 0;
                   1302:                }
                   1303:                if (bp->b_bno > max_bno)
                   1304:                        max_bno = bp->b_bno;
                   1305:                bp->b_dirty |= iof;
                   1306:                lastb = bp;
                   1307:                return bp->b_buf + off;
                   1308:        }
                   1309: 
                   1310:        /* The block we want doesn't reside in memory so we take the
                   1311:           least recently used clean block (if there is one) and use
                   1312:           it.  */
                   1313:        bp = f_block;
                   1314:        if (bp->b_dirty)        /* The best block is dirty ... */
                   1315:                SyncTmp();
                   1316: 
                   1317:        bp = b_unlink(bp);
                   1318:        if (l_block == 0)
                   1319:                l_block = f_block = bp;
                   1320:        else
                   1321:                l_block->b_LRUnext = bp;        /* Place it at the end ... */
                   1322:        bp->b_LRUprev = l_block;
                   1323:        l_block = bp;
                   1324:        bp->b_LRUnext = 0;              /* so it's Most Recently Used */
                   1325: 
                   1326:        bp->b_dirty = iof;
                   1327:        bp->b_bno = bno;
                   1328:        bp->b_HASHnext = bht[B_HASH(bno)];
                   1329:        bht[B_HASH(bno)] = bp;
                   1330: 
                   1331:        /* Get the current contents of the block UNLESS this is a new
                   1332:           block that's never been looked at before, i.e., it's past
                   1333:           the end of the tmp file. */
                   1334: 
                   1335:        if (bp->b_bno <= max_bno)
                   1336:                (*blkio)(bp, read);
                   1337:        else
                   1338:                max_bno = bno;
                   1339: 
                   1340:        lastb = bp;
                   1341:        return bp->b_buf + off;
                   1342: }
                   1343: 
                   1344: char *
                   1345: lbptr(line)
                   1346: Line   *line;
                   1347: {
                   1348:        return getblock(line->l_dline >> 1, READ);
                   1349: }
                   1350: 
                   1351: /* save the current contents of linebuf, if it has changed */
                   1352: 
                   1353: void
                   1354: lsave()
                   1355: {
                   1356:        if (curbuf == 0 || !DOLsave)    /* Nothing modified recently */
                   1357:                return;
                   1358: 
                   1359:        if (strcmp(lbptr(curline), linebuf) != 0)
                   1360:                SavLine(curline, linebuf);      /* Put linebuf on the disk. */
                   1361:        DOLsave = 0;
                   1362: }
                   1363: 
                   1364: #ifdef BACKUPFILES
                   1365: private void
                   1366: file_backup(fname)
                   1367: char *fname;
                   1368: {
                   1369: #ifndef MSDOS
                   1370:        char    *s;
                   1371:        register int    i;
                   1372:        int     fd1,
                   1373:                fd2;
                   1374:        char    tmp1[JBUFSIZ],
                   1375:                tmp2[JBUFSIZ];
                   1376:        struct stat buf;
                   1377:        int     mode;
                   1378: 
                   1379:        strcpy(tmp1, fname);
                   1380:        if ((s = strrchr(tmp1, '/')) == NULL)
                   1381:                swritef(tmp2, "#%s~", fname);
                   1382:        else {
                   1383:                *s++ = '\0';
                   1384:                swritef(tmp2, "%s/#%s~", tmp1, s);
                   1385:        }
                   1386: 
                   1387:        if ((fd1 = open(fname, 0)) < 0)
                   1388:                return;
                   1389: 
                   1390:        /* create backup file with same mode as input file */
                   1391: #ifndef MAC
                   1392:        if (fstat(fd1, &buf) != 0)
                   1393:                mode = CreatMode;
                   1394:        else
                   1395: #endif
                   1396:                mode = buf.st_mode;
                   1397: 
                   1398:        if ((fd2 = creat(tmp2, mode)) < 0) {
                   1399:                (void) close(fd1);
                   1400:                return;
                   1401:        }
                   1402:        while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
                   1403:                write(fd2, tmp1, (size_t) i);
                   1404: #ifdef BSD4_2
                   1405:        (void) fsync(fd2);
                   1406: #endif
                   1407:        (void) close(fd2);
                   1408:        (void) close(fd1);
                   1409: #else /* MSDOS */
                   1410:        char    *dot,
                   1411:                        *slash,
                   1412:                        tmp[FILESIZE];
                   1413: 
                   1414:        strcpy(tmp, fname);
                   1415:        slash = basename(tmp);
                   1416:        if (dot = strrchr(slash, '.')) {
                   1417:           if (!stricmp(dot,".bak"))
                   1418:                return;
                   1419:           else *dot = 0;
                   1420:        }
                   1421:        strcat(tmp, ".bak");
                   1422:        unlink(tmp);
                   1423:        rename(fname, tmp);
                   1424: #endif /* MSDOS */
                   1425: }
                   1426: #endif
                   1427: 
                   1428: #if defined(MSDOS)
                   1429: 
                   1430: private int                    /* chdir + drive */
                   1431: Dchdir(to)
                   1432: char *to;
                   1433: {
                   1434:        unsigned d, dd, n;
                   1435: 
                   1436:        if (to[1] == ':') {
                   1437:                d = to[0];
                   1438:                if (d >= 'a') d = d - 'a' + 1;
                   1439:                if (d >= 'A') d = d - 'A' + 1;
                   1440:                _dos_getdrive(&dd);
                   1441:                if (dd != d)
                   1442:                        _dos_setdrive(d, &n);
                   1443:                if (to[2] == 0)
                   1444:                        return 0;
                   1445:        }
                   1446:        return chdir(to);
                   1447: }
                   1448: 
                   1449: private char *
                   1450: fixpath(p)
                   1451: char *p;
                   1452: {
                   1453:        char *pp = p;
                   1454: 
                   1455:        while (*p) {
                   1456:                if (*p == '\\')
                   1457:                        *p = '/';
                   1458:                p++;
                   1459:        }
                   1460:        return(strlwr(pp));
                   1461: }
                   1462: 
                   1463: 
                   1464: private void
                   1465: abspath(so, dest)
                   1466: char *so, *dest;
                   1467: {
                   1468:        char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5],
                   1469:             soD[3], soDIR[FILESIZE], soF[9], soEXT[5];
                   1470:        char *drive, *path;
                   1471: 
                   1472:        _splitpath(fixpath(so), soD, soDIR, soF, soEXT);
                   1473:        getcwd(cwd, FILESIZE);
                   1474:        if (*soD != 0) {
                   1475:                Dchdir(soD);                            /* this is kinda messy  */
                   1476:                getcwd(cwdDIR, FILESIZE);       /* should probably just */
                   1477:                Dchdir(cwd);                            /* call DOS to do it    */
                   1478:                strcpy(cwd, cwdDIR);
                   1479:        }
                   1480:        (void) fixpath(cwd);
                   1481:        if (cwd[strlen(cwd)-1] != '/')
                   1482:                strcat(cwd, "/x.x");    /* need dummy filename */
                   1483: 
                   1484:        _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT);
                   1485: 
                   1486:        drive = (*soD == 0) ? cwdD : soD;
                   1487: 
                   1488:        if (*soDIR != '/')
                   1489:                path = strcat(cwdDIR, soDIR);
                   1490:        else
                   1491:                path = soDIR;
                   1492:        _makepath(dest, drive, path, soF, soEXT);
                   1493:        fixpath(dest);  /* can't do it often enough */
                   1494: }
                   1495: 
                   1496: #endif

unix.superglobalmegacorp.com

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