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

Defined functions

AppReg defined in line 650; used 4 times
Chdir defined in line 309; used 2 times
Dchdir defined in line 1438; used 8 times
DoWriteReg defined in line 658; used 4 times
InsFile defined in line 898; used 4 times
LRUunlink defined in line 1228; used 4 times
Popd defined in line 448; used 2 times
Pushd defined in line 404; used 2 times
ReadFile defined in line 851; used 4 times
SaveFile defined in line 229; used 6 times
SyncTmp defined in line 1192; used 4 times
WriteFile defined in line 688; used 5 times
WrtReg defined in line 644; used 4 times
abspath defined in line 1472; used 3 times
b_unlink defined in line 1242; used 3 times
chk_mtime defined in line 791; used 4 times
d_cache_init defined in line 1167; used 3 times
dbackup defined in line 464; used 3 times
dfollow defined in line 475; used 3 times
dofread defined in line 206; used 3 times
f_getputl defined in line 1026; used 4 times
fake_blkio defined in line 1157; used 3 times
file_backup defined in line 1373; used 4 times
file_write defined in line 824; used 6 times
filemunge defined in line 619; used 7 times
fixpath defined in line 1457; used 7 times
getCWD defined in line 366; used 3 times
get_hdir defined in line 551; used 1 times
getblock defined in line 1278; used 10 times
getline defined in line 968; never used
getwd defined in line 336; used 2 times
lbptr defined in line 1352; used 8 times
lookup defined in line 1216; used 5 times
make_cache defined in line 1131; used 1 times
prCWD defined in line 399; used 3 times
prDIRS defined in line 390; used 4 times
putreg defined in line 143; used 5 times
pwd defined in line 277; used 4 times
read_file defined in line 177; used 6 times
real_blkio defined in line 1139; used 4 times
setCWD defined in line 353; used 5 times
tmpclose defined in line 948; used 3 times
tmpinit defined in line 926; used 3 times

Defined variables

BkupOnWrite defined in line 122; used 3 times
CreatMode defined in line 656; used 2 times
DFree defined in line 922; used 8 times
DOLsave defined in line 915; used 2 times
DirSP defined in line 274; used 10 times
DirStack defined in line 273; used 5 times
EndWNewline defined in line 141; used 2 times
HomeDir defined in line 247; used 6 times
HomeLen defined in line 248; used 4 times
Jr_Len defined in line 961; used 2 times
OkayBadChars defined in line 686; used 2 times
b_cache defined in line 1112; used 2 times
bht defined in line 1114; used 6 times
genbuf defined in line 117; used 6 times
io_chars defined in line 108; used 6 times
io_lines defined in line 109; used 4 times
iobuff defined in line 116; used 10 times
max_bno defined in line 1117; used 5 times
nleft defined in line 920; used 5 times
private defined in line 1216; never used
tfname defined in line 924; used 7 times
tmpfd defined in line 921; used 8 times

Defined struct's

block defined in line 1096; used 8 times

Defined typedef's

Block defined in line 1104; used 18 times

Defined macros

B_HASH defined in line 1107; used 6 times
F_OK defined in line 105; never used
HASHSIZE defined in line 1106; used 2 times
NDIRS defined in line 271; used 3 times
PWD defined in line 275; used 18 times
W_OK defined in line 104; used 2 times
lockblock defined in line 1023; used 1 times
private defined in line 99; used 31 times
unlockblock defined in line 1024; used 1 times
Last modified: 1988-08-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 380
Valid CSS Valid XHTML 1.0 Strict