1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char *sccsid = "@(#)ex_temp.c 7.5.1.1 (Berkeley) 8/12/86"; 9: #endif 10: 11: #include "ex.h" 12: #include "ex_temp.h" 13: #include "ex_vis.h" 14: #include "ex_tty.h" 15: 16: /* 17: * Editor temporary file routines. 18: * Very similar to those of ed, except uses 2 input buffers. 19: */ 20: #define READ 0 21: #define WRITE 1 22: 23: char tfname[40]; 24: char rfname[40]; 25: int havetmp; 26: short tfile = -1; 27: short rfile = -1; 28: 29: fileinit() 30: { 31: register char *p; 32: register int i, j; 33: struct stat stbuf; 34: 35: if (tline == INCRMT * (HBLKS+2)) 36: return; 37: cleanup(0); 38: close(tfile); 39: tline = INCRMT * (HBLKS+2); 40: blocks[0] = HBLKS; 41: blocks[1] = HBLKS+1; 42: blocks[2] = -1; 43: dirtcnt = 0; 44: iblock = -1; 45: iblock2 = -1; 46: oblock = -1; 47: CP(tfname, svalue(DIRECTORY)); 48: if (stat(tfname, &stbuf)) { 49: dumbness: 50: if (setexit() == 0) 51: filioerr(tfname); 52: else 53: putNFL(); 54: cleanup(1); 55: exit(1); 56: } 57: if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { 58: errno = ENOTDIR; 59: goto dumbness; 60: } 61: ichanged = 0; 62: ichang2 = 0; 63: ignore(strcat(tfname, "/ExXXXXX")); 64: for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) 65: *--p = j % 10 | '0'; 66: tfile = creat(tfname, 0600); 67: if (tfile < 0) 68: goto dumbness; 69: #ifdef VMUNIX 70: { 71: extern stilinc; /* see below */ 72: stilinc = 0; 73: } 74: #endif 75: havetmp = 1; 76: close(tfile); 77: tfile = open(tfname, 2); 78: if (tfile < 0) 79: goto dumbness; 80: /* brk((char *)fendcore); */ 81: } 82: 83: cleanup(all) 84: bool all; 85: { 86: if (all) { 87: putpad(TE); 88: flush(); 89: } 90: if (havetmp) 91: unlink(tfname); 92: havetmp = 0; 93: if (all && rfile >= 0) { 94: unlink(rfname); 95: close(rfile); 96: rfile = -1; 97: } 98: } 99: 100: getline(tl) 101: line tl; 102: { 103: register char *bp, *lp; 104: register int nl; 105: 106: lp = linebuf; 107: bp = getblock(tl, READ); 108: nl = nleft; 109: tl &= ~OFFMSK; 110: while (*lp++ = *bp++) 111: if (--nl == 0) { 112: bp = getblock(tl += INCRMT, READ); 113: nl = nleft; 114: } 115: } 116: 117: putline() 118: { 119: register char *bp, *lp; 120: register int nl; 121: line tl; 122: 123: dirtcnt++; 124: lp = linebuf; 125: change(); 126: tl = tline; 127: bp = getblock(tl, WRITE); 128: nl = nleft; 129: tl &= ~OFFMSK; 130: while (*bp = *lp++) { 131: if (*bp++ == '\n') { 132: *--bp = 0; 133: linebp = lp; 134: break; 135: } 136: if (--nl == 0) { 137: bp = getblock(tl += INCRMT, WRITE); 138: nl = nleft; 139: } 140: } 141: tl = tline; 142: tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 143: return (tl); 144: } 145: 146: int read(); 147: int write(); 148: 149: char * 150: getblock(atl, iof) 151: line atl; 152: int iof; 153: { 154: register int bno, off; 155: register char *p1, *p2; 156: register int n; 157: 158: bno = (atl >> OFFBTS) & BLKMSK; 159: off = (atl << SHFT) & LBTMSK; 160: if (bno >= NMBLKS) 161: error(" Tmp file too large"); 162: nleft = BUFSIZ - off; 163: if (bno == iblock) { 164: ichanged |= iof; 165: hitin2 = 0; 166: return (ibuff + off); 167: } 168: if (bno == iblock2) { 169: ichang2 |= iof; 170: hitin2 = 1; 171: return (ibuff2 + off); 172: } 173: if (bno == oblock) 174: return (obuff + off); 175: if (iof == READ) { 176: if (hitin2 == 0) { 177: if (ichang2) { 178: blkio(iblock2, ibuff2, write); 179: } 180: ichang2 = 0; 181: iblock2 = bno; 182: blkio(bno, ibuff2, read); 183: hitin2 = 1; 184: return (ibuff2 + off); 185: } 186: hitin2 = 0; 187: if (ichanged) { 188: blkio(iblock, ibuff, write); 189: } 190: ichanged = 0; 191: iblock = bno; 192: blkio(bno, ibuff, read); 193: return (ibuff + off); 194: } 195: if (oblock >= 0) { 196: blkio(oblock, obuff, write); 197: } 198: oblock = bno; 199: return (obuff + off); 200: } 201: 202: #ifdef VMUNIX 203: #define INCORB 64 204: char incorb[INCORB+1][BUFSIZ]; 205: #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1))) 206: int stilinc; /* up to here not written yet */ 207: #endif 208: 209: blkio(b, buf, iofcn) 210: short b; 211: char *buf; 212: int (*iofcn)(); 213: { 214: 215: #ifdef VMUNIX 216: if (b < INCORB) { 217: if (iofcn == read) { 218: bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ); 219: return; 220: } 221: bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ); 222: if (laste) { 223: if (b >= stilinc) 224: stilinc = b + 1; 225: return; 226: } 227: } else if (stilinc) 228: tflush(); 229: #endif 230: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); 231: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) 232: filioerr(tfname); 233: } 234: 235: #ifdef VMUNIX 236: tlaste() 237: { 238: 239: if (stilinc) 240: dirtcnt = 0; 241: } 242: 243: tflush() 244: { 245: int i = stilinc; 246: 247: stilinc = 0; 248: lseek(tfile, (long) 0, 0); 249: if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ)) 250: filioerr(tfname); 251: } 252: #endif 253: 254: /* 255: * Synchronize the state of the temporary file in case 256: * a crash occurs. 257: */ 258: synctmp() 259: { 260: register int cnt; 261: register line *a; 262: register short *bp; 263: 264: #ifdef VMUNIX 265: if (stilinc) 266: return; 267: #endif 268: if (dol == zero) 269: return; 270: if (ichanged) 271: blkio(iblock, ibuff, write); 272: ichanged = 0; 273: if (ichang2) 274: blkio(iblock2, ibuff2, write); 275: ichang2 = 0; 276: if (oblock != -1) 277: blkio(oblock, obuff, write); 278: time(&H.Time); 279: uid = getuid(); 280: *zero = (line) H.Time; 281: for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { 282: if (*bp < 0) { 283: tline = (tline + OFFMSK) &~ OFFMSK; 284: *bp = ((tline >> OFFBTS) & BLKMSK); 285: if (*bp > NMBLKS) 286: error(" Tmp file too large"); 287: tline += INCRMT; 288: oblock = *bp + 1; 289: bp[1] = -1; 290: } 291: lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); 292: cnt = ((dol - a) + 2) * sizeof (line); 293: if (cnt > BUFSIZ) 294: cnt = BUFSIZ; 295: if (write(tfile, (char *) a, cnt) != cnt) { 296: oops: 297: *zero = 0; 298: filioerr(tfname); 299: } 300: *zero = 0; 301: } 302: flines = lineDOL(); 303: lseek(tfile, 0l, 0); 304: if (write(tfile, (char *) &H, sizeof H) != sizeof H) 305: goto oops; 306: #ifdef notdef 307: /* 308: * This will insure that exrecover gets as much 309: * back after a crash as is absolutely possible, 310: * but can result in pregnant pauses between commands 311: * when the TSYNC call is made, so... 312: */ 313: (void) fsync(tfile); 314: #endif 315: } 316: 317: TSYNC() 318: { 319: 320: if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */ 321: #ifdef VMUNIX 322: if (stilinc) 323: tflush(); 324: #endif 325: dirtcnt = 0; 326: synctmp(); 327: } 328: } 329: 330: /* 331: * Named buffer routines. 332: * These are implemented differently than the main buffer. 333: * Each named buffer has a chain of blocks in the register file. 334: * Each block contains roughly 508 chars of text, 335: * and a previous and next block number. We also have information 336: * about which blocks came from deletes of multiple partial lines, 337: * e.g. deleting a sentence or a LISP object. 338: * 339: * We maintain a free map for the temp file. To free the blocks 340: * in a register we must read the blocks to find how they are chained 341: * together. 342: * 343: * BUG: The default savind of deleted lines in numbered 344: * buffers may be rather inefficient; it hasn't been profiled. 345: */ 346: struct strreg { 347: short rg_flags; 348: short rg_nleft; 349: short rg_first; 350: short rg_last; 351: } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 352: 353: struct rbuf { 354: short rb_prev; 355: short rb_next; 356: char rb_text[BUFSIZ - 2 * sizeof (short)]; 357: } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; 358: #ifdef VMUNIX 359: short rused[256]; 360: #else 361: short rused[32]; 362: #endif 363: short rnleft; 364: short rblock; 365: short rnext; 366: char *rbufcp; 367: 368: regio(b, iofcn) 369: short b; 370: int (*iofcn)(); 371: { 372: 373: if (rfile == -1) { 374: CP(rfname, tfname); 375: *(strend(rfname) - 7) = 'R'; 376: rfile = creat(rfname, 0600); 377: if (rfile < 0) 378: oops: 379: filioerr(rfname); 380: close(rfile); 381: rfile = open(rfname, 2); 382: if (rfile < 0) 383: goto oops; 384: } 385: lseek(rfile, (long) b * BUFSIZ, 0); 386: if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) 387: goto oops; 388: rblock = b; 389: } 390: 391: REGblk() 392: { 393: register int i, j, m; 394: 395: for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { 396: m = (rused[i] ^ 0177777) & 0177777; 397: if (i == 0) 398: m &= ~1; 399: if (m != 0) { 400: j = 0; 401: while ((m & 1) == 0) 402: j++, m >>= 1; 403: rused[i] |= (1 << j); 404: #ifdef RDEBUG 405: printf("allocating block %d\n", i * 16 + j); 406: #endif 407: return (i * 16 + j); 408: } 409: } 410: error("Out of register space (ugh)"); 411: /*NOTREACHED*/ 412: } 413: 414: struct strreg * 415: mapreg(c) 416: register int c; 417: { 418: 419: if (isupper(c)) 420: c = tolower(c); 421: return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 422: } 423: 424: int shread(); 425: 426: KILLreg(c) 427: register int c; 428: { 429: register struct strreg *sp; 430: 431: rbuf = &KILLrbuf; 432: sp = mapreg(c); 433: rblock = sp->rg_first; 434: sp->rg_first = sp->rg_last = 0; 435: sp->rg_flags = sp->rg_nleft = 0; 436: while (rblock != 0) { 437: #ifdef RDEBUG 438: printf("freeing block %d\n", rblock); 439: #endif 440: rused[rblock / 16] &= ~(1 << (rblock % 16)); 441: regio(rblock, shread); 442: rblock = rbuf->rb_next; 443: } 444: } 445: 446: /*VARARGS*/ 447: shread() 448: { 449: struct front { short a; short b; }; 450: 451: if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 452: return (sizeof (struct rbuf)); 453: return (0); 454: } 455: 456: int getREG(); 457: 458: putreg(c) 459: char c; 460: { 461: register line *odot = dot; 462: register line *odol = dol; 463: register int cnt; 464: 465: deletenone(); 466: appendnone(); 467: rbuf = &putrbuf; 468: rnleft = 0; 469: rblock = 0; 470: rnext = mapreg(c)->rg_first; 471: if (rnext == 0) { 472: if (inopen) { 473: splitw++; 474: vclean(); 475: vgoto(WECHO, 0); 476: } 477: vreg = -1; 478: error("Nothing in register %c", c); 479: } 480: if (inopen && partreg(c)) { 481: if (!FIXUNDO) { 482: splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 483: error("Can't put partial line inside macro"); 484: } 485: squish(); 486: addr1 = addr2 = dol; 487: } 488: cnt = append(getREG, addr2); 489: if (inopen && partreg(c)) { 490: unddol = dol; 491: dol = odol; 492: dot = odot; 493: pragged(0); 494: } 495: killcnt(cnt); 496: notecnt = cnt; 497: } 498: 499: partreg(c) 500: char c; 501: { 502: 503: return (mapreg(c)->rg_flags); 504: } 505: 506: notpart(c) 507: register int c; 508: { 509: 510: if (c) 511: mapreg(c)->rg_flags = 0; 512: } 513: 514: getREG() 515: { 516: register char *lp = linebuf; 517: register int c; 518: 519: for (;;) { 520: if (rnleft == 0) { 521: if (rnext == 0) 522: return (EOF); 523: regio(rnext, read); 524: rnext = rbuf->rb_next; 525: rbufcp = rbuf->rb_text; 526: rnleft = sizeof rbuf->rb_text; 527: } 528: c = *rbufcp; 529: if (c == 0) 530: return (EOF); 531: rbufcp++, --rnleft; 532: if (c == '\n') { 533: *lp++ = 0; 534: return (0); 535: } 536: *lp++ = c; 537: } 538: } 539: 540: YANKreg(c) 541: register int c; 542: { 543: register line *addr; 544: register struct strreg *sp; 545: char savelb[LBSIZE]; 546: 547: if (isdigit(c)) 548: kshift(); 549: if (islower(c)) 550: KILLreg(c); 551: strp = sp = mapreg(c); 552: sp->rg_flags = inopen && cursor && wcursor; 553: rbuf = &YANKrbuf; 554: if (sp->rg_last) { 555: regio(sp->rg_last, read); 556: rnleft = sp->rg_nleft; 557: rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 558: } else { 559: rblock = 0; 560: rnleft = 0; 561: } 562: CP(savelb,linebuf); 563: for (addr = addr1; addr <= addr2; addr++) { 564: getline(*addr); 565: if (sp->rg_flags) { 566: if (addr == addr2) 567: *wcursor = 0; 568: if (addr == addr1) 569: strcpy(linebuf, cursor); 570: } 571: YANKline(); 572: } 573: rbflush(); 574: killed(); 575: CP(linebuf,savelb); 576: } 577: 578: kshift() 579: { 580: register int i; 581: 582: KILLreg('9'); 583: for (i = '8'; i >= '0'; i--) 584: copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 585: } 586: 587: YANKline() 588: { 589: register char *lp = linebuf; 590: register struct rbuf *rp = rbuf; 591: register int c; 592: 593: do { 594: c = *lp++; 595: if (c == 0) 596: c = '\n'; 597: if (rnleft == 0) { 598: rp->rb_next = REGblk(); 599: rbflush(); 600: rblock = rp->rb_next; 601: rp->rb_next = 0; 602: rp->rb_prev = rblock; 603: rnleft = sizeof rp->rb_text; 604: rbufcp = rp->rb_text; 605: } 606: *rbufcp++ = c; 607: --rnleft; 608: } while (c != '\n'); 609: if (rnleft) 610: *rbufcp = 0; 611: } 612: 613: rbflush() 614: { 615: register struct strreg *sp = strp; 616: 617: if (rblock == 0) 618: return; 619: regio(rblock, write); 620: if (sp->rg_first == 0) 621: sp->rg_first = rblock; 622: sp->rg_last = rblock; 623: sp->rg_nleft = rnleft; 624: } 625: 626: /* Register c to char buffer buf of size buflen */ 627: regbuf(c, buf, buflen) 628: char c; 629: char *buf; 630: int buflen; 631: { 632: register char *p, *lp; 633: 634: rbuf = ®rbuf; 635: rnleft = 0; 636: rblock = 0; 637: rnext = mapreg(c)->rg_first; 638: if (rnext==0) { 639: *buf = 0; 640: error("Nothing in register %c",c); 641: } 642: p = buf; 643: while (getREG()==0) { 644: for (lp=linebuf; *lp;) { 645: if (p >= &buf[buflen]) 646: error("Register too long@to fit in memory"); 647: *p++ = *lp++; 648: } 649: *p++ = '\n'; 650: } 651: if (partreg(c)) p--; 652: *p = '\0'; 653: getDOT(); 654: } 655: 656: /* 657: * Encryption routines. These are essentially unmodified from ed. 658: */