1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ex_temp.c 8.1.1.1 (Berkeley) 08/19/93"; 10 #endif /* not lint */ 11 12 #include "ex.h" 13 #include "ex_temp.h" 14 #include "ex_vis.h" 15 #include "ex_tty.h" 16 #include "pathnames.h" 17 18 /* 19 * Editor temporary file routines. 20 * Very similar to those of ed, except uses 2 input buffers. 21 */ 22 #define READ 0 23 #define WRITE 1 24 25 #ifndef vms 26 #define EPOSITION 7 27 #else 28 #define EPOSITION 13 29 #endif 30 31 char tfname[40]; 32 char rfname[40]; 33 int havetmp; 34 short tfile = -1; 35 short rfile = -1; 36 37 fileinit() 38 { 39 register char *p; 40 register int i, j; 41 struct stat stbuf; 42 43 if (tline == INCRMT * (HBLKS+2)) 44 return; 45 cleanup(0); 46 if (tfile >= 0) 47 close(tfile); 48 tline = INCRMT * (HBLKS+2); 49 blocks[0] = HBLKS; 50 blocks[1] = HBLKS+1; 51 blocks[2] = -1; 52 dirtcnt = 0; 53 iblock = -1; 54 iblock2 = -1; 55 oblock = -1; 56 CP(tfname, svalue(DIRECTORY)); 57 #ifndef vms 58 if (stat(tfname, &stbuf)) 59 #else 60 goto vms_no_check_dir; 61 #endif 62 { 63 dumbness: 64 if (setexit() == 0) 65 filioerr(tfname); 66 else 67 putNFL(); 68 cleanup(1); 69 ex_exit(1); 70 } 71 #ifndef vms 72 if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { 73 errno = ENOTDIR; 74 goto dumbness; 75 } 76 #else 77 vms_no_check_dir: 78 #endif 79 ichanged = 0; 80 ichang2 = 0; 81 #ifndef vms 82 ignore(strcat(tfname, "/ExXXXXX")); 83 #else 84 ignore(strcat(tfname, "ExXXXXX")); 85 #endif 86 for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) 87 *--p = j % 10 | '0'; 88 #ifdef vms 89 ignore(strcat(tfname, ".txt.1")); 90 unlink(tfname); 91 #endif 92 tfile = creat(tfname, 0600); 93 if (tfile < 0) 94 goto dumbness; 95 #ifdef VMUNIX 96 { 97 extern stilinc; /* see below */ 98 stilinc = 0; 99 } 100 #endif 101 havetmp = 1; 102 if (tfile >= 0) 103 close(tfile); 104 tfile = open(tfname, 2); 105 if (tfile < 0) 106 goto dumbness; 107 #ifdef UNIX_SBRK 108 /* brk((char *)fendcore); */ 109 #endif 110 } 111 112 cleanup(all) 113 bool all; 114 { 115 if (all) { 116 putpad(TE); 117 flush(); 118 } 119 if (havetmp) { 120 if (tfile >= 0) 121 close(tfile); 122 unlink(tfname); 123 } 124 havetmp = 0; 125 if (all && rfile >= 0) { 126 if (rfile >= 0) 127 close(rfile); 128 unlink(rfname); 129 rfile = -1; 130 } 131 } 132 133 getline(tl) 134 line tl; 135 { 136 register char *bp, *lp; 137 register int nl; 138 139 lp = linebuf; 140 bp = getblock(tl, READ); 141 nl = nleft; 142 tl &= ~OFFMSK; 143 while (*lp++ = *bp++) 144 if (--nl == 0) { 145 bp = getblock(tl += INCRMT, READ); 146 nl = nleft; 147 } 148 } 149 150 putline() 151 { 152 register char *bp, *lp; 153 register int nl; 154 line tl; 155 156 dirtcnt++; 157 lp = linebuf; 158 change(); 159 tl = tline; 160 bp = getblock(tl, WRITE); 161 nl = nleft; 162 tl &= ~OFFMSK; 163 while (*bp = *lp++) { 164 if (*bp++ == '\n') { 165 *--bp = 0; 166 linebp = lp; 167 break; 168 } 169 if (--nl == 0) { 170 bp = getblock(tl += INCRMT, WRITE); 171 nl = nleft; 172 } 173 } 174 tl = tline; 175 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 176 return (tl); 177 } 178 179 int read(); 180 int write(); 181 182 char * 183 getblock(atl, iof) 184 line atl; 185 int iof; 186 { 187 register int bno, off; 188 189 bno = (atl >> OFFBTS) & BLKMSK; 190 off = (atl << SHFT) & LBTMSK; 191 if (bno >= NMBLKS) 192 error(" Tmp file too large"); 193 nleft = BUFSIZ - off; 194 if (bno == iblock) { 195 ichanged |= iof; 196 hitin2 = 0; 197 return (ibuff + off); 198 } 199 if (bno == iblock2) { 200 ichang2 |= iof; 201 hitin2 = 1; 202 return (ibuff2 + off); 203 } 204 if (bno == oblock) 205 return (obuff + off); 206 if (iof == READ) { 207 if (hitin2 == 0) { 208 if (ichang2) { 209 blkio(iblock2, ibuff2, write); 210 } 211 ichang2 = 0; 212 iblock2 = bno; 213 blkio(bno, ibuff2, read); 214 hitin2 = 1; 215 return (ibuff2 + off); 216 } 217 hitin2 = 0; 218 if (ichanged) { 219 blkio(iblock, ibuff, write); 220 } 221 ichanged = 0; 222 iblock = bno; 223 blkio(bno, ibuff, read); 224 return (ibuff + off); 225 } 226 if (oblock >= 0) { 227 blkio(oblock, obuff, write); 228 } 229 oblock = bno; 230 return (obuff + off); 231 } 232 233 #ifdef VMUNIX 234 #ifdef vms 235 #define INCORB 32 236 #else 237 #define INCORB 64 238 #endif 239 char incorb[INCORB+1][BUFSIZ]; 240 #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1))) 241 int stilinc; /* up to here not written yet */ 242 #endif 243 244 blkio(b, buf, iofcn) 245 short b; 246 char *buf; 247 int (*iofcn)(); 248 { 249 250 #ifdef VMUNIX 251 if (b < INCORB) { 252 if (iofcn == read) { 253 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ); 254 return; 255 } 256 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ); 257 if (laste) { 258 if (b >= stilinc) 259 stilinc = b + 1; 260 return; 261 } 262 } else if (stilinc) 263 tflush(); 264 #endif 265 lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); 266 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) 267 filioerr(tfname); 268 } 269 270 #ifdef VMUNIX 271 tlaste() 272 { 273 274 if (stilinc) 275 dirtcnt = 0; 276 } 277 278 tflush() 279 { 280 int i = stilinc; 281 282 stilinc = 0; 283 lseek(tfile, (long) 0, 0); 284 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ)) 285 filioerr(tfname); 286 } 287 #endif 288 289 /* 290 * Synchronize the state of the temporary file in case 291 * a crash occurs. 292 */ 293 synctmp() 294 { 295 register int cnt; 296 register line *a; 297 register short *bp; 298 299 #ifdef VMUNIX 300 if (stilinc) 301 return; 302 #endif 303 if (dol == zero) 304 return; 305 if (ichanged) 306 blkio(iblock, ibuff, write); 307 ichanged = 0; 308 if (ichang2) 309 blkio(iblock2, ibuff2, write); 310 ichang2 = 0; 311 if (oblock != -1) 312 blkio(oblock, obuff, write); 313 time(&H.Time); 314 uid = getuid(); 315 *zero = (line) H.Time; 316 for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { 317 if (*bp < 0) { 318 tline = (tline + OFFMSK) &~ OFFMSK; 319 *bp = ((tline >> OFFBTS) & BLKMSK); 320 if (*bp > NMBLKS) 321 error(" Tmp file too large"); 322 tline += INCRMT; 323 oblock = *bp + 1; 324 bp[1] = -1; 325 } 326 lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); 327 cnt = ((dol - a) + 2) * sizeof (line); 328 if (cnt > BUFSIZ) 329 cnt = BUFSIZ; 330 if (write(tfile, (char *) a, cnt) != cnt) { 331 oops: 332 *zero = 0; 333 filioerr(tfname); 334 } 335 *zero = 0; 336 } 337 flines = lineDOL(); 338 lseek(tfile, 0l, 0); 339 if (write(tfile, (char *) &H, sizeof H) != sizeof H) 340 goto oops; 341 #ifdef notdef 342 /* 343 * This will insure that exrecover gets as much 344 * back after a crash as is absolutely possible, 345 * but can result in pregnant pauses between commands 346 * when the TSYNC call is made, so... 347 */ 348 #ifndef vms 349 (void) fsync(tfile); 350 #endif 351 #endif 352 } 353 354 TSYNC() 355 { 356 357 if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */ 358 #ifdef VMUNIX 359 if (stilinc) 360 tflush(); 361 #endif 362 dirtcnt = 0; 363 synctmp(); 364 } 365 } 366 367 /* 368 * Named buffer routines. 369 * These are implemented differently than the main buffer. 370 * Each named buffer has a chain of blocks in the register file. 371 * Each block contains roughly 508 chars of text, 372 * and a previous and next block number. We also have information 373 * about which blocks came from deletes of multiple partial lines, 374 * e.g. deleting a sentence or a LISP object. 375 * 376 * We maintain a free map for the temp file. To free the blocks 377 * in a register we must read the blocks to find how they are chained 378 * together. 379 * 380 * BUG: The default savind of deleted lines in numbered 381 * buffers may be rather inefficient; it hasn't been profiled. 382 */ 383 struct strreg { 384 short rg_flags; 385 short rg_nleft; 386 short rg_first; 387 short rg_last; 388 } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 389 390 struct rbuf { 391 short rb_prev; 392 short rb_next; 393 char rb_text[BUFSIZ - 2 * sizeof (short)]; 394 } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; 395 #ifdef VMUNIX 396 short rused[256]; 397 #else 398 short rused[32]; 399 #endif 400 short rnleft; 401 short rblock; 402 short rnext; 403 char *rbufcp; 404 405 regio(b, iofcn) 406 short b; 407 int (*iofcn)(); 408 { 409 410 if (rfile == -1) { 411 CP(rfname, tfname); 412 *(strend(rfname) - EPOSITION) = 'R'; 413 rfile = creat(rfname, 0600); 414 if (rfile < 0) 415 oops: 416 filioerr(rfname); 417 else 418 close(rfile); 419 rfile = open(rfname, 2); 420 if (rfile < 0) 421 goto oops; 422 } 423 lseek(rfile, (long) b * BUFSIZ, 0); 424 if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) 425 goto oops; 426 rblock = b; 427 } 428 429 REGblk() 430 { 431 register int i, j, m; 432 433 for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { 434 m = (rused[i] ^ 0177777) & 0177777; 435 if (i == 0) 436 m &= ~1; 437 if (m != 0) { 438 j = 0; 439 while ((m & 1) == 0) 440 j++, m >>= 1; 441 rused[i] |= (1 << j); 442 #ifdef RDEBUG 443 ex_printf("allocating block %d\n", i * 16 + j); 444 #endif 445 return (i * 16 + j); 446 } 447 } 448 error("Out of register space (ugh)"); 449 /*NOTREACHED*/ 450 } 451 452 struct strreg * 453 mapreg(c) 454 register int c; 455 { 456 457 if (isupper(c)) 458 c = tolower(c); 459 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 460 } 461 462 int shread(); 463 464 KILLreg(c) 465 register int c; 466 { 467 register struct strreg *sp; 468 469 rbuf = &KILLrbuf; 470 sp = mapreg(c); 471 rblock = sp->rg_first; 472 sp->rg_first = sp->rg_last = 0; 473 sp->rg_flags = sp->rg_nleft = 0; 474 while (rblock != 0) { 475 #ifdef RDEBUG 476 ex_printf("freeing block %d\n", rblock); 477 #endif 478 rused[rblock / 16] &= ~(1 << (rblock % 16)); 479 regio(rblock, shread); 480 rblock = rbuf->rb_next; 481 } 482 } 483 484 /*VARARGS*/ 485 shread() 486 { 487 struct front { short a; short b; }; 488 489 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 490 return (sizeof (struct rbuf)); 491 return (0); 492 } 493 494 int getREG(); 495 496 putreg(c) 497 char c; 498 { 499 register line *odot = dot; 500 register line *odol = dol; 501 register int cnt; 502 503 deletenone(); 504 appendnone(); 505 rbuf = &putrbuf; 506 rnleft = 0; 507 rblock = 0; 508 rnext = mapreg(c)->rg_first; 509 if (rnext == 0) { 510 if (inopen) { 511 splitw++; 512 vclean(); 513 vgoto(WECHO, 0); 514 } 515 vreg = -1; 516 error("Nothing in register %c", c); 517 } 518 if (inopen && partreg(c)) { 519 if (!FIXUNDO) { 520 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; 521 error("Can't put partial line inside macro"); 522 } 523 squish(); 524 addr1 = addr2 = dol; 525 } 526 cnt = append(getREG, addr2); 527 if (inopen && partreg(c)) { 528 unddol = dol; 529 dol = odol; 530 dot = odot; 531 pragged(0); 532 } 533 killcnt(cnt); 534 notecnt = cnt; 535 } 536 537 partreg(c) 538 char c; 539 { 540 541 return (mapreg(c)->rg_flags); 542 } 543 544 notpart(c) 545 register int c; 546 { 547 548 if (c) 549 mapreg(c)->rg_flags = 0; 550 } 551 552 getREG() 553 { 554 register char *lp = linebuf; 555 register int c; 556 557 for (;;) { 558 if (rnleft == 0) { 559 if (rnext == 0) 560 return (EOF); 561 regio(rnext, read); 562 rnext = rbuf->rb_next; 563 rbufcp = rbuf->rb_text; 564 rnleft = sizeof rbuf->rb_text; 565 } 566 c = *rbufcp; 567 if (c == 0) 568 return (EOF); 569 rbufcp++, --rnleft; 570 if (c == '\n') { 571 *lp++ = 0; 572 return (0); 573 } 574 *lp++ = c; 575 } 576 } 577 578 YANKreg(c) 579 register int c; 580 { 581 register line *addr; 582 register struct strreg *sp; 583 char savelb[LBSIZE]; 584 585 if (isdigit(c)) 586 kshift(); 587 if (islower(c)) 588 KILLreg(c); 589 strp = sp = mapreg(c); 590 sp->rg_flags = inopen && cursor && wcursor; 591 rbuf = &YANKrbuf; 592 if (sp->rg_last) { 593 regio(sp->rg_last, read); 594 rnleft = sp->rg_nleft; 595 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 596 } else { 597 rblock = 0; 598 rnleft = 0; 599 } 600 CP(savelb,linebuf); 601 for (addr = addr1; addr <= addr2; addr++) { 602 getline(*addr); 603 if (sp->rg_flags) { 604 if (addr == addr2) 605 *wcursor = 0; 606 if (addr == addr1) 607 strcpy(linebuf, cursor); 608 } 609 YANKline(); 610 } 611 rbflush(); 612 killed(); 613 CP(linebuf,savelb); 614 } 615 616 kshift() 617 { 618 register int i; 619 620 KILLreg('9'); 621 for (i = '8'; i >= '0'; i--) 622 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 623 } 624 625 YANKline() 626 { 627 register char *lp = linebuf; 628 register struct rbuf *rp = rbuf; 629 register int c; 630 631 do { 632 c = *lp++; 633 if (c == 0) 634 c = '\n'; 635 if (rnleft == 0) { 636 rp->rb_next = REGblk(); 637 rbflush(); 638 rblock = rp->rb_next; 639 rp->rb_next = 0; 640 rp->rb_prev = rblock; 641 rnleft = sizeof rp->rb_text; 642 rbufcp = rp->rb_text; 643 } 644 *rbufcp++ = c; 645 --rnleft; 646 } while (c != '\n'); 647 if (rnleft) 648 *rbufcp = 0; 649 } 650 651 rbflush() 652 { 653 register struct strreg *sp = strp; 654 655 if (rblock == 0) 656 return; 657 regio(rblock, write); 658 if (sp->rg_first == 0) 659 sp->rg_first = rblock; 660 sp->rg_last = rblock; 661 sp->rg_nleft = rnleft; 662 } 663 664 /* Register c to char buffer buf of size buflen */ 665 regbuf(c, buf, buflen) 666 char c; 667 char *buf; 668 int buflen; 669 { 670 register char *p, *lp; 671 672 rbuf = ®rbuf; 673 rnleft = 0; 674 rblock = 0; 675 rnext = mapreg(c)->rg_first; 676 if (rnext==0) { 677 *buf = 0; 678 error("Nothing in register %c",c); 679 } 680 p = buf; 681 while (getREG()==0) { 682 for (lp=linebuf; *lp;) { 683 if (p >= &buf[buflen]) 684 error("Register too long@to fit in memory"); 685 *p++ = *lp++; 686 } 687 *p++ = '\n'; 688 } 689 if (partreg(c)) p--; 690 *p = '\0'; 691 getDOT(); 692 } 693 694 /* 695 * Encryption routines. These are essentially unmodified from ed. 696 */ 697 698