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