1: /* Copyright (c) 1981 Regents of the University of California */ 2: static char *sccsid = "@(#)ex_temp.c 7.3 9/3/81"; 3: #include "ex.h" 4: #include "ex_temp.h" 5: #include "ex_vis.h" 6: #include "ex_tty.h" 7: 8: /* 9: * Editor temporary file routines. 10: * Very similar to those of ed, except uses 2 input buffers. 11: */ 12: #define READ 0 13: #define WRITE 1 14: 15: char tfname[40]; 16: char rfname[40]; 17: int havetmp; 18: short tfile = -1; 19: short rfile = -1; 20: 21: fileinit() 22: { 23: register char *p; 24: register int i, j; 25: struct stat stbuf; 26: 27: if (tline == INCRMT * (HBLKS+2)) 28: return; 29: cleanup(0); 30: close(tfile); 31: tline = INCRMT * (HBLKS+2); 32: blocks[0] = HBLKS; 33: blocks[1] = HBLKS+1; 34: blocks[2] = -1; 35: dirtcnt = 0; 36: iblock = -1; 37: iblock2 = -1; 38: oblock = -1; 39: CP(tfname, svalue(DIRECTORY)); 40: if (stat(tfname, &stbuf)) { 41: dumbness: 42: if (setexit() == 0) 43: filioerr(tfname); 44: else 45: putNFL(); 46: cleanup(1); 47: exit(1); 48: } 49: if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { 50: errno = ENOTDIR; 51: goto dumbness; 52: } 53: ichanged = 0; 54: ichang2 = 0; 55: ignore(strcat(tfname, "/ExXXXXX")); 56: for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) 57: *--p = j % 10 | '0'; 58: tfile = creat(tfname, 0600); 59: if (tfile < 0) 60: goto dumbness; 61: #ifdef VMUNIX 62: { 63: extern stilinc; /* see below */ 64: stilinc = 0; 65: } 66: #endif 67: havetmp = 1; 68: close(tfile); 69: tfile = open(tfname, 2); 70: if (tfile < 0) 71: goto dumbness; 72: /* brk((char *)fendcore); */ 73: } 74: 75: cleanup(all) 76: bool all; 77: { 78: if (all) { 79: putpad(TE); 80: flush(); 81: } 82: if (havetmp) 83: unlink(tfname); 84: havetmp = 0; 85: if (all && rfile >= 0) { 86: unlink(rfname); 87: close(rfile); 88: rfile = -1; 89: } 90: } 91: 92: getline(tl) 93: line tl; 94: { 95: register char *bp, *lp; 96: register int nl; 97: 98: lp = linebuf; 99: bp = getblock(tl, READ); 100: nl = nleft; 101: tl &= ~OFFMSK; 102: while (*lp++ = *bp++) 103: if (--nl == 0) { 104: bp = getblock(tl += INCRMT, READ); 105: nl = nleft; 106: } 107: } 108: 109: putline() 110: { 111: register char *bp, *lp; 112: register int nl; 113: line tl; 114: 115: dirtcnt++; 116: lp = linebuf; 117: change(); 118: tl = tline; 119: bp = getblock(tl, WRITE); 120: nl = nleft; 121: tl &= ~OFFMSK; 122: while (*bp = *lp++) { 123: if (*bp++ == '\n') { 124: *--bp = 0; 125: linebp = lp; 126: break; 127: } 128: if (--nl == 0) { 129: bp = getblock(tl += INCRMT, WRITE); 130: nl = nleft; 131: } 132: } 133: tl = tline; 134: tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 135: return (tl); 136: } 137: 138: int read(); 139: int write(); 140: 141: char * 142: getblock(atl, iof) 143: line atl; 144: int iof; 145: { 146: register int bno, off; 147: register char *p1, *p2; 148: register int n; 149: 150: bno = (atl >> OFFBTS) & BLKMSK; 151: off = (atl << SHFT) & LBTMSK; 152: if (bno >= NMBLKS) 153: error(" Tmp file too large"); 154: nleft = BUFSIZ - off; 155: if (bno == iblock) { 156: ichanged |= iof; 157: hitin2 = 0; 158: return (ibuff + off); 159: } 160: if (bno == iblock2) { 161: ichang2 |= iof; 162: hitin2 = 1; 163: return (ibuff2 + off); 164: } 165: if (bno == oblock) 166: return (obuff + off); 167: if (iof == READ) { 168: if (hitin2 == 0) { 169: if (ichang2) { 170: #ifdef CRYPT 171: if(xtflag) 172: crblock(tperm, ibuff2, CRSIZE, (long)0); 173: #endif 174: blkio(iblock2, ibuff2, write); 175: } 176: ichang2 = 0; 177: iblock2 = bno; 178: blkio(bno, ibuff2, read); 179: #ifdef CRYPT 180: if(xtflag) 181: crblock(tperm, ibuff2, CRSIZE, (long)0); 182: #endif 183: hitin2 = 1; 184: return (ibuff2 + off); 185: } 186: hitin2 = 0; 187: if (ichanged) { 188: #ifdef CRYPT 189: if(xtflag) 190: crblock(tperm, ibuff, CRSIZE, (long)0); 191: #endif 192: blkio(iblock, ibuff, write); 193: } 194: ichanged = 0; 195: iblock = bno; 196: blkio(bno, ibuff, read); 197: #ifdef CRYPT 198: if(xtflag) 199: crblock(tperm, ibuff, CRSIZE, (long)0); 200: #endif 201: return (ibuff + off); 202: } 203: if (oblock >= 0) { 204: #ifdef CRYPT 205: if(xtflag) { 206: /* 207: * Encrypt block before writing, so some devious 208: * person can't look at temp file while editing. 209: */ 210: p1 = obuff; 211: p2 = crbuf; 212: n = CRSIZE; 213: while(n--) 214: *p2++ = *p1++; 215: crblock(tperm, crbuf, CRSIZE, (long)0); 216: blkio(oblock, crbuf, write); 217: } else 218: #endif 219: blkio(oblock, obuff, write); 220: } 221: oblock = bno; 222: return (obuff + off); 223: } 224: 225: #ifdef VMUNIX 226: #define INCORB 64 227: char incorb[INCORB+1][BUFSIZ]; 228: #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1))) 229: int stilinc; /* up to here not written yet */ 230: #endif 231: 232: blkio(b, buf, iofcn) 233: short b; 234: char *buf; 235: int (*iofcn)(); 236: { 237: 238: #ifdef VMUNIX 239: if (b < INCORB) { 240: if (iofcn == read) { 241: bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ); 242: return; 243: } 244: bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ); 245: if (laste) { 246: if (b >= stilinc) 247: stilinc = b + 1; 248: return; 249: } 250: } else if (stilinc) 251: tflush(); 252: #endif 253: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); 254: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) 255: filioerr(tfname); 256: } 257: 258: #ifdef VMUNIX 259: tlaste() 260: { 261: 262: if (stilinc) 263: dirtcnt = 0; 264: } 265: 266: tflush() 267: { 268: int i = stilinc; 269: 270: stilinc = 0; 271: lseek(tfile, (long) 0, 0); 272: if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ)) 273: filioerr(tfname); 274: } 275: #endif 276: 277: /* 278: * Synchronize the state of the temporary file in case 279: * a crash occurs. 280: */ 281: synctmp() 282: { 283: register int cnt; 284: register line *a; 285: register short *bp; 286: 287: #ifdef VMUNIX 288: if (stilinc) 289: return; 290: #endif 291: if (dol == zero) 292: return; 293: if (ichanged) 294: blkio(iblock, ibuff, write); 295: ichanged = 0; 296: if (ichang2) 297: blkio(iblock2, ibuff2, write); 298: ichang2 = 0; 299: if (oblock != -1) 300: blkio(oblock, obuff, write); 301: time(&H.Time); 302: uid = getuid(); 303: *zero = (line) H.Time; 304: for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { 305: if (*bp < 0) { 306: tline = (tline + OFFMSK) &~ OFFMSK; 307: *bp = ((tline >> OFFBTS) & BLKMSK); 308: if (*bp > NMBLKS) 309: error(" Tmp file too large"); 310: tline += INCRMT; 311: oblock = *bp + 1; 312: bp[1] = -1; 313: } 314: lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); 315: cnt = ((dol - a) + 2) * sizeof (line); 316: if (cnt > BUFSIZ) 317: cnt = BUFSIZ; 318: if (write(tfile, (char *) a, cnt) != cnt) { 319: oops: 320: *zero = 0; 321: filioerr(tfname); 322: } 323: *zero = 0; 324: } 325: flines = lineDOL(); 326: lseek(tfile, 0l, 0); 327: if (write(tfile, (char *) &H, sizeof H) != sizeof H) 328: goto oops; 329: } 330: 331: TSYNC() 332: { 333: 334: if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */ 335: #ifdef VMUNIX 336: if (stilinc) 337: tflush(); 338: #endif 339: dirtcnt = 0; 340: synctmp(); 341: } 342: } 343: 344: /* 345: * Named buffer routines. 346: * These are implemented differently than the main buffer. 347: * Each named buffer has a chain of blocks in the register file. 348: * Each block contains roughly 508 chars of text, 349: * and a previous and next block number. We also have information 350: * about which blocks came from deletes of multiple partial lines, 351: * e.g. deleting a sentence or a LISP object. 352: * 353: * We maintain a free map for the temp file. To free the blocks 354: * in a register we must read the blocks to find how they are chained 355: * together. 356: * 357: * BUG: The default savind of deleted lines in numbered 358: * buffers may be rather inefficient; it hasn't been profiled. 359: */ 360: struct strreg { 361: short rg_flags; 362: short rg_nleft; 363: short rg_first; 364: short rg_last; 365: } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 366: 367: struct rbuf { 368: short rb_prev; 369: short rb_next; 370: char rb_text[BUFSIZ - 2 * sizeof (short)]; 371: } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; 372: #ifdef VMUNIX 373: short rused[256]; 374: #else 375: short rused[32]; 376: #endif 377: short rnleft; 378: short rblock; 379: short rnext; 380: char *rbufcp; 381: 382: regio(b, iofcn) 383: short b; 384: int (*iofcn)(); 385: { 386: 387: if (rfile == -1) { 388: CP(rfname, tfname); 389: *(strend(rfname) - 7) = 'R'; 390: rfile = creat(rfname, 0600); 391: if (rfile < 0) 392: oops: 393: filioerr(rfname); 394: close(rfile); 395: rfile = open(rfname, 2); 396: if (rfile < 0) 397: goto oops; 398: } 399: lseek(rfile, (long) b * BUFSIZ, 0); 400: if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) 401: goto oops; 402: rblock = b; 403: } 404: 405: REGblk() 406: { 407: register int i, j, m; 408: 409: for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { 410: m = (rused[i] ^ 0177777) & 0177777; 411: if (i == 0) 412: m &= ~1; 413: if (m != 0) { 414: j = 0; 415: while ((m & 1) == 0) 416: j++, m >>= 1; 417: rused[i] |= (1 << j); 418: #ifdef RDEBUG 419: printf("allocating block %d\n", i * 16 + j); 420: #endif 421: return (i * 16 + j); 422: } 423: } 424: error("Out of register space (ugh)"); 425: /*NOTREACHED*/ 426: } 427: 428: struct strreg * 429: mapreg(c) 430: register int c; 431: { 432: 433: if (isupper(c)) 434: c = tolower(c); 435: return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 436: } 437: 438: int shread(); 439: 440: KILLreg(c) 441: register int c; 442: { 443: register struct strreg *sp; 444: 445: rbuf = &KILLrbuf; 446: sp = mapreg(c); 447: rblock = sp->rg_first; 448: sp->rg_first = sp->rg_last = 0; 449: sp->rg_flags = sp->rg_nleft = 0; 450: while (rblock != 0) { 451: #ifdef RDEBUG 452: printf("freeing block %d\n", rblock); 453: #endif 454: rused[rblock / 16] &= ~(1 << (rblock % 16)); 455: regio(rblock, shread); 456: rblock = rbuf->rb_next; 457: } 458: } 459: 460: /*VARARGS*/ 461: shread() 462: { 463: struct front { short a; short b; }; 464: 465: if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 466: return (sizeof (struct rbuf)); 467: return (0); 468: } 469: 470: int getREG(); 471: 472: putreg(c) 473: char c; 474: { 475: register line *odot = dot; 476: register line *odol = dol; 477: register int cnt; 478: 479: deletenone(); 480: appendnone(); 481: rbuf = &putrbuf; 482: rnleft = 0; 483: rblock = 0; 484: rnext = mapreg(c)->rg_first; 485: if (rnext == 0) { 486: if (inopen) { 487: splitw++; 488: vclean(); 489: vgoto(WECHO, 0); 490: } 491: vreg = -1; 492: error("Nothing in register %c", c); 493: } 494: if (inopen && partreg(c)) { 495: if (!FIXUNDO) { 496: splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 497: error("Can't put partial line inside macro"); 498: } 499: squish(); 500: addr1 = addr2 = dol; 501: } 502: cnt = append(getREG, addr2); 503: if (inopen && partreg(c)) { 504: unddol = dol; 505: dol = odol; 506: dot = odot; 507: pragged(0); 508: } 509: killcnt(cnt); 510: notecnt = cnt; 511: } 512: 513: partreg(c) 514: char c; 515: { 516: 517: return (mapreg(c)->rg_flags); 518: } 519: 520: notpart(c) 521: register int c; 522: { 523: 524: if (c) 525: mapreg(c)->rg_flags = 0; 526: } 527: 528: getREG() 529: { 530: register char *lp = linebuf; 531: register int c; 532: 533: for (;;) { 534: if (rnleft == 0) { 535: if (rnext == 0) 536: return (EOF); 537: regio(rnext, read); 538: rnext = rbuf->rb_next; 539: rbufcp = rbuf->rb_text; 540: rnleft = sizeof rbuf->rb_text; 541: } 542: c = *rbufcp; 543: if (c == 0) 544: return (EOF); 545: rbufcp++, --rnleft; 546: if (c == '\n') { 547: *lp++ = 0; 548: return (0); 549: } 550: *lp++ = c; 551: } 552: } 553: 554: YANKreg(c) 555: register int c; 556: { 557: register line *addr; 558: register struct strreg *sp; 559: char savelb[LBSIZE]; 560: 561: if (isdigit(c)) 562: kshift(); 563: if (islower(c)) 564: KILLreg(c); 565: strp = sp = mapreg(c); 566: sp->rg_flags = inopen && cursor && wcursor; 567: rbuf = &YANKrbuf; 568: if (sp->rg_last) { 569: regio(sp->rg_last, read); 570: rnleft = sp->rg_nleft; 571: rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 572: } else { 573: rblock = 0; 574: rnleft = 0; 575: } 576: CP(savelb,linebuf); 577: for (addr = addr1; addr <= addr2; addr++) { 578: getline(*addr); 579: if (sp->rg_flags) { 580: if (addr == addr2) 581: *wcursor = 0; 582: if (addr == addr1) 583: strcpy(linebuf, cursor); 584: } 585: YANKline(); 586: } 587: rbflush(); 588: killed(); 589: CP(linebuf,savelb); 590: } 591: 592: kshift() 593: { 594: register int i; 595: 596: KILLreg('9'); 597: for (i = '8'; i >= '0'; i--) 598: copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 599: } 600: 601: YANKline() 602: { 603: register char *lp = linebuf; 604: register struct rbuf *rp = rbuf; 605: register int c; 606: 607: do { 608: c = *lp++; 609: if (c == 0) 610: c = '\n'; 611: if (rnleft == 0) { 612: rp->rb_next = REGblk(); 613: rbflush(); 614: rblock = rp->rb_next; 615: rp->rb_next = 0; 616: rp->rb_prev = rblock; 617: rnleft = sizeof rp->rb_text; 618: rbufcp = rp->rb_text; 619: } 620: *rbufcp++ = c; 621: --rnleft; 622: } while (c != '\n'); 623: if (rnleft) 624: *rbufcp = 0; 625: } 626: 627: rbflush() 628: { 629: register struct strreg *sp = strp; 630: 631: if (rblock == 0) 632: return; 633: regio(rblock, write); 634: if (sp->rg_first == 0) 635: sp->rg_first = rblock; 636: sp->rg_last = rblock; 637: sp->rg_nleft = rnleft; 638: } 639: 640: /* Register c to char buffer buf of size buflen */ 641: regbuf(c, buf, buflen) 642: char c; 643: char *buf; 644: int buflen; 645: { 646: register char *p, *lp; 647: 648: rbuf = ®rbuf; 649: rnleft = 0; 650: rblock = 0; 651: rnext = mapreg(c)->rg_first; 652: if (rnext==0) { 653: *buf = 0; 654: error("Nothing in register %c",c); 655: } 656: p = buf; 657: while (getREG()==0) { 658: for (lp=linebuf; *lp;) { 659: if (p >= &buf[buflen]) 660: error("Register too long@to fit in memory"); 661: *p++ = *lp++; 662: } 663: *p++ = '\n'; 664: } 665: if (partreg(c)) p--; 666: *p = '\0'; 667: getDOT(); 668: } 669: 670: /* 671: * Encryption routines. These are essentially unmodified from ed. 672: */ 673: 674: #ifdef CRYPT 675: /* 676: * crblock: encrypt/decrypt a block of text. 677: * buf is the buffer through which the text is both input and 678: * output. nchar is the size of the buffer. permp is a work 679: * buffer, and startn is the beginning of a sequence. 680: */ 681: crblock(permp, buf, nchar, startn) 682: char *permp; 683: char *buf; 684: int nchar; 685: long startn; 686: { 687: register char *p1; 688: int n1; 689: int n2; 690: register char *t1, *t2, *t3; 691: 692: t1 = permp; 693: t2 = &permp[256]; 694: t3 = &permp[512]; 695: 696: n1 = startn&0377; 697: n2 = (startn>>8)&0377; 698: p1 = buf; 699: while(nchar--) { 700: *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; 701: n1++; 702: if(n1==256){ 703: n1 = 0; 704: n2++; 705: if(n2==256) n2 = 0; 706: } 707: p1++; 708: } 709: } 710: 711: /* 712: * makekey: initialize buffers based on user key a. 713: */ 714: makekey(a, b) 715: char *a, *b; 716: { 717: register int i; 718: long t; 719: char temp[KSIZE + 1]; 720: 721: for(i = 0; i < KSIZE; i++) 722: temp[i] = *a++; 723: time(&t); 724: t += getpid(); 725: for(i = 0; i < 4; i++) 726: temp[i] ^= (t>>(8*i))&0377; 727: crinit(temp, b); 728: } 729: 730: /* 731: * crinit: besides initializing the encryption machine, this routine 732: * returns 0 if the key is null, and 1 if it is non-null. 733: */ 734: crinit(keyp, permp) 735: char *keyp, *permp; 736: { 737: register char *t1, *t2, *t3; 738: register i; 739: int ic, k, temp; 740: unsigned random; 741: char buf[13]; 742: long seed; 743: 744: t1 = permp; 745: t2 = &permp[256]; 746: t3 = &permp[512]; 747: if(*keyp == 0) 748: return(0); 749: strncpy(buf, keyp, 8); 750: while (*keyp) 751: *keyp++ = '\0'; 752: 753: buf[8] = buf[0]; 754: buf[9] = buf[1]; 755: domakekey(buf); 756: 757: seed = 123; 758: for (i=0; i<13; i++) 759: seed = seed*buf[i] + i; 760: for(i=0;i<256;i++){ 761: t1[i] = i; 762: t3[i] = 0; 763: } 764: for(i=0; i<256; i++) { 765: seed = 5*seed + buf[i%13]; 766: random = seed % 65521; 767: k = 256-1 - i; 768: ic = (random&0377) % (k+1); 769: random >>= 8; 770: temp = t1[k]; 771: t1[k] = t1[ic]; 772: t1[ic] = temp; 773: if(t3[k]!=0) continue; 774: ic = (random&0377) % k; 775: while(t3[ic]!=0) ic = (ic+1) % k; 776: t3[k] = ic; 777: t3[ic] = k; 778: } 779: for(i=0; i<256; i++) 780: t2[t1[i]&0377] = i; 781: return(1); 782: } 783: 784: /* 785: * domakekey: the following is the major nonportable part of the encryption 786: * mechanism. A 10 character key is supplied in buffer. 787: * This string is fed to makekey (an external program) which 788: * responds with a 13 character result. This result is placed 789: * in buffer. 790: */ 791: domakekey(buffer) 792: char *buffer; 793: { 794: int pf[2]; 795: 796: if (pipe(pf)<0) 797: pf[0] = pf[1] = -1; 798: if (fork()==0) { 799: close(0); 800: close(1); 801: dup(pf[0]); 802: dup(pf[1]); 803: execl("/usr/lib/makekey", "-", 0); 804: execl("/lib/makekey", "-", 0); 805: exit(1); 806: } 807: write(pf[1], buffer, 10); 808: if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) 809: error("crypt: cannot generate key"); 810: close(pf[0]); 811: close(pf[1]); 812: /* end of nonportable part */ 813: } 814: #endif