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