1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_temp.c 7.1 07/08/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; mjm: in ex_space.c */ 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; 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 char savelb[LBSIZE]; 563 564 if (isdigit(c)) 565 kshift(); 566 if (islower(c)) 567 KILLreg(c); 568 strp = sp = mapreg(c); 569 sp->rg_flags = inopen && cursor && wcursor; 570 rbuf = &arbuf; 571 if (sp->rg_last) { 572 regio(sp->rg_last, read); 573 rnleft = sp->rg_nleft; 574 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 575 } else { 576 rblock = 0; 577 rnleft = 0; 578 } 579 CP(savelb,linebuf); 580 for (addr = addr1; addr <= addr2; addr++) { 581 getline(*addr); 582 if (sp->rg_flags) { 583 if (addr == addr2) 584 *wcursor = 0; 585 if (addr == addr1) 586 strcpy(linebuf, cursor); 587 } 588 YANKline(); 589 } 590 rbflush(); 591 killed(); 592 CP(linebuf,savelb); 593 } 594 595 kshift() 596 { 597 register int i; 598 599 KILLreg('9'); 600 for (i = '8'; i >= '0'; i--) 601 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 602 } 603 604 YANKline() 605 { 606 register char *lp = linebuf; 607 register struct rbuf *rp = rbuf; 608 register int c; 609 610 do { 611 c = *lp++; 612 if (c == 0) 613 c = '\n'; 614 if (rnleft == 0) { 615 rp->rb_next = REGblk(); 616 rbflush(); 617 rblock = rp->rb_next; 618 rp->rb_next = 0; 619 rp->rb_prev = rblock; 620 rnleft = sizeof rp->rb_text; 621 rbufcp = rp->rb_text; 622 } 623 *rbufcp++ = c; 624 --rnleft; 625 } while (c != '\n'); 626 if (rnleft) 627 *rbufcp = 0; 628 } 629 630 rbflush() 631 { 632 register struct strreg *sp = strp; 633 634 if (rblock == 0) 635 return; 636 regio(rblock, write); 637 if (sp->rg_first == 0) 638 sp->rg_first = rblock; 639 sp->rg_last = rblock; 640 sp->rg_nleft = rnleft; 641 } 642 643 /* Register c to char buffer buf of size buflen */ 644 regbuf(c, buf, buflen) 645 char c; 646 char *buf; 647 int buflen; 648 { 649 struct rbuf arbuf; 650 register char *p, *lp; 651 652 rbuf = &arbuf; 653 rnleft = 0; 654 rblock = 0; 655 rnext = mapreg(c)->rg_first; 656 if (rnext==0) { 657 *buf = 0; 658 error("Nothing in register %c",c); 659 } 660 p = buf; 661 while (getREG()==0) { 662 for (lp=linebuf; *lp;) { 663 if (p >= &buf[buflen]) 664 error("Register too long@to fit in memory"); 665 *p++ = *lp++; 666 } 667 *p++ = '\n'; 668 } 669 if (partreg(c)) p--; 670 *p = '\0'; 671 getDOT(); 672 } 673 674 /* 675 * Encryption routines. These are essentially unmodified from ed. 676 */ 677 678 #ifdef CRYPT 679 /* 680 * crblock: encrypt/decrypt a block of text. 681 * buf is the buffer through which the text is both input and 682 * output. nchar is the size of the buffer. permp is a work 683 * buffer, and startn is the beginning of a sequence. 684 */ 685 crblock(permp, buf, nchar, startn) 686 char *permp; 687 char *buf; 688 int nchar; 689 long startn; 690 { 691 register char *p1; 692 int n1; 693 int n2; 694 register char *t1, *t2, *t3; 695 696 t1 = permp; 697 t2 = &permp[256]; 698 t3 = &permp[512]; 699 700 n1 = startn&0377; 701 n2 = (startn>>8)&0377; 702 p1 = buf; 703 while(nchar--) { 704 *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; 705 n1++; 706 if(n1==256){ 707 n1 = 0; 708 n2++; 709 if(n2==256) n2 = 0; 710 } 711 p1++; 712 } 713 } 714 715 /* 716 * makekey: initialize buffers based on user key a. 717 */ 718 makekey(a, b) 719 char *a, *b; 720 { 721 register int i; 722 long t; 723 char temp[KSIZE + 1]; 724 725 for(i = 0; i < KSIZE; i++) 726 temp[i] = *a++; 727 time(&t); 728 t += getpid(); 729 for(i = 0; i < 4; i++) 730 temp[i] ^= (t>>(8*i))&0377; 731 crinit(temp, b); 732 } 733 734 /* 735 * crinit: besides initializing the encryption machine, this routine 736 * returns 0 if the key is null, and 1 if it is non-null. 737 */ 738 crinit(keyp, permp) 739 char *keyp, *permp; 740 { 741 register char *t1, *t2, *t3; 742 register i; 743 int ic, k, temp; 744 unsigned random; 745 char buf[13]; 746 long seed; 747 748 t1 = permp; 749 t2 = &permp[256]; 750 t3 = &permp[512]; 751 if(*keyp == 0) 752 return(0); 753 strncpy(buf, keyp, 8); 754 while (*keyp) 755 *keyp++ = '\0'; 756 757 buf[8] = buf[0]; 758 buf[9] = buf[1]; 759 domakekey(buf); 760 761 seed = 123; 762 for (i=0; i<13; i++) 763 seed = seed*buf[i] + i; 764 for(i=0;i<256;i++){ 765 t1[i] = i; 766 t3[i] = 0; 767 } 768 for(i=0; i<256; i++) { 769 seed = 5*seed + buf[i%13]; 770 random = seed % 65521; 771 k = 256-1 - i; 772 ic = (random&0377) % (k+1); 773 random >>= 8; 774 temp = t1[k]; 775 t1[k] = t1[ic]; 776 t1[ic] = temp; 777 if(t3[k]!=0) continue; 778 ic = (random&0377) % k; 779 while(t3[ic]!=0) ic = (ic+1) % k; 780 t3[k] = ic; 781 t3[ic] = k; 782 } 783 for(i=0; i<256; i++) 784 t2[t1[i]&0377] = i; 785 return(1); 786 } 787 788 /* 789 * domakekey: the following is the major nonportable part of the encryption 790 * mechanism. A 10 character key is supplied in buffer. 791 * This string is fed to makekey (an external program) which 792 * responds with a 13 character result. This result is placed 793 * in buffer. 794 */ 795 domakekey(buffer) 796 char *buffer; 797 { 798 int pf[2]; 799 800 if (pipe(pf)<0) 801 pf[0] = pf[1] = -1; 802 if (fork()==0) { 803 close(0); 804 close(1); 805 dup(pf[0]); 806 dup(pf[1]); 807 execl("/usr/lib/makekey", "-", 0); 808 execl("/lib/makekey", "-", 0); 809 exit(1); 810 } 811 write(pf[1], buffer, 10); 812 if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) 813 error("crypt: cannot generate key"); 814 close(pf[0]); 815 close(pf[1]); 816 /* end of nonportable part */ 817 } 818 #endif 819