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