1: /* Copyright (c) 1979 Regents of the University of California */ 2: #include "ex.h" 3: #include "ex_temp.h" 4: #include "ex_vis.h" 5: #include "ex_tty.h" 6: 7: /* 8: * Editor temporary file routines. 9: * Very similar to those of ed, except uses 2 input buffers. 10: */ 11: #define READ 0 12: #define WRITE 1 13: 14: char tfname[40]; 15: char rfname[40]; 16: int havetmp; 17: short tfile = -1; 18: short rfile = -1; 19: 20: fileinit() 21: { 22: register char *p; 23: register int i, j; 24: struct stat stbuf; 25: 26: if (tline == INCRMT * (HBLKS+2)) 27: return; 28: cleanup(0); 29: close(tfile); 30: tline = INCRMT * (HBLKS+2); 31: blocks[0] = HBLKS; 32: blocks[1] = HBLKS+1; 33: blocks[2] = -1; 34: dirtcnt = 0; 35: iblock = -1; 36: iblock2 = -1; 37: oblock = -1; 38: CP(tfname, svalue(DIRECTORY)); 39: if (stat(tfname, &stbuf)) { 40: dumbness: 41: if (setexit() == 0) 42: filioerr(tfname); 43: else 44: putNFL(); 45: cleanup(1); 46: exit(1); 47: } 48: if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { 49: errno = ENOTDIR; 50: goto dumbness; 51: } 52: ichanged = 0; 53: ichang2 = 0; 54: ignore(strcat(tfname, "/ExXXXXX")); 55: for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) 56: *--p = j % 10 | '0'; 57: tfile = creat(tfname, 0600); 58: if (tfile < 0) 59: goto dumbness; 60: havetmp = 1; 61: close(tfile); 62: tfile = open(tfname, 2); 63: if (tfile < 0) 64: goto dumbness; 65: /* brk((char *)fendcore); */ 66: } 67: 68: cleanup(all) 69: bool all; 70: { 71: if (all) { 72: putpad(TE); 73: flush(); 74: } 75: if (havetmp) 76: unlink(tfname); 77: havetmp = 0; 78: if (all && rfile >= 0) { 79: unlink(rfname); 80: close(rfile); 81: rfile = -1; 82: } 83: } 84: 85: getline(tl) 86: line tl; 87: { 88: register char *bp, *lp; 89: register int nl; 90: 91: lp = linebuf; 92: bp = getblock(tl, READ); 93: nl = nleft; 94: tl &= ~OFFMSK; 95: while (*lp++ = *bp++) 96: if (--nl == 0) { 97: bp = getblock(tl += INCRMT, READ); 98: nl = nleft; 99: } 100: } 101: 102: putline() 103: { 104: register char *bp, *lp; 105: register int nl; 106: line tl; 107: 108: dirtcnt++; 109: lp = linebuf; 110: change(); 111: tl = tline; 112: bp = getblock(tl, WRITE); 113: nl = nleft; 114: tl &= ~OFFMSK; 115: while (*bp = *lp++) { 116: if (*bp++ == '\n') { 117: *--bp = 0; 118: linebp = lp; 119: break; 120: } 121: if (--nl == 0) { 122: bp = getblock(tl += INCRMT, WRITE); 123: nl = nleft; 124: } 125: } 126: tl = tline; 127: tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; 128: return (tl); 129: } 130: 131: int read(); 132: int write(); 133: 134: char * 135: getblock(atl, iof) 136: line atl; 137: int iof; 138: { 139: register int bno, off; 140: 141: bno = (atl >> OFFBTS) & BLKMSK; 142: off = (atl << SHFT) & LBTMSK; 143: if (bno >= NMBLKS) 144: error(" Tmp file too large"); 145: nleft = BUFSIZ - off; 146: if (bno == iblock) { 147: ichanged |= iof; 148: hitin2 = 0; 149: return (ibuff + off); 150: } 151: if (bno == iblock2) { 152: ichang2 |= iof; 153: hitin2 = 1; 154: return (ibuff2 + off); 155: } 156: if (bno == oblock) 157: return (obuff + off); 158: if (iof == READ) { 159: if (hitin2 == 0) { 160: if (ichang2) 161: blkio(iblock2, ibuff2, write); 162: ichang2 = 0; 163: iblock2 = bno; 164: blkio(bno, ibuff2, read); 165: hitin2 = 1; 166: return (ibuff2 + off); 167: } 168: hitin2 = 0; 169: if (ichanged) 170: blkio(iblock, ibuff, write); 171: ichanged = 0; 172: iblock = bno; 173: blkio(bno, ibuff, read); 174: return (ibuff + off); 175: } 176: if (oblock >= 0) 177: blkio(oblock, obuff, write); 178: oblock = bno; 179: return (obuff + off); 180: } 181: 182: blkio(b, buf, iofcn) 183: short b; 184: char *buf; 185: int (*iofcn)(); 186: { 187: 188: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); 189: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) 190: filioerr(tfname); 191: } 192: 193: /* 194: * Synchronize the state of the temporary file in case 195: * a crash occurs. 196: */ 197: synctmp() 198: { 199: register int cnt; 200: register line *a; 201: register short *bp; 202: 203: if (dol == zero) 204: return; 205: if (ichanged) 206: blkio(iblock, ibuff, write); 207: ichanged = 0; 208: if (ichang2) 209: blkio(iblock2, ibuff2, write); 210: ichang2 = 0; 211: if (oblock != -1) 212: blkio(oblock, obuff, write); 213: time(&H.Time); 214: uid = getuid(); 215: *zero = (line) H.Time; 216: for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { 217: if (*bp < 0) { 218: tline = (tline + OFFMSK) &~ OFFMSK; 219: *bp = ((tline >> OFFBTS) & BLKMSK); 220: if (*bp > NMBLKS) 221: error(" Tmp file too large"); 222: tline += INCRMT; 223: oblock = *bp + 1; 224: bp[1] = -1; 225: } 226: lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); 227: cnt = ((dol - a) + 2) * sizeof (line); 228: if (cnt > BUFSIZ) 229: cnt = BUFSIZ; 230: if (write(tfile, (char *) a, cnt) != cnt) { 231: oops: 232: *zero = 0; 233: filioerr(tfname); 234: } 235: *zero = 0; 236: } 237: flines = lineDOL(); 238: lseek(tfile, 0l, 0); 239: if (write(tfile, (char *) &H, sizeof H) != sizeof H) 240: goto oops; 241: } 242: 243: TSYNC() 244: { 245: 246: if (dirtcnt > 12) { 247: dirtcnt = 0; 248: synctmp(); 249: } 250: } 251: 252: /* 253: * Named buffer routines. 254: * These are implemented differently than the main buffer. 255: * Each named buffer has a chain of blocks in the register file. 256: * Each block contains roughly 508 chars of text, 257: * and a previous and next block number. We also have information 258: * about which blocks came from deletes of multiple partial lines, 259: * e.g. deleting a sentence or a LISP object. 260: * 261: * We maintain a free map for the temp file. To free the blocks 262: * in a register we must read the blocks to find how they are chained 263: * together. 264: * 265: * BUG: The default savind of deleted lines in numbered 266: * buffers may be rather inefficient; it hasn't been profiled. 267: */ 268: struct strreg { 269: short rg_flags; 270: short rg_nleft; 271: short rg_first; 272: short rg_last; 273: } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; 274: 275: struct rbuf { 276: short rb_prev; 277: short rb_next; 278: char rb_text[BUFSIZ - 2 * sizeof (short)]; 279: } *rbuf; 280: short rused[32]; 281: short rnleft; 282: short rblock; 283: short rnext; 284: char *rbufcp; 285: 286: regio(b, iofcn) 287: short b; 288: int (*iofcn)(); 289: { 290: 291: if (rfile == -1) { 292: CP(rfname, tfname); 293: *(strend(rfname) - 7) = 'R'; 294: rfile = creat(rfname, 0600); 295: if (rfile < 0) 296: oops: 297: filioerr(rfname); 298: close(rfile); 299: rfile = open(rfname, 2); 300: if (rfile < 0) 301: goto oops; 302: } 303: lseek(rfile, (long) b * BUFSIZ, 0); 304: if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) 305: goto oops; 306: rblock = b; 307: } 308: 309: REGblk() 310: { 311: register int i, j, m; 312: 313: for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { 314: m = (rused[i] ^ 0177777) & 0177777; 315: if (i == 0) 316: m &= ~1; 317: if (m != 0) { 318: j = 0; 319: while ((m & 1) == 0) 320: j++, m >>= 1; 321: rused[i] |= (1 << j); 322: #ifdef RDEBUG 323: printf("allocating block %d\n", i * 16 + j); 324: #endif 325: return (i * 16 + j); 326: } 327: } 328: error("Out of register space (ugh)"); 329: /*NOTREACHED*/ 330: } 331: 332: struct strreg * 333: mapreg(c) 334: register int c; 335: { 336: 337: if (isupper(c)) 338: c = tolower(c); 339: return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); 340: } 341: 342: int shread(); 343: 344: KILLreg(c) 345: register int c; 346: { 347: struct rbuf arbuf; 348: register struct strreg *sp; 349: 350: rbuf = &arbuf; 351: sp = mapreg(c); 352: rblock = sp->rg_first; 353: sp->rg_first = sp->rg_last = 0; 354: sp->rg_flags = sp->rg_nleft = 0; 355: while (rblock != 0) { 356: #ifdef RDEBUG 357: printf("freeing block %d\n", rblock); 358: #endif 359: rused[rblock / 16] &= ~(1 << (rblock % 16)); 360: regio(rblock, shread); 361: rblock = rbuf->rb_next; 362: } 363: } 364: 365: /*VARARGS*/ 366: shread() 367: { 368: struct front { short a; short b; }; 369: 370: if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) 371: return (sizeof (struct rbuf)); 372: return (0); 373: } 374: 375: int getREG(); 376: 377: putreg(c) 378: char c; 379: { 380: struct rbuf arbuf; 381: register line *odot = dot; 382: register line *odol = dol; 383: register int cnt; 384: 385: deletenone(); 386: appendnone(); 387: rbuf = &arbuf; 388: rnleft = 0; 389: rblock = 0; 390: rnext = mapreg(c)->rg_first; 391: if (rnext == 0) { 392: if (inopen) { 393: splitw++; 394: vclean(); 395: vgoto(WECHO, 0); 396: } 397: vreg = -1; 398: error("Nothing in register %c", c); 399: } 400: if (inopen && partreg(c)) { 401: squish(); 402: addr1 = addr2 = dol; 403: } 404: ignore(append(getREG, addr2)); 405: if (inopen && partreg(c)) { 406: unddol = dol; 407: dol = odol; 408: dot = odot; 409: pragged(0); 410: } 411: cnt = undap2 - undap1; 412: killcnt(cnt); 413: notecnt = cnt; 414: } 415: 416: partreg(c) 417: char c; 418: { 419: 420: return (mapreg(c)->rg_flags); 421: } 422: 423: notpart(c) 424: register int c; 425: { 426: 427: if (c) 428: mapreg(c)->rg_flags = 0; 429: } 430: 431: getREG() 432: { 433: register char *lp = linebuf; 434: register int c; 435: 436: for (;;) { 437: if (rnleft == 0) { 438: if (rnext == 0) 439: return (EOF); 440: regio(rnext, read); 441: rnext = rbuf->rb_next; 442: rbufcp = rbuf->rb_text; 443: rnleft = sizeof rbuf->rb_text; 444: } 445: c = *rbufcp; 446: if (c == 0) 447: return (EOF); 448: rbufcp++, --rnleft; 449: if (c == '\n') { 450: *lp++ = 0; 451: return (0); 452: } 453: *lp++ = c; 454: } 455: } 456: 457: YANKreg(c) 458: register int c; 459: { 460: struct rbuf arbuf; 461: register line *addr; 462: register struct strreg *sp; 463: 464: if (isdigit(c)) 465: kshift(); 466: if (islower(c)) 467: KILLreg(c); 468: strp = sp = mapreg(c); 469: sp->rg_flags = inopen && cursor && wcursor; 470: rbuf = &arbuf; 471: if (sp->rg_last) { 472: regio(sp->rg_last, read); 473: rnleft = sp->rg_nleft; 474: rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; 475: } else { 476: rblock = 0; 477: rnleft = 0; 478: } 479: for (addr = addr1; addr <= addr2; addr++) { 480: getline(*addr); 481: if (sp->rg_flags) { 482: if (addr == addr2) 483: *wcursor = 0; 484: if (addr == addr1) 485: strcpy(linebuf, cursor); 486: } 487: YANKline(); 488: } 489: rbflush(); 490: killed(); 491: } 492: 493: kshift() 494: { 495: register int i; 496: 497: KILLreg('9'); 498: for (i = '8'; i >= '0'; i--) 499: copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); 500: } 501: 502: YANKline() 503: { 504: register char *lp = linebuf; 505: register struct rbuf *rp = rbuf; 506: register int c; 507: 508: do { 509: c = *lp++; 510: if (c == 0) 511: c = '\n'; 512: if (rnleft == 0) { 513: rp->rb_next = REGblk(); 514: rbflush(); 515: rblock = rp->rb_next; 516: rp->rb_next = 0; 517: rp->rb_prev = rblock; 518: rnleft = sizeof rp->rb_text; 519: rbufcp = rp->rb_text; 520: } 521: *rbufcp++ = c; 522: --rnleft; 523: } while (c != '\n'); 524: if (rnleft) 525: *rbufcp = 0; 526: } 527: 528: rbflush() 529: { 530: register struct strreg *sp = strp; 531: 532: if (rblock == 0) 533: return; 534: regio(rblock, write); 535: if (sp->rg_first == 0) 536: sp->rg_first = rblock; 537: sp->rg_last = rblock; 538: sp->rg_nleft = rnleft; 539: }