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

Defined functions

AppReg defined in line 454; used 2 times
Chdir defined in line 209; used 2 times
DoWriteReg defined in line 461; used 2 times
InsFile defined in line 634; used 2 times
LRUunlink defined in line 801; used 2 times
PathParse defined in line 398; used 5 times
Popd defined in line 314; used 2 times
Pushd defined in line 284; used 2 times
ReadFile defined in line 605; used 2 times
SaveFile defined in line 134; used 4 times
SyncTmp defined in line 942; used 2 times
WriteFile defined in line 490; used 3 times
WrtReg defined in line 449; used 2 times
b_unlink defined in line 815; used 1 times
blkio defined in line 932; used 3 times
block_init defined in line 765; used 1 times
chk_mtime defined in line 553; used 3 times
close_file defined in line 40; used 6 times
dbackup defined in line 326; used 1 times
dfollow defined in line 337; used 1 times
dofread defined in line 113; used 1 times
file_backup defined in line 966; used 2 times
file_write defined in line 579; used 4 times
filemunge defined in line 432; used 4 times
getCWD defined in line 252; used 1 times
get_hdir defined in line 375; used 1 times
getblock defined in line 851; used 5 times
getline defined in line 681; never used
getwd defined in line 223; used 3 times
lbptr defined in line 925; used 7 times
lookup defined in line 789; used 1 times
prCWD defined in line 279; used 2 times
prDIRS defined in line 270; used 4 times
putline defined in line 712; used 7 times
putreg defined in line 57; used 3 times
pwd defined in line 179; used 2 times
read_file defined in line 86; used 4 times
setCWD defined in line 239; used 4 times
tmpclose defined in line 669; used 1 times
tmpinit defined in line 656; used 1 times

Defined variables

BkupOnWrite defined in line 37; used 3 times
CreatMode defined in line 459; used 2 times
DOLsave defined in line 645; used 2 times
DirSP defined in line 176; used 10 times
DirStack defined in line 175; used 5 times
EndWNewline defined in line 55; used 2 times
HomeDir defined in line 149; used 4 times
HomeLen defined in line 150; used 4 times
Jr_Len defined in line 679; used 2 times
OkayBadChars defined in line 488; used 2 times
b_cache defined in line 758; used 1 times
bht defined in line 759; used 6 times
genbuf defined in line 32; used 5 times
io_chars defined in line 22; used 5 times
io_lines defined in line 23; used 3 times
iobuff defined in line 31; used 7 times
max_bno defined in line 762; used 4 times
nleft defined in line 650; used 5 times
nretries defined in line 710; used 1 times
tellall defined in line 24; used 2 times
tfname defined in line 654; used 5 times
tline defined in line 652; used 5 times
tmpfd defined in line 651; used 6 times

Defined struct's

block defined in line 745; used 2 times
  • in line 749(2)

Defined typedef's

Block defined in line 753; used 12 times

Defined macros

B_HASH defined in line 756; used 6 times
HASHSIZE defined in line 755; used 2 times
NDIRS defined in line 173; used 3 times
PWD defined in line 177; used 16 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3293
Valid CSS Valid XHTML 1.0 Strict