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 40 /* 41 * Editor temporary file routines. 42 * Very similar to those of ed, except uses 2 input buffers. 43 */ 44 #define READ 0 45 #define WRITE 1 46 47 unsigned char tfname[PATH_MAX+1]; 48 static unsigned char rfname[PATH_MAX+1]; 49 static unsigned char tempname[PATH_MAX+1]; 50 int havetmp; 51 short tfile = -1; 52 static short rfile = -1; 53 54 extern int junk(); 55 extern int checkjunk(); 56 57 fileinit() 58 { 59 register unsigned char *p; 60 register pid_t j; 61 register int i; 62 struct stat64 stbuf; 63 64 if (tline == INCRMT * (HBLKS+2)) 65 return; 66 cleanup(0); 67 if (tfile != -1) 68 close(tfile); 69 tline = INCRMT * (HBLKS+2); 70 blocks[0] = HBLKS; 71 blocks[1] = HBLKS+1; 72 blocks[2] = -1; 73 dirtcnt = 0; 74 iblock = -1; 75 iblock2 = -1; 76 oblock = -1; 77 if (strlen(svalue(vi_DIRECTORY)) > (PATH_MAX -13)) 78 error(gettext("User set directory too long")); 79 CP(tfname, svalue(vi_DIRECTORY)); 80 if (stat64((char *)tfname, &stbuf)) { 81 dumbness: 82 if (setexit() == 0) 83 filioerr(tfname); 84 else 85 putNFL(); 86 cleanup(1); 87 exit(++errcnt); 88 } 89 if (!ISDIR(stbuf)) { 90 errno = ENOTDIR; 91 goto dumbness; 92 } 93 CP(tempname, tfname); 94 ichanged = 0; 95 ichang2 = 0; 96 (void) strcat(tfname, "/ExXXXXXX"); 97 if ((tfile = mkstemp((char *)tfname)) < 0) 98 goto dumbness; 99 #ifdef VMUNIX 100 { 101 extern stilinc; /* see below */ 102 stilinc = 0; 103 } 104 #endif 105 havetmp = 1; 106 /* brk((unsigned char *)fendcore); */ 107 } 108 109 cleanup(all) 110 bool all; 111 { 112 pid_t pgrp; 113 if (all) { 114 if (kflag) 115 crypt_close(perm); 116 if (xtflag) 117 crypt_close(tperm); 118 putpad(exit_ca_mode); 119 flush(); 120 if (ioctl(2, TIOCGPGRP, &pgrp) == 0) { 121 if (pgrp == getpgid(0)) { 122 #ifdef XPG4 123 if (envlines != -1 || envcolumns != -1) { 124 struct winsize jwin; 125 jwin.ws_row = oldlines; 126 jwin.ws_col = oldcolumns; 127 ioctl(0, TIOCSWINSZ, &jwin); 128 } 129 #endif /* XPG4 */ 130 resetterm(); 131 normtty--; 132 } 133 } else { 134 #ifdef XPG4 135 if (envlines != -1 || envcolumns != -1) { 136 struct winsize jwin; 137 jwin.ws_row = oldlines; 138 jwin.ws_col = oldcolumns; 139 ioctl(0, TIOCSWINSZ, &jwin); 140 } 141 #endif /* XPG4 */ 142 resetterm(); 143 normtty--; 144 } 145 } 146 if (havetmp) 147 unlink(tfname); 148 havetmp = 0; 149 if (all && rfile >= 0) { 150 unlink(rfname); 151 close(rfile); 152 rfile = -1; 153 } 154 if (all == 1) 155 exit(errcnt); 156 } 157 158 getline(tl) 159 line tl; 160 { 161 register unsigned char *bp, *lp; 162 register int nl; 163 164 lp = linebuf; 165 bp = getblock(tl, READ); 166 nl = nleft; 167 tl &= ~OFFMSK; 168 while (*lp++ = *bp++) 169 if (--nl == 0) { 170 bp = getblock(tl += INCRMT, READ); 171 nl = nleft; 172 } 173 } 174 175 int 176 putline(void) 177 { 178 unsigned char *bp, *lp; 179 unsigned char tmpbp; 180 int nl; 181 line tl; 182 183 dirtcnt++; 184 lp = linebuf; 185 change(); 186 tl = tline; 187 bp = getblock(tl, WRITE); 188 nl = nleft; 189 tl &= ~OFFMSK; 190 while (*bp = *lp++) { 191 tmpbp = *bp; 192 if (tmpbp == '\n') { 193 *bp = 0; 194 linebp = lp; 195 break; 196 } else if (junk(*bp++)) { 197 (void) checkjunk(tmpbp); 198 *--bp; 199 } 200 if (--nl == 0) { 201 bp = getblock(tl += INCRMT, WRITE); 202 nl = nleft; 203 } 204 } 205 tl = tline; 206 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 207 return (tl); 208 } 209 210 int read(); 211 int write(); 212 213 unsigned char * 214 getblock(atl, iof) 215 line atl; 216 int iof; 217 { 218 register int bno, off; 219 register unsigned char *p1, *p2; 220 register int n; 221 line *tmpptr; 222 223 bno = (atl >> OFFBTS) & BLKMSK; 224 off = (atl << SHFT) & LBTMSK; 225 if (bno >= NMBLKS) { 226 /* 227 * When we overflow tmpfile buffers, 228 * throw away line which could not be 229 * put into buffer. 230 */ 231 for (tmpptr = dot; tmpptr < unddol; tmpptr++) 232 *tmpptr = *(tmpptr+1); 233 if (dot == dol) 234 dot--; 235 dol--; 236 unddol--; 237 error(gettext(" Tmp file too large")); 238 } 239 nleft = BUFSIZE - off; 240 if (bno == iblock) { 241 ichanged |= iof; 242 hitin2 = 0; 243 return (ibuff + off); 244 } 245 if (bno == iblock2) { 246 ichang2 |= iof; 247 hitin2 = 1; 248 return (ibuff2 + off); 249 } 250 if (bno == oblock) 251 return (obuff + off); 252 if (iof == READ) { 253 if (hitin2 == 0) { 254 if (ichang2) { 255 if (xtflag) 256 if (run_crypt(0L, ibuff2, 257 CRSIZE, tperm) == -1) 258 filioerr(tfname); 259 blkio(iblock2, ibuff2, write); 260 } 261 ichang2 = 0; 262 iblock2 = bno; 263 blkio(bno, ibuff2, read); 264 if (xtflag) 265 if (run_crypt(0L, ibuff2, CRSIZE, tperm) == -1) 266 filioerr(tfname); 267 hitin2 = 1; 268 return (ibuff2 + off); 269 } 270 hitin2 = 0; 271 if (ichanged) { 272 if (xtflag) 273 if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1) 274 filioerr(tfname); 275 blkio(iblock, ibuff, write); 276 } 277 ichanged = 0; 278 iblock = bno; 279 blkio(bno, ibuff, read); 280 if (xtflag) 281 if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1) 282 filioerr(tfname); 283 return (ibuff + off); 284 } 285 if (oblock >= 0) { 286 if (xtflag) { 287 /* 288 * Encrypt block before writing, so some devious 289 * person can't look at temp file while editing. 290 */ 291 p1 = obuff; 292 p2 = crbuf; 293 n = CRSIZE; 294 while (n--) 295 *p2++ = *p1++; 296 if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1) 297 filioerr(tfname); 298 blkio(oblock, crbuf, write); 299 } else 300 blkio(oblock, obuff, write); 301 } 302 oblock = bno; 303 return (obuff + off); 304 } 305 306 #ifdef VMUNIX 307 #define INCORB 64 308 unsigned char incorb[INCORB+1][BUFSIZE]; 309 #define pagrnd(a) ((unsigned char *)(((int)a)&~(BUFSIZE-1))) 310 int stilinc; /* up to here not written yet */ 311 #endif 312 313 blkio(b, buf, iofcn) 314 short b; 315 unsigned char *buf; 316 int (*iofcn)(); 317 { 318 319 #ifdef VMUNIX 320 if (b < INCORB) { 321 if (iofcn == read) { 322 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZE); 323 return; 324 } 325 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZE); 326 if (laste) { 327 if (b >= stilinc) 328 stilinc = b + 1; 329 return; 330 } 331 } else if (stilinc) 332 tflush(); 333 #endif 334 lseek(tfile, (long)(unsigned)b * BUFSIZE, 0); 335 if ((*iofcn)(tfile, buf, BUFSIZE) != BUFSIZE) 336 filioerr(tfname); 337 } 338 339 #ifdef VMUNIX 340 tlaste() 341 { 342 343 if (stilinc) 344 dirtcnt = 0; 345 } 346 347 tflush() 348 { 349 int i = stilinc; 350 351 stilinc = 0; 352 lseek(tfile, (long)0, 0); 353 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZE) != (i * BUFSIZE)) 354 filioerr(tfname); 355 } 356 #endif 357 358 /* 359 * Synchronize the state of the temporary file in case 360 * a crash occurs. 361 */ 362 synctmp() 363 { 364 register int cnt; 365 register line *a; 366 register short *bp; 367 register unsigned char *p1, *p2; 368 register int n; 369 370 #ifdef VMUNIX 371 if (stilinc) 372 return; 373 #endif 374 if (dol == zero) 375 return; 376 /* 377 * In theory, we need to encrypt iblock and iblock2 before writing 378 * them out, as well as oblock, but in practice ichanged and ichang2 379 * can never be set, so this isn't really needed. Likewise, the 380 * code in getblock above for iblock+iblock2 isn't needed. 381 */ 382 if (ichanged) 383 blkio(iblock, ibuff, write); 384 ichanged = 0; 385 if (ichang2) 386 blkio(iblock2, ibuff2, write); 387 ichang2 = 0; 388 if (oblock != -1) 389 if (xtflag) { 390 /* 391 * Encrypt block before writing, so some devious 392 * person can't look at temp file while editing. 393 */ 394 p1 = obuff; 395 p2 = crbuf; 396 n = CRSIZE; 397 while (n--) 398 *p2++ = *p1++; 399 if (run_crypt(0L, crbuf, CRSIZE, tperm) == -1) 400 filioerr(tfname); 401 blkio(oblock, crbuf, write); 402 } else 403 blkio(oblock, obuff, write); 404 time(&H.Time); 405 uid = getuid(); 406 if (xtflag) 407 H.encrypted = 1; 408 else 409 H.encrypted = 0; 410 *zero = (line) H.Time; 411 for (a = zero, bp = blocks; a <= dol; 412 a += BUFSIZE / sizeof (*a), bp++) { 413 if (bp >= &H.Blocks[LBLKS-1]) 414 error(gettext( 415 "file too large to recover with -r option")); 416 if (*bp < 0) { 417 tline = (tline + OFFMSK) &~ OFFMSK; 418 *bp = ((tline >> OFFBTS) & BLKMSK); 419 if (*bp > NMBLKS) 420 error(gettext(" Tmp file too large")); 421 tline += INCRMT; 422 oblock = *bp + 1; 423 bp[1] = -1; 424 } 425 lseek(tfile, (long)(unsigned)*bp * BUFSIZE, 0); 426 cnt = ((dol - a) + 2) * sizeof (line); 427 if (cnt > BUFSIZE) 428 cnt = BUFSIZE; 429 if (write(tfile, (char *)a, cnt) != cnt) { 430 oops: 431 *zero = 0; 432 filioerr(tfname); 433 } 434 *zero = 0; 435 } 436 flines = lineDOL(); 437 lseek(tfile, 0l, 0); 438 if (write(tfile, (char *)&H, sizeof (H)) != sizeof (H)) 439 goto oops; 440 } 441 442 TSYNC() 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 regio(b, iofcn) 494 short b; 495 int (*iofcn)(); 496 { 497 498 if (rfile == -1) { 499 CP(rfname, tempname); 500 (void) strcat(rfname, "/RxXXXXXX"); 501 if ((rfile = mkstemp((char *)rfname)) < 0) 502 filioerr(rfname); 503 } 504 lseek(rfile, (long)b * BUFSIZE, 0); 505 if ((*iofcn)(rfile, rbuf, BUFSIZE) != BUFSIZE) 506 filioerr(rfname); 507 rblock = b; 508 } 509 510 REGblk() 511 { 512 register 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 printf("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 } 532 533 struct strreg * 534 mapreg(c) 535 register 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 KILLreg(c) 546 register int c; 547 { 548 register 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 printf("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 shread() 567 { 568 struct front { short a; short b; }; 569 570 if (read(rfile, (char *)rbuf, sizeof (struct front)) == 571 sizeof (struct front)) 572 return (sizeof (struct rbuf)); 573 return (0); 574 } 575 576 int getREG(); 577 578 putreg(c) 579 unsigned char c; 580 { 581 register line *odot = dot; 582 register line *odol = dol; 583 register int cnt; 584 585 deletenone(); 586 appendnone(); 587 rbuf = &putrbuf; 588 rnleft = 0; 589 rblock = 0; 590 rnext = mapreg(c)->rg_first; 591 if (rnext == 0) { 592 if (inopen) { 593 splitw++; 594 vclean(); 595 vgoto(WECHO, 0); 596 } 597 vreg = -1; 598 error(gettext("Nothing in register %c"), c); 599 } 600 if (inopen && partreg(c)) { 601 if (!FIXUNDO) { 602 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 603 error(gettext("Can't put partial line inside macro")); 604 } 605 squish(); 606 addr1 = addr2 = dol; 607 } 608 cnt = append(getREG, addr2); 609 if (inopen && partreg(c)) { 610 unddol = dol; 611 dol = odol; 612 dot = odot; 613 pragged(0); 614 } 615 killcnt(cnt); 616 notecnt = cnt; 617 } 618 619 partreg(c) 620 unsigned char c; 621 { 622 623 return (mapreg(c)->rg_flags); 624 } 625 626 notpart(c) 627 register int c; 628 { 629 630 if (c) 631 mapreg(c)->rg_flags = 0; 632 } 633 634 getREG() 635 { 636 register unsigned char *lp = linebuf; 637 register int c; 638 639 for (;;) { 640 if (rnleft == 0) { 641 if (rnext == 0) 642 return (EOF); 643 regio(rnext, read); 644 rnext = rbuf->rb_next; 645 rbufcp = rbuf->rb_text; 646 rnleft = sizeof (rbuf->rb_text); 647 } 648 c = *rbufcp; 649 if (c == 0) 650 return (EOF); 651 rbufcp++, --rnleft; 652 if (c == '\n') { 653 *lp++ = 0; 654 return (0); 655 } 656 *lp++ = c; 657 } 658 } 659 660 YANKreg(c) 661 register int c; 662 { 663 register line *addr; 664 register struct strreg *sp; 665 unsigned char savelb[LBSIZE]; 666 667 if (isdigit(c)) 668 kshift(); 669 if (islower(c)) 670 KILLreg(c); 671 strp = sp = mapreg(c); 672 sp->rg_flags = inopen && cursor && wcursor; 673 rbuf = &YANKrbuf; 674 if (sp->rg_last) { 675 regio(sp->rg_last, read); 676 rnleft = sp->rg_nleft; 677 rbufcp = &rbuf->rb_text[sizeof (rbuf->rb_text) - rnleft]; 678 } else { 679 rblock = 0; 680 rnleft = 0; 681 } 682 CP(savelb, linebuf); 683 for (addr = addr1; addr <= addr2; addr++) { 684 getline(*addr); 685 if (sp->rg_flags) { 686 if (addr == addr2) 687 *wcursor = 0; 688 if (addr == addr1) 689 strcpy(linebuf, cursor); 690 } 691 YANKline(); 692 } 693 rbflush(); 694 killed(); 695 CP(linebuf, savelb); 696 } 697 698 kshift() 699 { 700 register int i; 701 702 KILLreg('9'); 703 for (i = '8'; i >= '0'; i--) 704 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 705 } 706 707 YANKline() 708 { 709 register unsigned char *lp = linebuf; 710 register struct rbuf *rp = rbuf; 711 register int c; 712 713 do { 714 c = *lp++; 715 if (c == 0) 716 c = '\n'; 717 if (rnleft == 0) { 718 rp->rb_next = REGblk(); 719 rbflush(); 720 rblock = rp->rb_next; 721 rp->rb_next = 0; 722 rp->rb_prev = rblock; 723 rnleft = sizeof (rp->rb_text); 724 rbufcp = rp->rb_text; 725 } 726 *rbufcp++ = c; 727 --rnleft; 728 } while (c != '\n'); 729 if (rnleft) 730 *rbufcp = 0; 731 } 732 733 rbflush() 734 { 735 register struct strreg *sp = strp; 736 737 if (rblock == 0) 738 return; 739 regio(rblock, write); 740 if (sp->rg_first == 0) 741 sp->rg_first = rblock; 742 sp->rg_last = rblock; 743 sp->rg_nleft = rnleft; 744 } 745 746 /* Register c to char buffer buf of size buflen */ 747 regbuf(c, buf, buflen) 748 unsigned char c; 749 unsigned char *buf; 750 int buflen; 751 { 752 register unsigned char *p, *lp; 753 754 rbuf = ®rbuf; 755 rnleft = 0; 756 rblock = 0; 757 rnext = mapreg(c)->rg_first; 758 if (rnext == 0) { 759 *buf = 0; 760 error(gettext("Nothing in register %c"), c); 761 } 762 p = buf; 763 while (getREG() == 0) { 764 lp = linebuf; 765 while (*lp) { 766 if (p >= &buf[buflen]) 767 error(value(vi_TERSE) ? 768 gettext("Register too long") : gettext("Register too long to fit in memory")); 769 *p++ = *lp++; 770 } 771 *p++ = '\n'; 772 } 773 if (partreg(c)) p--; 774 *p = '\0'; 775 getDOT(); 776 } 777 778 #ifdef TRACE 779 780 /* 781 * Test code for displaying named registers. 782 */ 783 784 shownam() 785 { 786 int k; 787 788 printf("\nRegister Contents\n"); 789 printf("======== ========\n"); 790 for (k = 'a'; k <= 'z'; k++) { 791 rbuf = &putrbuf; 792 rnleft = 0; 793 rblock = 0; 794 rnext = mapreg(k)->rg_first; 795 printf(" %c:", k); 796 if (rnext == 0) 797 printf("\t\tNothing in register.\n"); 798 while (getREG() == 0) { 799 printf("\t\t%s\n", linebuf); 800 } 801 } 802 return (0); 803 } 804 805 /* 806 * Test code for displaying numbered registers. 807 */ 808 809 shownbr() 810 { 811 int k; 812 813 printf("\nRegister Contents\n"); 814 printf("======== ========\n"); 815 for (k = '1'; k <= '9'; k++) { 816 rbuf = &putrbuf; 817 rnleft = 0; 818 rblock = 0; 819 rnext = mapreg(k)->rg_first; 820 printf(" %c:", k); 821 if (rnext == 0) 822 printf("\t\tNothing in register.\n"); 823 while (getREG() == 0) { 824 printf("\t\t%s\n", linebuf); 825 } 826 } 827 return (0); 828 } 829 #endif 830