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 45unsigned char tfname[PATH_MAX+1]; 46static unsigned char rfname[PATH_MAX+1]; 47static unsigned char tempname[PATH_MAX+1]; 48int havetmp; 49short tfile = -1; 50static short rfile = -1; 51 52extern int junk(); 53 54void 55fileinit(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)) { 79dumbness: 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 107void 108cleanup(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 156void 157getaline(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 173int 174putline(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 208int read(); 209int write(); 210 211unsigned char * 212getblock(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 306unsigned char incorb[INCORB+1][BUFSIZE]; 307#define pagrnd(a) ((unsigned char *)(((int)a)&~(BUFSIZE-1))) 308int stilinc; /* up to here not written yet */ 309#endif 310 311void 312blkio(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 336void 337tlaste(void) 338{ 339 340 if (stilinc) 341 dirtcnt = 0; 342} 343 344void 345tflush(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 */ 360void 361synctmp(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) { 429oops: 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 441void 442TSYNC(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 */ 471struct 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 478struct 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 484short rused[256]; 485#else 486short rused[32]; 487#endif 488short rnleft; 489short rblock; 490short rnext; 491unsigned char *rbufcp; 492 493void 494regio(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 509int 510REGblk(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 534struct strreg * 535mapreg(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 544int shread(); 545 546void 547KILLreg(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*/ 567int 568shread(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 578int getREG(); 579 580int 581putreg(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 622short 623partreg(unsigned char c) 624{ 625 626 return (mapreg(c)->rg_flags); 627} 628 629void 630notpart(int c) 631{ 632 633 if (c) 634 mapreg(c)->rg_flags = 0; 635} 636 637int 638getREG(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 664int 665YANKreg(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 703void 704kshift(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 713void 714YANKline(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 740void 741rbflush(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 */ 755void 756regbuf(c, buf, buflen) 757unsigned char c; 758unsigned char *buf; 759int 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) ? 777gettext("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 793shownam() 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 818shownbr() 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