1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_temp.c 5.1 08/20/80"; 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 > 12) { 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; 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 struct rbuf arbuf; 444 register struct strreg *sp; 445 446 rbuf = &arbuf; 447 sp = mapreg(c); 448 rblock = sp->rg_first; 449 sp->rg_first = sp->rg_last = 0; 450 sp->rg_flags = sp->rg_nleft = 0; 451 while (rblock != 0) { 452 #ifdef RDEBUG 453 printf("freeing block %d\n", rblock); 454 #endif 455 rused[rblock / 16] &= ~(1 << (rblock % 16)); 456 regio(rblock, shread); 457 rblock = rbuf->rb_next; 458 } 459 } 460 461 /*VARARGS*/ 462 shread() 463 { 464 struct front { short a; short b; }; 465 466 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 467 return (sizeof (struct rbuf)); 468 return (0); 469 } 470 471 int getREG(); 472 473 putreg(c) 474 char c; 475 { 476 struct rbuf arbuf; 477 register line *odot = dot; 478 register line *odol = dol; 479 register int cnt; 480 481 deletenone(); 482 appendnone(); 483 rbuf = &arbuf; 484 rnleft = 0; 485 rblock = 0; 486 rnext = mapreg(c)->rg_first; 487 if (rnext == 0) { 488 if (inopen) { 489 splitw++; 490 vclean(); 491 vgoto(WECHO, 0); 492 } 493 vreg = -1; 494 error("Nothing in register %c", c); 495 } 496 if (inopen && partreg(c)) { 497 if (!FIXUNDO) { 498 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 499 error("Can't put partial line inside macro"); 500 } 501 squish(); 502 addr1 = addr2 = dol; 503 } 504 cnt = append(getREG, addr2); 505 if (inopen && partreg(c)) { 506 unddol = dol; 507 dol = odol; 508 dot = odot; 509 pragged(0); 510 } 511 killcnt(cnt); 512 notecnt = cnt; 513 } 514 515 partreg(c) 516 char c; 517 { 518 519 return (mapreg(c)->rg_flags); 520 } 521 522 notpart(c) 523 register int c; 524 { 525 526 if (c) 527 mapreg(c)->rg_flags = 0; 528 } 529 530 getREG() 531 { 532 register char *lp = linebuf; 533 register int c; 534 535 for (;;) { 536 if (rnleft == 0) { 537 if (rnext == 0) 538 return (EOF); 539 regio(rnext, read); 540 rnext = rbuf->rb_next; 541 rbufcp = rbuf->rb_text; 542 rnleft = sizeof rbuf->rb_text; 543 } 544 c = *rbufcp; 545 if (c == 0) 546 return (EOF); 547 rbufcp++, --rnleft; 548 if (c == '\n') { 549 *lp++ = 0; 550 return (0); 551 } 552 *lp++ = c; 553 } 554 } 555 556 YANKreg(c) 557 register int c; 558 { 559 struct rbuf arbuf; 560 register line *addr; 561 register struct strreg *sp; 562 563 if (isdigit(c)) 564 kshift(); 565 if (islower(c)) 566 KILLreg(c); 567 strp = sp = mapreg(c); 568 sp->rg_flags = inopen && cursor && wcursor; 569 rbuf = &arbuf; 570 if (sp->rg_last) { 571 regio(sp->rg_last, read); 572 rnleft = sp->rg_nleft; 573 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 574 } else { 575 rblock = 0; 576 rnleft = 0; 577 } 578 for (addr = addr1; addr <= addr2; addr++) { 579 getline(*addr); 580 if (sp->rg_flags) { 581 if (addr == addr2) 582 *wcursor = 0; 583 if (addr == addr1) 584 strcpy(linebuf, cursor); 585 } 586 YANKline(); 587 } 588 rbflush(); 589 killed(); 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 struct rbuf arbuf; 647 register char *p, *lp; 648 649 rbuf = &arbuf; 650 rnleft = 0; 651 rblock = 0; 652 rnext = mapreg(c)->rg_first; 653 if (rnext==0) { 654 *buf = 0; 655 error("Nothing in register %c",c); 656 } 657 p = buf; 658 while (getREG()==0) { 659 for (lp=linebuf; *lp;) { 660 if (p >= &buf[buflen]) 661 error("Register too long@to fit in memory"); 662 *p++ = *lp++; 663 } 664 *p++ = '\n'; 665 } 666 if (partreg(c)) p--; 667 *p = '\0'; 668 getDOT(); 669 } 670 671 /* 672 * Encryption routines. These are essentially unmodified from ed. 673 */ 674 675 #ifdef CRYPT 676 /* 677 * crblock: encrypt/decrypt a block of text. 678 * buf is the buffer through which the text is both input and 679 * output. nchar is the size of the buffer. permp is a work 680 * buffer, and startn is the beginning of a sequence. 681 */ 682 crblock(permp, buf, nchar, startn) 683 char *permp; 684 char *buf; 685 int nchar; 686 long startn; 687 { 688 register char *p1; 689 int n1; 690 int n2; 691 register char *t1, *t2, *t3; 692 693 t1 = permp; 694 t2 = &permp[256]; 695 t3 = &permp[512]; 696 697 n1 = startn&0377; 698 n2 = (startn>>8)&0377; 699 p1 = buf; 700 while(nchar--) { 701 *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; 702 n1++; 703 if(n1==256){ 704 n1 = 0; 705 n2++; 706 if(n2==256) n2 = 0; 707 } 708 p1++; 709 } 710 } 711 712 /* 713 * makekey: initialize buffers based on user key a. 714 */ 715 makekey(a, b) 716 char *a, *b; 717 { 718 register int i; 719 long t; 720 char temp[KSIZE + 1]; 721 722 for(i = 0; i < KSIZE; i++) 723 temp[i] = *a++; 724 time(&t); 725 t += getpid(); 726 for(i = 0; i < 4; i++) 727 temp[i] ^= (t>>(8*i))&0377; 728 crinit(temp, b); 729 } 730 731 /* 732 * crinit: besides initializing the encryption machine, this routine 733 * returns 0 if the key is null, and 1 if it is non-null. 734 */ 735 crinit(keyp, permp) 736 char *keyp, *permp; 737 { 738 register char *t1, *t2, *t3; 739 register i; 740 int ic, k, temp; 741 unsigned random; 742 char buf[13]; 743 long seed; 744 745 t1 = permp; 746 t2 = &permp[256]; 747 t3 = &permp[512]; 748 if(*keyp == 0) 749 return(0); 750 strncpy(buf, keyp, 8); 751 while (*keyp) 752 *keyp++ = '\0'; 753 754 buf[8] = buf[0]; 755 buf[9] = buf[1]; 756 domakekey(buf); 757 758 seed = 123; 759 for (i=0; i<13; i++) 760 seed = seed*buf[i] + i; 761 for(i=0;i<256;i++){ 762 t1[i] = i; 763 t3[i] = 0; 764 } 765 for(i=0; i<256; i++) { 766 seed = 5*seed + buf[i%13]; 767 random = seed % 65521; 768 k = 256-1 - i; 769 ic = (random&0377) % (k+1); 770 random >>= 8; 771 temp = t1[k]; 772 t1[k] = t1[ic]; 773 t1[ic] = temp; 774 if(t3[k]!=0) continue; 775 ic = (random&0377) % k; 776 while(t3[ic]!=0) ic = (ic+1) % k; 777 t3[k] = ic; 778 t3[ic] = k; 779 } 780 for(i=0; i<256; i++) 781 t2[t1[i]&0377] = i; 782 return(1); 783 } 784 785 /* 786 * domakekey: the following is the major nonportable part of the encryption 787 * mechanism. A 10 character key is supplied in buffer. 788 * This string is fed to makekey (an external program) which 789 * responds with a 13 character result. This result is placed 790 * in buffer. 791 */ 792 domakekey(buffer) 793 char *buffer; 794 { 795 int pf[2]; 796 797 if (pipe(pf)<0) 798 pf[0] = pf[1] = -1; 799 if (fork()==0) { 800 close(0); 801 close(1); 802 dup(pf[0]); 803 dup(pf[1]); 804 execl("/usr/lib/makekey", "-", 0); 805 execl("/lib/makekey", "-", 0); 806 exit(1); 807 } 808 write(pf[1], buffer, 10); 809 if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) 810 error("crypt: cannot generate key"); 811 close(pf[0]); 812 close(pf[1]); 813 /* end of nonportable part */ 814 } 815 #endif 816