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