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: #ifndef lint 8: static char *sccsid = "@(#)ex_temp.c 7.5 (Berkeley) 6/7/85"; 9: #endif not lint 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: #ifdef CRYPT 179: if(xtflag) 180: crblock(tperm, ibuff2, CRSIZE, (long)0); 181: #endif 182: blkio(iblock2, ibuff2, write); 183: } 184: ichang2 = 0; 185: iblock2 = bno; 186: blkio(bno, ibuff2, read); 187: #ifdef CRYPT 188: if(xtflag) 189: crblock(tperm, ibuff2, CRSIZE, (long)0); 190: #endif 191: hitin2 = 1; 192: return (ibuff2 + off); 193: } 194: hitin2 = 0; 195: if (ichanged) { 196: #ifdef CRYPT 197: if(xtflag) 198: crblock(tperm, ibuff, CRSIZE, (long)0); 199: #endif 200: blkio(iblock, ibuff, write); 201: } 202: ichanged = 0; 203: iblock = bno; 204: blkio(bno, ibuff, read); 205: #ifdef CRYPT 206: if(xtflag) 207: crblock(tperm, ibuff, CRSIZE, (long)0); 208: #endif 209: return (ibuff + off); 210: } 211: if (oblock >= 0) { 212: #ifdef CRYPT 213: if(xtflag) { 214: /* 215: * Encrypt block before writing, so some devious 216: * person can't look at temp file while editing. 217: */ 218: p1 = obuff; 219: p2 = crbuf; 220: n = CRSIZE; 221: while(n--) 222: *p2++ = *p1++; 223: crblock(tperm, crbuf, CRSIZE, (long)0); 224: blkio(oblock, crbuf, write); 225: } else 226: #endif 227: blkio(oblock, obuff, write); 228: } 229: oblock = bno; 230: return (obuff + off); 231: } 232: 233: #ifdef VMUNIX 234: #define INCORB 64 235: char incorb[INCORB+1][BUFSIZ]; 236: #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1))) 237: int stilinc; /* up to here not written yet */ 238: #endif 239: 240: blkio(b, buf, iofcn) 241: short b; 242: char *buf; 243: int (*iofcn)(); 244: { 245: 246: #ifdef VMUNIX 247: if (b < INCORB) { 248: if (iofcn == read) { 249: bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ); 250: return; 251: } 252: bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ); 253: if (laste) { 254: if (b >= stilinc) 255: stilinc = b + 1; 256: return; 257: } 258: } else if (stilinc) 259: tflush(); 260: #endif 261: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); 262: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) 263: filioerr(tfname); 264: } 265: 266: #ifdef VMUNIX 267: tlaste() 268: { 269: 270: if (stilinc) 271: dirtcnt = 0; 272: } 273: 274: tflush() 275: { 276: int i = stilinc; 277: 278: stilinc = 0; 279: lseek(tfile, (long) 0, 0); 280: if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ)) 281: filioerr(tfname); 282: } 283: #endif 284: 285: /* 286: * Synchronize the state of the temporary file in case 287: * a crash occurs. 288: */ 289: synctmp() 290: { 291: register int cnt; 292: register line *a; 293: register short *bp; 294: 295: #ifdef VMUNIX 296: if (stilinc) 297: return; 298: #endif 299: if (dol == zero) 300: return; 301: if (ichanged) 302: blkio(iblock, ibuff, write); 303: ichanged = 0; 304: if (ichang2) 305: blkio(iblock2, ibuff2, write); 306: ichang2 = 0; 307: if (oblock != -1) 308: blkio(oblock, obuff, write); 309: time(&H.Time); 310: uid = getuid(); 311: *zero = (line) H.Time; 312: for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { 313: if (*bp < 0) { 314: tline = (tline + OFFMSK) &~ OFFMSK; 315: *bp = ((tline >> OFFBTS) & BLKMSK); 316: if (*bp > NMBLKS) 317: error(" Tmp file too large"); 318: tline += INCRMT; 319: oblock = *bp + 1; 320: bp[1] = -1; 321: } 322: lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); 323: cnt = ((dol - a) + 2) * sizeof (line); 324: if (cnt > BUFSIZ) 325: cnt = BUFSIZ; 326: if (write(tfile, (char *) a, cnt) != cnt) { 327: oops: 328: *zero = 0; 329: filioerr(tfname); 330: } 331: *zero = 0; 332: } 333: flines = lineDOL(); 334: lseek(tfile, 0l, 0); 335: if (write(tfile, (char *) &H, sizeof H) != sizeof H) 336: goto oops; 337: #ifdef notdef 338: /* 339: * This will insure that exrecover gets as much 340: * back after a crash as is absolutely possible, 341: * but can result in pregnant pauses between commands 342: * when the TSYNC call is made, so... 343: */ 344: (void) fsync(tfile); 345: #endif 346: } 347: 348: TSYNC() 349: { 350: 351: if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */ 352: #ifdef VMUNIX 353: if (stilinc) 354: tflush(); 355: #endif 356: dirtcnt = 0; 357: synctmp(); 358: } 359: } 360: 361: /* 362: * Named buffer routines. 363: * These are implemented differently than the main buffer. 364: * Each named buffer has a chain of blocks in the register file. 365: * Each block contains roughly 508 chars of text, 366: * and a previous and next block number. We also have information 367: * about which blocks came from deletes of multiple partial lines, 368: * e.g. deleting a sentence or a LISP object. 369: * 370: * We maintain a free map for the temp file. To free the blocks 371: * in a register we must read the blocks to find how they are chained 372: * together. 373: * 374: * BUG: The default savind of deleted lines in numbered 375: * buffers may be rather inefficient; it hasn't been profiled. 376: */ 377: struct strreg { 378: short rg_flags; 379: short rg_nleft; 380: short rg_first; 381: short rg_last; 382: } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 383: 384: struct rbuf { 385: short rb_prev; 386: short rb_next; 387: char rb_text[BUFSIZ - 2 * sizeof (short)]; 388: } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; 389: #ifdef VMUNIX 390: short rused[256]; 391: #else 392: short rused[32]; 393: #endif 394: short rnleft; 395: short rblock; 396: short rnext; 397: char *rbufcp; 398: 399: regio(b, iofcn) 400: short b; 401: int (*iofcn)(); 402: { 403: 404: if (rfile == -1) { 405: CP(rfname, tfname); 406: *(strend(rfname) - 7) = 'R'; 407: rfile = creat(rfname, 0600); 408: if (rfile < 0) 409: oops: 410: filioerr(rfname); 411: close(rfile); 412: rfile = open(rfname, 2); 413: if (rfile < 0) 414: goto oops; 415: } 416: lseek(rfile, (long) b * BUFSIZ, 0); 417: if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) 418: goto oops; 419: rblock = b; 420: } 421: 422: REGblk() 423: { 424: register int i, j, m; 425: 426: for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { 427: m = (rused[i] ^ 0177777) & 0177777; 428: if (i == 0) 429: m &= ~1; 430: if (m != 0) { 431: j = 0; 432: while ((m & 1) == 0) 433: j++, m >>= 1; 434: rused[i] |= (1 << j); 435: #ifdef RDEBUG 436: printf("allocating block %d\n", i * 16 + j); 437: #endif 438: return (i * 16 + j); 439: } 440: } 441: error("Out of register space (ugh)"); 442: /*NOTREACHED*/ 443: } 444: 445: struct strreg * 446: mapreg(c) 447: register int c; 448: { 449: 450: if (isupper(c)) 451: c = tolower(c); 452: return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 453: } 454: 455: int shread(); 456: 457: KILLreg(c) 458: register int c; 459: { 460: register struct strreg *sp; 461: 462: rbuf = &KILLrbuf; 463: sp = mapreg(c); 464: rblock = sp->rg_first; 465: sp->rg_first = sp->rg_last = 0; 466: sp->rg_flags = sp->rg_nleft = 0; 467: while (rblock != 0) { 468: #ifdef RDEBUG 469: printf("freeing block %d\n", rblock); 470: #endif 471: rused[rblock / 16] &= ~(1 << (rblock % 16)); 472: regio(rblock, shread); 473: rblock = rbuf->rb_next; 474: } 475: } 476: 477: /*VARARGS*/ 478: shread() 479: { 480: struct front { short a; short b; }; 481: 482: if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 483: return (sizeof (struct rbuf)); 484: return (0); 485: } 486: 487: int getREG(); 488: 489: putreg(c) 490: char c; 491: { 492: register line *odot = dot; 493: register line *odol = dol; 494: register int cnt; 495: 496: deletenone(); 497: appendnone(); 498: rbuf = &putrbuf; 499: rnleft = 0; 500: rblock = 0; 501: rnext = mapreg(c)->rg_first; 502: if (rnext == 0) { 503: if (inopen) { 504: splitw++; 505: vclean(); 506: vgoto(WECHO, 0); 507: } 508: vreg = -1; 509: error("Nothing in register %c", c); 510: } 511: if (inopen && partreg(c)) { 512: if (!FIXUNDO) { 513: splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 514: error("Can't put partial line inside macro"); 515: } 516: squish(); 517: addr1 = addr2 = dol; 518: } 519: cnt = append(getREG, addr2); 520: if (inopen && partreg(c)) { 521: unddol = dol; 522: dol = odol; 523: dot = odot; 524: pragged(0); 525: } 526: killcnt(cnt); 527: notecnt = cnt; 528: } 529: 530: partreg(c) 531: char c; 532: { 533: 534: return (mapreg(c)->rg_flags); 535: } 536: 537: notpart(c) 538: register int c; 539: { 540: 541: if (c) 542: mapreg(c)->rg_flags = 0; 543: } 544: 545: getREG() 546: { 547: register char *lp = linebuf; 548: register int c; 549: 550: for (;;) { 551: if (rnleft == 0) { 552: if (rnext == 0) 553: return (EOF); 554: regio(rnext, read); 555: rnext = rbuf->rb_next; 556: rbufcp = rbuf->rb_text; 557: rnleft = sizeof rbuf->rb_text; 558: } 559: c = *rbufcp; 560: if (c == 0) 561: return (EOF); 562: rbufcp++, --rnleft; 563: if (c == '\n') { 564: *lp++ = 0; 565: return (0); 566: } 567: *lp++ = c; 568: } 569: } 570: 571: YANKreg(c) 572: register int c; 573: { 574: register line *addr; 575: register struct strreg *sp; 576: char savelb[LBSIZE]; 577: 578: if (isdigit(c)) 579: kshift(); 580: if (islower(c)) 581: KILLreg(c); 582: strp = sp = mapreg(c); 583: sp->rg_flags = inopen && cursor && wcursor; 584: rbuf = &YANKrbuf; 585: if (sp->rg_last) { 586: regio(sp->rg_last, read); 587: rnleft = sp->rg_nleft; 588: rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 589: } else { 590: rblock = 0; 591: rnleft = 0; 592: } 593: CP(savelb,linebuf); 594: for (addr = addr1; addr <= addr2; addr++) { 595: getline(*addr); 596: if (sp->rg_flags) { 597: if (addr == addr2) 598: *wcursor = 0; 599: if (addr == addr1) 600: strcpy(linebuf, cursor); 601: } 602: YANKline(); 603: } 604: rbflush(); 605: killed(); 606: CP(linebuf,savelb); 607: } 608: 609: kshift() 610: { 611: register int i; 612: 613: KILLreg('9'); 614: for (i = '8'; i >= '0'; i--) 615: copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 616: } 617: 618: YANKline() 619: { 620: register char *lp = linebuf; 621: register struct rbuf *rp = rbuf; 622: register int c; 623: 624: do { 625: c = *lp++; 626: if (c == 0) 627: c = '\n'; 628: if (rnleft == 0) { 629: rp->rb_next = REGblk(); 630: rbflush(); 631: rblock = rp->rb_next; 632: rp->rb_next = 0; 633: rp->rb_prev = rblock; 634: rnleft = sizeof rp->rb_text; 635: rbufcp = rp->rb_text; 636: } 637: *rbufcp++ = c; 638: --rnleft; 639: } while (c != '\n'); 640: if (rnleft) 641: *rbufcp = 0; 642: } 643: 644: rbflush() 645: { 646: register struct strreg *sp = strp; 647: 648: if (rblock == 0) 649: return; 650: regio(rblock, write); 651: if (sp->rg_first == 0) 652: sp->rg_first = rblock; 653: sp->rg_last = rblock; 654: sp->rg_nleft = rnleft; 655: } 656: 657: /* Register c to char buffer buf of size buflen */ 658: regbuf(c, buf, buflen) 659: char c; 660: char *buf; 661: int buflen; 662: { 663: register char *p, *lp; 664: 665: rbuf = ®rbuf; 666: rnleft = 0; 667: rblock = 0; 668: rnext = mapreg(c)->rg_first; 669: if (rnext==0) { 670: *buf = 0; 671: error("Nothing in register %c",c); 672: } 673: p = buf; 674: while (getREG()==0) { 675: for (lp=linebuf; *lp;) { 676: if (p >= &buf[buflen]) 677: error("Register too long@to fit in memory"); 678: *p++ = *lp++; 679: } 680: *p++ = '\n'; 681: } 682: if (partreg(c)) p--; 683: *p = '\0'; 684: getDOT(); 685: } 686: 687: /* 688: * Encryption routines. These are essentially unmodified from ed. 689: */ 690: 691: #ifdef CRYPT 692: /* 693: * crblock: encrypt/decrypt a block of text. 694: * buf is the buffer through which the text is both input and 695: * output. nchar is the size of the buffer. permp is a work 696: * buffer, and startn is the beginning of a sequence. 697: */ 698: crblock(permp, buf, nchar, startn) 699: char *permp; 700: char *buf; 701: int nchar; 702: long startn; 703: { 704: register char *p1; 705: int n1; 706: int n2; 707: register char *t1, *t2, *t3; 708: 709: t1 = permp; 710: t2 = &permp[256]; 711: t3 = &permp[512]; 712: 713: n1 = startn&0377; 714: n2 = (startn>>8)&0377; 715: p1 = buf; 716: while(nchar--) { 717: *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; 718: n1++; 719: if(n1==256){ 720: n1 = 0; 721: n2++; 722: if(n2==256) n2 = 0; 723: } 724: p1++; 725: } 726: } 727: 728: /* 729: * makekey: initialize buffers based on user key a. 730: */ 731: makekey(a, b) 732: char *a, *b; 733: { 734: register int i; 735: long t; 736: char temp[KSIZE + 1]; 737: 738: for(i = 0; i < KSIZE; i++) 739: temp[i] = *a++; 740: time(&t); 741: t += getpid(); 742: for(i = 0; i < 4; i++) 743: temp[i] ^= (t>>(8*i))&0377; 744: crinit(temp, b); 745: } 746: 747: /* 748: * crinit: besides initializing the encryption machine, this routine 749: * returns 0 if the key is null, and 1 if it is non-null. 750: */ 751: crinit(keyp, permp) 752: char *keyp, *permp; 753: { 754: register char *t1, *t2, *t3; 755: register i; 756: int ic, k, temp; 757: unsigned random; 758: char buf[13]; 759: long seed; 760: 761: t1 = permp; 762: t2 = &permp[256]; 763: t3 = &permp[512]; 764: if(*keyp == 0) 765: return(0); 766: strncpy(buf, keyp, 8); 767: while (*keyp) 768: *keyp++ = '\0'; 769: 770: buf[8] = buf[0]; 771: buf[9] = buf[1]; 772: domakekey(buf); 773: 774: seed = 123; 775: for (i=0; i<13; i++) 776: seed = seed*buf[i] + i; 777: for(i=0;i<256;i++){ 778: t1[i] = i; 779: t3[i] = 0; 780: } 781: for(i=0; i<256; i++) { 782: seed = 5*seed + buf[i%13]; 783: random = seed % 65521; 784: k = 256-1 - i; 785: ic = (random&0377) % (k+1); 786: random >>= 8; 787: temp = t1[k]; 788: t1[k] = t1[ic]; 789: t1[ic] = temp; 790: if(t3[k]!=0) continue; 791: ic = (random&0377) % k; 792: while(t3[ic]!=0) ic = (ic+1) % k; 793: t3[k] = ic; 794: t3[ic] = k; 795: } 796: for(i=0; i<256; i++) 797: t2[t1[i]&0377] = i; 798: return(1); 799: } 800: 801: /* 802: * domakekey: the following is the major nonportable part of the encryption 803: * mechanism. A 10 character key is supplied in buffer. 804: * This string is fed to makekey (an external program) which 805: * responds with a 13 character result. This result is placed 806: * in buffer. 807: */ 808: domakekey(buffer) 809: char *buffer; 810: { 811: int pf[2]; 812: 813: if (pipe(pf)<0) 814: pf[0] = pf[1] = -1; 815: if (fork()==0) { 816: close(0); 817: close(1); 818: dup(pf[0]); 819: dup(pf[1]); 820: execl("/usr/lib/makekey", "-", 0); 821: execl("/lib/makekey", "-", 0); 822: exit(1); 823: } 824: write(pf[1], buffer, 10); 825: if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) 826: error("crypt: cannot generate key"); 827: close(pf[0]); 828: close(pf[1]); 829: /* end of nonportable part */ 830: } 831: #endif