1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* Copyright (c) 1981 Regents of the University of California */ 31 32 #include "ex.h" 33 #include "ex_temp.h" 34 #include "ex_vis.h" 35 #include "ex_tty.h" 36 #include <unistd.h> 37 38 /* 39 * Editor temporary file routines. 40 * Very similar to those of ed, except uses 2 input buffers. 41 */ 42 #define READ 0 43 #define WRITE 1 44 45 unsigned char tfname[PATH_MAX+1]; 46 static unsigned char rfname[PATH_MAX+1]; 47 static unsigned char tempname[PATH_MAX+1]; 48 int havetmp; 49 short tfile = -1; 50 static short rfile = -1; 51 52 extern int junk(); 53 54 void 55 fileinit(void) 56 { 57 unsigned char *p; 58 pid_t j; 59 int i; 60 struct stat64 stbuf; 61 62 if (tline == INCRMT * (HBLKS+2)) 63 return; 64 cleanup(0); 65 if (tfile != -1) 66 close(tfile); 67 tline = INCRMT * (HBLKS+2); 68 blocks[0] = HBLKS; 69 blocks[1] = HBLKS+1; 70 blocks[2] = -1; 71 dirtcnt = 0; 72 iblock = -1; 73 iblock2 = -1; 74 oblock = -1; 75 if (strlen(svalue(vi_DIRECTORY)) > (PATH_MAX -13)) 76 error(gettext("User set directory too long")); 77 CP(tfname, svalue(vi_DIRECTORY)); 78 if (stat64((char *)tfname, &stbuf)) { 79 dumbness: 80 if (setexit() == 0) 81 filioerr(tfname); 82 else 83 putNFL(); 84 cleanup(1); 85 exit(++errcnt); 86 } 87 if (!ISDIR(stbuf)) { 88 errno = ENOTDIR; 89 goto dumbness; 90 } 91 CP(tempname, tfname); 92 ichanged = 0; 93 ichang2 = 0; 94 (void) strcat(tfname, "/ExXXXXXX"); 95 if ((tfile = mkstemp((char *)tfname)) < 0) 96 goto dumbness; 97 #ifdef VMUNIX 98 { 99 extern int stilinc; /* see below */ 100 stilinc = 0; 101 } 102 #endif 103 havetmp = 1; 104 /* brk((unsigned char *)fendcore); */ 105 } 106 107 void 108 cleanup(bool all) 109 { 110 pid_t pgrp; 111 if (all) { 112 if (kflag) 113 crypt_close(perm); 114 if (xtflag) 115 crypt_close(tperm); 116 putpad((unsigned char *)exit_ca_mode); 117 flush(); 118 if (ioctl(2, TIOCGPGRP, &pgrp) == 0) { 119 if (pgrp == getpgid(0)) { 120 #ifdef XPG4 121 if (envlines != -1 || envcolumns != -1) { 122 struct winsize jwin; 123 jwin.ws_row = oldlines; 124 jwin.ws_col = oldcolumns; 125 ioctl(0, TIOCSWINSZ, &jwin); 126 } 127 #endif /* XPG4 */ 128 resetterm(); 129 normtty--; 130 } 131 } else { 132 #ifdef XPG4 133 if (envlines != -1 || envcolumns != -1) { 134 struct winsize jwin; 135 jwin.ws_row = oldlines; 136 jwin.ws_col = oldcolumns; 137 ioctl(0, TIOCSWINSZ, &jwin); 138 } 139 #endif /* XPG4 */ 140 resetterm(); 141 normtty--; 142 } 143 } 144 if (havetmp) 145 unlink((char *)tfname); 146 havetmp = 0; 147 if (all && rfile >= 0) { 148 unlink((char *)rfname); 149 close(rfile); 150 rfile = -1; 151 } 152 if (all == 1) 153 exit(errcnt); 154 } 155 156 void 157 getaline(line tl) 158 { 159 unsigned char *bp, *lp; 160 int nl; 161 162 lp = linebuf; 163 bp = getblock(tl, READ); 164 nl = nleft; 165 tl &= ~OFFMSK; 166 while (*lp++ = *bp++) 167 if (--nl == 0) { 168 bp = getblock(tl += INCRMT, READ); 169 nl = nleft; 170 } 171 } 172 173 int 174 putline(void) 175 { 176 unsigned char *bp, *lp; 177 unsigned char tmpbp; 178 int nl; 179 line tl; 180 181 dirtcnt++; 182 lp = linebuf; 183 change(); 184 tl = tline; 185 bp = getblock(tl, WRITE); 186 nl = nleft; 187 tl &= ~OFFMSK; 188 while (*bp = *lp++) { 189 tmpbp = *bp; 190 if (tmpbp == '\n') { 191 *bp = 0; 192 linebp = lp; 193 break; 194 } else if (junk(*bp++)) { 195 checkjunk(tmpbp); 196 *--bp; 197 } 198 if (--nl == 0) { 199 bp = getblock(tl += INCRMT, WRITE); 200 nl = nleft; 201 } 202 } 203 tl = tline; 204 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 205 return (tl); 206 } 207 208 int read(); 209 int write(); 210 211 unsigned char * 212 getblock(atl, iof) 213 line atl; 214 int iof; 215 { 216 int bno, off; 217 unsigned char *p1, *p2; 218 int n; 219 line *tmpptr; 220 221 bno = (atl >> OFFBTS) & BLKMSK; 222 off = (atl << SHFT) & LBTMSK; 223 if (bno >= NMBLKS) { 224 /* 225 * When we overflow tmpfile buffers, 226 * throw away line which could not be 227 * put into buffer. 228 */ 229 for (tmpptr = dot; tmpptr < unddol; tmpptr++) 230 *tmpptr = *(tmpptr+1); 231 if (dot == dol) 232 dot--; 233 dol--; 234 unddol--; 235 error(gettext(" Tmp file too large")); 236 } 237 nleft = BUFSIZE - off; 238 if (bno == iblock) { 239 ichanged |= iof; 240 hitin2 = 0; 241 return (ibuff + off); 242 } 243 if (bno == iblock2) { 244 ichang2 |= iof; 245 hitin2 = 1; 246 return (ibuff2 + off); 247 } 248 if (bno == oblock) 249 return (obuff + off); 250 if (iof == READ) { 251 if (hitin2 == 0) { 252 if (ichang2) { 253 if (xtflag) 254 if (run_crypt(0L, ibuff2, 255 CRSIZE, tperm) == -1) 256 filioerr(tfname); 257 blkio(iblock2, ibuff2, write); 258 } 259 ichang2 = 0; 260 iblock2 = bno; 261 blkio(bno, ibuff2, read); 262 if (xtflag) 263 if (run_crypt(0L, ibuff2, CRSIZE, tperm) == -1) 264 filioerr(tfname); 265 hitin2 = 1; 266 return (ibuff2 + off); 267 } 268 hitin2 = 0; 269 if (ichanged) { 270 if (xtflag) 271 if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1) 272 filioerr(tfname); 273 blkio(iblock, ibuff, write); 274 } 275 ichanged = 0; 276 iblock = bno; 277 blkio(bno, ibuff, read); 278 if (xtflag) 279 if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1) 280 filioerr(tfname); 281 return (ibuff + off); 282 } 283 if (oblock >= 0) { 284 if (xtflag) { 285 /* 286 * Encrypt block before writing, so some devious 287 * person can't look at temp file while editing. 288 */ 289 p1 = obuff; 290 p2 = crbuf; 291 n = CRSIZE; 292 while (n--) 293 *p2++ = *p1++; 294 if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1) 295 filioerr(tfname); 296 blkio(oblock, crbuf, write); 297 } else 298 blkio(oblock, obuff, write); 299 } 300 oblock = bno; 301 return (obuff + off); 302 } 303 304 #ifdef VMUNIX 305 #define INCORB 64 306 unsigned char incorb[INCORB+1][BUFSIZE]; 307 #define pagrnd(a) ((unsigned char *)(((int)a)&~(BUFSIZE-1))) 308 int stilinc; /* up to here not written yet */ 309 #endif 310 311 void 312 blkio(short b, unsigned char *buf, int (*iofcn)()) 313 { 314 315 #ifdef VMUNIX 316 if (b < INCORB) { 317 if (iofcn == read) { 318 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZE); 319 return; 320 } 321 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZE); 322 if (laste) { 323 if (b >= stilinc) 324 stilinc = b + 1; 325 return; 326 } 327 } else if (stilinc) 328 tflush(); 329 #endif 330 lseek(tfile, (long)(unsigned)b * BUFSIZE, 0); 331 if ((*iofcn)(tfile, buf, BUFSIZE) != BUFSIZE) 332 filioerr(tfname); 333 } 334 335 #ifdef VMUNIX 336 void 337 tlaste(void) 338 { 339 340 if (stilinc) 341 dirtcnt = 0; 342 } 343 344 void 345 tflush(void) 346 { 347 int i = stilinc; 348 349 stilinc = 0; 350 lseek(tfile, (long)0, 0); 351 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZE) != (i * BUFSIZE)) 352 filioerr(tfname); 353 } 354 #endif 355 356 /* 357 * Synchronize the state of the temporary file in case 358 * a crash occurs. 359 */ 360 void 361 synctmp(void) 362 { 363 int cnt; 364 line *a; 365 short *bp; 366 unsigned char *p1, *p2; 367 int n; 368 369 #ifdef VMUNIX 370 if (stilinc) 371 return; 372 #endif 373 if (dol == zero) 374 return; 375 /* 376 * In theory, we need to encrypt iblock and iblock2 before writing 377 * them out, as well as oblock, but in practice ichanged and ichang2 378 * can never be set, so this isn't really needed. Likewise, the 379 * code in getblock above for iblock+iblock2 isn't needed. 380 */ 381 if (ichanged) 382 blkio(iblock, ibuff, write); 383 ichanged = 0; 384 if (ichang2) 385 blkio(iblock2, ibuff2, write); 386 ichang2 = 0; 387 if (oblock != -1) 388 if (xtflag) { 389 /* 390 * Encrypt block before writing, so some devious 391 * person can't look at temp file while editing. 392 */ 393 p1 = obuff; 394 p2 = crbuf; 395 n = CRSIZE; 396 while (n--) 397 *p2++ = *p1++; 398 if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1) 399 filioerr(tfname); 400 blkio(oblock, crbuf, write); 401 } else 402 blkio(oblock, obuff, write); 403 time(&H.Time); 404 uid = getuid(); 405 if (xtflag) 406 H.encrypted = 1; 407 else 408 H.encrypted = 0; 409 *zero = (line) H.Time; 410 for (a = zero, bp = blocks; a <= dol; 411 a += BUFSIZE / sizeof (*a), bp++) { 412 if (bp >= &H.Blocks[LBLKS-1]) 413 error(gettext( 414 "file too large to recover with -r option")); 415 if (*bp < 0) { 416 tline = (tline + OFFMSK) &~ OFFMSK; 417 *bp = ((tline >> OFFBTS) & BLKMSK); 418 if (*bp > NMBLKS) 419 error(gettext(" Tmp file too large")); 420 tline += INCRMT; 421 oblock = *bp + 1; 422 bp[1] = -1; 423 } 424 lseek(tfile, (long)(unsigned)*bp * BUFSIZE, 0); 425 cnt = ((dol - a) + 2) * sizeof (line); 426 if (cnt > BUFSIZE) 427 cnt = BUFSIZE; 428 if (write(tfile, (char *)a, cnt) != cnt) { 429 oops: 430 *zero = 0; 431 filioerr(tfname); 432 } 433 *zero = 0; 434 } 435 flines = lineDOL(); 436 lseek(tfile, 0l, 0); 437 if (write(tfile, (char *)&H, sizeof (H)) != sizeof (H)) 438 goto oops; 439 } 440 441 void 442 TSYNC(void) 443 { 444 445 if (dirtcnt > MAXDIRT) { 446 #ifdef VMUNIX 447 if (stilinc) 448 tflush(); 449 #endif 450 dirtcnt = 0; 451 synctmp(); 452 } 453 } 454 455 /* 456 * Named buffer routines. 457 * These are implemented differently than the main buffer. 458 * Each named buffer has a chain of blocks in the register file. 459 * Each block contains roughly 508 chars of text, 460 * and a previous and next block number. We also have information 461 * about which blocks came from deletes of multiple partial lines, 462 * e.g. deleting a sentence or a LISP object. 463 * 464 * We maintain a free map for the temp file. To free the blocks 465 * in a register we must read the blocks to find how they are chained 466 * together. 467 * 468 * BUG: The default savind of deleted lines in numbered 469 * buffers may be rather inefficient; it hasn't been profiled. 470 */ 471 struct strreg { 472 short rg_flags; 473 short rg_nleft; 474 short rg_first; 475 short rg_last; 476 } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 477 478 struct rbuf { 479 short rb_prev; 480 short rb_next; 481 unsigned char rb_text[BUFSIZE - 2 * sizeof (short)]; 482 } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; 483 #ifdef VMUNIX 484 short rused[256]; 485 #else 486 short rused[32]; 487 #endif 488 short rnleft; 489 short rblock; 490 short rnext; 491 unsigned char *rbufcp; 492 493 void 494 regio(short b, int (*iofcn)()) 495 { 496 497 if (rfile == -1) { 498 CP(rfname, tempname); 499 (void) strcat(rfname, "/RxXXXXXX"); 500 if ((rfile = mkstemp((char *)rfname)) < 0) 501 filioerr(rfname); 502 } 503 lseek(rfile, (long)b * BUFSIZE, 0); 504 if ((*iofcn)(rfile, rbuf, BUFSIZE) != BUFSIZE) 505 filioerr(rfname); 506 rblock = b; 507 } 508 509 int 510 REGblk(void) 511 { 512 int i, j, m; 513 514 for (i = 0; i < sizeof (rused) / sizeof (rused[0]); i++) { 515 m = (rused[i] ^ 0177777) & 0177777; 516 if (i == 0) 517 m &= ~1; 518 if (m != 0) { 519 j = 0; 520 while ((m & 1) == 0) 521 j++, m >>= 1; 522 rused[i] |= (1 << j); 523 #ifdef RDEBUG 524 viprintf("allocating block %d\n", i * 16 + j); 525 #endif 526 return (i * 16 + j); 527 } 528 } 529 error(gettext("Out of register space (ugh)")); 530 /*NOTREACHED*/ 531 return (0); 532 } 533 534 struct strreg * 535 mapreg(c) 536 int c; 537 { 538 539 if (isupper(c)) 540 c = tolower(c); 541 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 542 } 543 544 int shread(); 545 546 void 547 KILLreg(int c) 548 { 549 struct strreg *sp; 550 551 rbuf = &KILLrbuf; 552 sp = mapreg(c); 553 rblock = sp->rg_first; 554 sp->rg_first = sp->rg_last = 0; 555 sp->rg_flags = sp->rg_nleft = 0; 556 while (rblock != 0) { 557 #ifdef RDEBUG 558 viprintf("freeing block %d\n", rblock); 559 #endif 560 rused[rblock / 16] &= ~(1 << (rblock % 16)); 561 regio(rblock, shread); 562 rblock = rbuf->rb_next; 563 } 564 } 565 566 /*VARARGS*/ 567 int 568 shread(void) 569 { 570 struct front { short a; short b; }; 571 572 if (read(rfile, (char *)rbuf, sizeof (struct front)) == 573 sizeof (struct front)) 574 return (sizeof (struct rbuf)); 575 return (0); 576 } 577 578 int getREG(); 579 580 int 581 putreg(unsigned char c) 582 { 583 line *odot = dot; 584 line *odol = dol; 585 int cnt; 586 587 deletenone(); 588 appendnone(); 589 rbuf = &putrbuf; 590 rnleft = 0; 591 rblock = 0; 592 rnext = mapreg(c)->rg_first; 593 if (rnext == 0) { 594 if (inopen) { 595 splitw++; 596 vclean(); 597 vgoto(WECHO, 0); 598 } 599 vreg = -1; 600 error(gettext("Nothing in register %c"), c); 601 } 602 if (inopen && partreg(c)) { 603 if (!FIXUNDO) { 604 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 605 error(gettext("Can't put partial line inside macro")); 606 } 607 squish(); 608 addr1 = addr2 = dol; 609 } 610 cnt = append(getREG, addr2); 611 if (inopen && partreg(c)) { 612 unddol = dol; 613 dol = odol; 614 dot = odot; 615 pragged(0); 616 } 617 killcnt(cnt); 618 notecnt = cnt; 619 return (0); 620 } 621 622 short 623 partreg(unsigned char c) 624 { 625 626 return (mapreg(c)->rg_flags); 627 } 628 629 void 630 notpart(int c) 631 { 632 633 if (c) 634 mapreg(c)->rg_flags = 0; 635 } 636 637 int 638 getREG(void) 639 { 640 unsigned char *lp = linebuf; 641 int c; 642 643 for (;;) { 644 if (rnleft == 0) { 645 if (rnext == 0) 646 return (EOF); 647 regio(rnext, read); 648 rnext = rbuf->rb_next; 649 rbufcp = rbuf->rb_text; 650 rnleft = sizeof (rbuf->rb_text); 651 } 652 c = *rbufcp; 653 if (c == 0) 654 return (EOF); 655 rbufcp++, --rnleft; 656 if (c == '\n') { 657 *lp++ = 0; 658 return (0); 659 } 660 *lp++ = c; 661 } 662 } 663 664 int 665 YANKreg(int c) 666 { 667 line *addr; 668 struct strreg *sp; 669 unsigned char savelb[LBSIZE]; 670 671 if (isdigit(c)) 672 kshift(); 673 if (islower(c)) 674 KILLreg(c); 675 strp = sp = mapreg(c); 676 sp->rg_flags = inopen && cursor && wcursor; 677 rbuf = &YANKrbuf; 678 if (sp->rg_last) { 679 regio(sp->rg_last, read); 680 rnleft = sp->rg_nleft; 681 rbufcp = &rbuf->rb_text[sizeof (rbuf->rb_text) - rnleft]; 682 } else { 683 rblock = 0; 684 rnleft = 0; 685 } 686 CP(savelb, linebuf); 687 for (addr = addr1; addr <= addr2; addr++) { 688 getaline(*addr); 689 if (sp->rg_flags) { 690 if (addr == addr2) 691 *wcursor = 0; 692 if (addr == addr1) 693 strcpy(linebuf, cursor); 694 } 695 YANKline(); 696 } 697 rbflush(); 698 killed(); 699 CP(linebuf, savelb); 700 return (0); 701 } 702 703 void 704 kshift(void) 705 { 706 int i; 707 708 KILLreg('9'); 709 for (i = '8'; i >= '0'; i--) 710 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 711 } 712 713 void 714 YANKline(void) 715 { 716 unsigned char *lp = linebuf; 717 struct rbuf *rp = rbuf; 718 int c; 719 720 do { 721 c = *lp++; 722 if (c == 0) 723 c = '\n'; 724 if (rnleft == 0) { 725 rp->rb_next = REGblk(); 726 rbflush(); 727 rblock = rp->rb_next; 728 rp->rb_next = 0; 729 rp->rb_prev = rblock; 730 rnleft = sizeof (rp->rb_text); 731 rbufcp = rp->rb_text; 732 } 733 *rbufcp++ = c; 734 --rnleft; 735 } while (c != '\n'); 736 if (rnleft) 737 *rbufcp = 0; 738 } 739 740 void 741 rbflush(void) 742 { 743 struct strreg *sp = strp; 744 745 if (rblock == 0) 746 return; 747 regio(rblock, write); 748 if (sp->rg_first == 0) 749 sp->rg_first = rblock; 750 sp->rg_last = rblock; 751 sp->rg_nleft = rnleft; 752 } 753 754 /* Register c to char buffer buf of size buflen */ 755 void 756 regbuf(c, buf, buflen) 757 unsigned char c; 758 unsigned char *buf; 759 int buflen; 760 { 761 unsigned char *p, *lp; 762 763 rbuf = ®rbuf; 764 rnleft = 0; 765 rblock = 0; 766 rnext = mapreg(c)->rg_first; 767 if (rnext == 0) { 768 *buf = 0; 769 error(gettext("Nothing in register %c"), c); 770 } 771 p = buf; 772 while (getREG() == 0) { 773 lp = linebuf; 774 while (*lp) { 775 if (p >= &buf[buflen]) 776 error(value(vi_TERSE) ? 777 gettext("Register too long") : gettext("Register too long to fit in memory")); 778 *p++ = *lp++; 779 } 780 *p++ = '\n'; 781 } 782 if (partreg(c)) p--; 783 *p = '\0'; 784 getDOT(); 785 } 786 787 #ifdef TRACE 788 789 /* 790 * Test code for displaying named registers. 791 */ 792 793 shownam() 794 { 795 int k; 796 797 viprintf("\nRegister Contents\n"); 798 viprintf("======== ========\n"); 799 for (k = 'a'; k <= 'z'; k++) { 800 rbuf = &putrbuf; 801 rnleft = 0; 802 rblock = 0; 803 rnext = mapreg(k)->rg_first; 804 viprintf(" %c:", k); 805 if (rnext == 0) 806 viprintf("\t\tNothing in register.\n"); 807 while (getREG() == 0) { 808 viprintf("\t\t%s\n", linebuf); 809 } 810 } 811 return (0); 812 } 813 814 /* 815 * Test code for displaying numbered registers. 816 */ 817 818 shownbr() 819 { 820 int k; 821 822 viprintf("\nRegister Contents\n"); 823 viprintf("======== ========\n"); 824 for (k = '1'; k <= '9'; k++) { 825 rbuf = &putrbuf; 826 rnleft = 0; 827 rblock = 0; 828 rnext = mapreg(k)->rg_first; 829 viprintf(" %c:", k); 830 if (rnext == 0) 831 viprintf("\t\tNothing in register.\n"); 832 while (getREG() == 0) { 833 viprintf("\t\t%s\n", linebuf); 834 } 835 } 836 return (0); 837 } 838 #endif 839