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