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