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(line atl, int iof) 213 { 214 int bno, off; 215 unsigned char *p1, *p2; 216 int n; 217 line *tmpptr; 218 219 bno = (atl >> OFFBTS) & BLKMSK; 220 off = (atl << SHFT) & LBTMSK; 221 if (bno >= NMBLKS) { 222 /* 223 * When we overflow tmpfile buffers, 224 * throw away line which could not be 225 * put into buffer. 226 */ 227 for (tmpptr = dot; tmpptr < unddol; tmpptr++) 228 *tmpptr = *(tmpptr+1); 229 if (dot == dol) 230 dot--; 231 dol--; 232 unddol--; 233 error(gettext(" Tmp file too large")); 234 } 235 nleft = BUFSIZE - off; 236 if (bno == iblock) { 237 ichanged |= iof; 238 hitin2 = 0; 239 return (ibuff + off); 240 } 241 if (bno == iblock2) { 242 ichang2 |= iof; 243 hitin2 = 1; 244 return (ibuff2 + off); 245 } 246 if (bno == oblock) 247 return (obuff + off); 248 if (iof == READ) { 249 if (hitin2 == 0) { 250 if (ichang2) { 251 if (xtflag) { 252 if (run_crypt(0L, ibuff2, 253 CRSIZE, tperm) == -1) { 254 filioerr(tfname); 255 } 256 } 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(int c) 536 { 537 538 if (isupper(c)) 539 c = tolower(c); 540 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 541 } 542 543 int shread(); 544 545 void 546 KILLreg(int c) 547 { 548 struct strreg *sp; 549 550 rbuf = &KILLrbuf; 551 sp = mapreg(c); 552 rblock = sp->rg_first; 553 sp->rg_first = sp->rg_last = 0; 554 sp->rg_flags = sp->rg_nleft = 0; 555 while (rblock != 0) { 556 #ifdef RDEBUG 557 viprintf("freeing block %d\n", rblock); 558 #endif 559 rused[rblock / 16] &= ~(1 << (rblock % 16)); 560 regio(rblock, shread); 561 rblock = rbuf->rb_next; 562 } 563 } 564 565 /*VARARGS*/ 566 int 567 shread(void) 568 { 569 struct front { short a; short b; }; 570 571 if (read(rfile, (char *)rbuf, sizeof (struct front)) == 572 sizeof (struct front)) 573 return (sizeof (struct rbuf)); 574 return (0); 575 } 576 577 int getREG(); 578 579 int 580 putreg(unsigned char c) 581 { 582 line *odot = dot; 583 line *odol = dol; 584 int cnt; 585 586 deletenone(); 587 appendnone(); 588 rbuf = &putrbuf; 589 rnleft = 0; 590 rblock = 0; 591 rnext = mapreg(c)->rg_first; 592 if (rnext == 0) { 593 if (inopen) { 594 splitw++; 595 vclean(); 596 vgoto(WECHO, 0); 597 } 598 vreg = -1; 599 error(gettext("Nothing in register %c"), c); 600 } 601 if (inopen && partreg(c)) { 602 if (!FIXUNDO) { 603 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 604 error(gettext("Can't put partial line inside macro")); 605 } 606 squish(); 607 addr1 = addr2 = dol; 608 } 609 cnt = append(getREG, addr2); 610 if (inopen && partreg(c)) { 611 unddol = dol; 612 dol = odol; 613 dot = odot; 614 pragged(0); 615 } 616 killcnt(cnt); 617 notecnt = cnt; 618 return (0); 619 } 620 621 short 622 partreg(unsigned char c) 623 { 624 625 return (mapreg(c)->rg_flags); 626 } 627 628 void 629 notpart(int c) 630 { 631 632 if (c) 633 mapreg(c)->rg_flags = 0; 634 } 635 636 int 637 getREG(void) 638 { 639 unsigned char *lp = linebuf; 640 int c; 641 642 for (;;) { 643 if (rnleft == 0) { 644 if (rnext == 0) 645 return (EOF); 646 regio(rnext, read); 647 rnext = rbuf->rb_next; 648 rbufcp = rbuf->rb_text; 649 rnleft = sizeof (rbuf->rb_text); 650 } 651 c = *rbufcp; 652 if (c == 0) 653 return (EOF); 654 rbufcp++, --rnleft; 655 if (c == '\n') { 656 *lp++ = 0; 657 return (0); 658 } 659 *lp++ = c; 660 } 661 } 662 663 int 664 YANKreg(int c) 665 { 666 line *addr; 667 struct strreg *sp; 668 unsigned char savelb[LBSIZE]; 669 670 if (isdigit(c)) 671 kshift(); 672 if (islower(c)) 673 KILLreg(c); 674 strp = sp = mapreg(c); 675 sp->rg_flags = inopen && cursor && wcursor; 676 rbuf = &YANKrbuf; 677 if (sp->rg_last) { 678 regio(sp->rg_last, read); 679 rnleft = sp->rg_nleft; 680 rbufcp = &rbuf->rb_text[sizeof (rbuf->rb_text) - rnleft]; 681 } else { 682 rblock = 0; 683 rnleft = 0; 684 } 685 CP(savelb, linebuf); 686 for (addr = addr1; addr <= addr2; addr++) { 687 getaline(*addr); 688 if (sp->rg_flags) { 689 if (addr == addr2) 690 *wcursor = 0; 691 if (addr == addr1) 692 strcpy(linebuf, cursor); 693 } 694 YANKline(); 695 } 696 rbflush(); 697 killed(); 698 CP(linebuf, savelb); 699 return (0); 700 } 701 702 void 703 kshift(void) 704 { 705 int i; 706 707 KILLreg('9'); 708 for (i = '8'; i >= '0'; i--) 709 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 710 } 711 712 void 713 YANKline(void) 714 { 715 unsigned char *lp = linebuf; 716 struct rbuf *rp = rbuf; 717 int c; 718 719 do { 720 c = *lp++; 721 if (c == 0) 722 c = '\n'; 723 if (rnleft == 0) { 724 rp->rb_next = REGblk(); 725 rbflush(); 726 rblock = rp->rb_next; 727 rp->rb_next = 0; 728 rp->rb_prev = rblock; 729 rnleft = sizeof (rp->rb_text); 730 rbufcp = rp->rb_text; 731 } 732 *rbufcp++ = c; 733 --rnleft; 734 } while (c != '\n'); 735 if (rnleft) 736 *rbufcp = 0; 737 } 738 739 void 740 rbflush(void) 741 { 742 struct strreg *sp = strp; 743 744 if (rblock == 0) 745 return; 746 regio(rblock, write); 747 if (sp->rg_first == 0) 748 sp->rg_first = rblock; 749 sp->rg_last = rblock; 750 sp->rg_nleft = rnleft; 751 } 752 753 /* Register c to char buffer buf of size buflen */ 754 void 755 regbuf(unsigned char c, unsigned char *buf, int buflen) 756 { 757 unsigned char *p, *lp; 758 759 rbuf = ®rbuf; 760 rnleft = 0; 761 rblock = 0; 762 rnext = mapreg(c)->rg_first; 763 if (rnext == 0) { 764 *buf = 0; 765 error(gettext("Nothing in register %c"), c); 766 } 767 p = buf; 768 while (getREG() == 0) { 769 lp = linebuf; 770 while (*lp) { 771 if (p >= &buf[buflen]) 772 error(value(vi_TERSE) ? 773 gettext("Register too long") : gettext("Register too long to fit in memory")); 774 *p++ = *lp++; 775 } 776 *p++ = '\n'; 777 } 778 if (partreg(c)) p--; 779 *p = '\0'; 780 getDOT(); 781 } 782 783 #ifdef TRACE 784 785 /* 786 * Test code for displaying named registers. 787 */ 788 789 shownam() 790 { 791 int k; 792 793 viprintf("\nRegister Contents\n"); 794 viprintf("======== ========\n"); 795 for (k = 'a'; k <= 'z'; k++) { 796 rbuf = &putrbuf; 797 rnleft = 0; 798 rblock = 0; 799 rnext = mapreg(k)->rg_first; 800 viprintf(" %c:", k); 801 if (rnext == 0) 802 viprintf("\t\tNothing in register.\n"); 803 while (getREG() == 0) { 804 viprintf("\t\t%s\n", linebuf); 805 } 806 } 807 return (0); 808 } 809 810 /* 811 * Test code for displaying numbered registers. 812 */ 813 814 shownbr() 815 { 816 int k; 817 818 viprintf("\nRegister Contents\n"); 819 viprintf("======== ========\n"); 820 for (k = '1'; k <= '9'; k++) { 821 rbuf = &putrbuf; 822 rnleft = 0; 823 rblock = 0; 824 rnext = mapreg(k)->rg_first; 825 viprintf(" %c:", k); 826 if (rnext == 0) 827 viprintf("\t\tNothing in register.\n"); 828 while (getREG() == 0) { 829 viprintf("\t\t%s\n", linebuf); 830 } 831 } 832 return (0); 833 } 834 #endif 835