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