1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_temp.c 7.3 09/03/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 815