/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char *sccsid = "@(#)ex_temp.c 7.7.1.1 (Berkeley) 10/21/90"; #endif not lint #include "ex.h" #include "ex_temp.h" #include "ex_vis.h" #include "ex_tty.h" #include "pathnames.h" /* * Editor temporary file routines. * Very similar to those of ed, except uses 2 input buffers. */ #define READ 0 #define WRITE 1 #ifndef vms #define EPOSITION 7 #else #define EPOSITION 13 #endif char tfname[40]; char rfname[40]; int havetmp; short tfile = -1; short rfile = -1; fileinit() { register char *p; register int i, j; struct stat stbuf; if (tline == INCRMT * (HBLKS+2)) return; cleanup(0); if (tfile >= 0) close(tfile); tline = INCRMT * (HBLKS+2); blocks[0] = HBLKS; blocks[1] = HBLKS+1; blocks[2] = -1; dirtcnt = 0; iblock = -1; iblock2 = -1; oblock = -1; CP(tfname, svalue(DIRECTORY)); #ifndef vms if (stat(tfname, &stbuf)) #else goto vms_no_check_dir; #endif { dumbness: if (setexit() == 0) filioerr(tfname); else putNFL(); cleanup(1); ex_exit(1); } #ifndef vms if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { errno = ENOTDIR; goto dumbness; } #else vms_no_check_dir: #endif ichanged = 0; ichang2 = 0; #ifndef vms ignore(strcat(tfname, "/ExXXXXX")); #else ignore(strcat(tfname, "ExXXXXX")); #endif for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) *--p = j % 10 | '0'; #ifdef vms ignore(strcat(tfname, ".txt.1")); unlink(tfname); #endif tfile = creat(tfname, 0600); if (tfile < 0) goto dumbness; #ifdef VMUNIX { extern stilinc; /* see below */ stilinc = 0; } #endif havetmp = 1; if (tfile >= 0) close(tfile); tfile = open(tfname, 2); if (tfile < 0) goto dumbness; #ifdef UNIX_SBRK /* brk((char *)fendcore); */ #endif } cleanup(all) bool all; { if (all) { putpad(TE); flush(); } if (havetmp) { if (tfile >= 0) close(tfile); unlink(tfname); } havetmp = 0; if (all && rfile >= 0) { if (rfile >= 0) close(rfile); unlink(rfname); rfile = -1; } } getline(tl) line tl; { register char *bp, *lp; register int nl; lp = linebuf; bp = getblock(tl, READ); nl = nleft; tl &= ~OFFMSK; while (*lp++ = *bp++) if (--nl == 0) { bp = getblock(tl += INCRMT, READ); nl = nleft; } } putline() { register char *bp, *lp; register int nl; line tl; dirtcnt++; lp = linebuf; change(); tl = tline; bp = getblock(tl, WRITE); nl = nleft; tl &= ~OFFMSK; while (*bp = *lp++) { if (*bp++ == '\n') { *--bp = 0; linebp = lp; break; } if (--nl == 0) { bp = getblock(tl += INCRMT, WRITE); nl = nleft; } } tl = tline; tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776; return (tl); } int read(); int write(); char * getblock(atl, iof) line atl; int iof; { register int bno, off; bno = (atl >> OFFBTS) & BLKMSK; off = (atl << SHFT) & LBTMSK; if (bno >= NMBLKS) error(" Tmp file too large"); nleft = BUFSIZ - off; if (bno == iblock) { ichanged |= iof; hitin2 = 0; return (ibuff + off); } if (bno == iblock2) { ichang2 |= iof; hitin2 = 1; return (ibuff2 + off); } if (bno == oblock) return (obuff + off); if (iof == READ) { if (hitin2 == 0) { if (ichang2) { blkio(iblock2, ibuff2, write); } ichang2 = 0; iblock2 = bno; blkio(bno, ibuff2, read); hitin2 = 1; return (ibuff2 + off); } hitin2 = 0; if (ichanged) { blkio(iblock, ibuff, write); } ichanged = 0; iblock = bno; blkio(bno, ibuff, read); return (ibuff + off); } if (oblock >= 0) { blkio(oblock, obuff, write); } oblock = bno; return (obuff + off); } #ifdef VMUNIX #ifdef vms #define INCORB 32 #else #define INCORB 64 #endif char incorb[INCORB+1][BUFSIZ]; #define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1))) int stilinc; /* up to here not written yet */ #endif blkio(b, buf, iofcn) short b; char *buf; int (*iofcn)(); { #ifdef VMUNIX if (b < INCORB) { if (iofcn == read) { bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ); return; } bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ); if (laste) { if (b >= stilinc) stilinc = b + 1; return; } } else if (stilinc) tflush(); #endif lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) filioerr(tfname); } #ifdef VMUNIX tlaste() { if (stilinc) dirtcnt = 0; } tflush() { int i = stilinc; stilinc = 0; lseek(tfile, (long) 0, 0); if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ)) filioerr(tfname); } #endif /* * Synchronize the state of the temporary file in case * a crash occurs. */ synctmp() { register int cnt; register line *a; register short *bp; #ifdef VMUNIX if (stilinc) return; #endif if (dol == zero) return; if (ichanged) blkio(iblock, ibuff, write); ichanged = 0; if (ichang2) blkio(iblock2, ibuff2, write); ichang2 = 0; if (oblock != -1) blkio(oblock, obuff, write); time(&H.Time); uid = getuid(); *zero = (line) H.Time; for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) { if (*bp < 0) { tline = (tline + OFFMSK) &~ OFFMSK; *bp = ((tline >> OFFBTS) & BLKMSK); if (*bp > NMBLKS) error(" Tmp file too large"); tline += INCRMT; oblock = *bp + 1; bp[1] = -1; } lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0); cnt = ((dol - a) + 2) * sizeof (line); if (cnt > BUFSIZ) cnt = BUFSIZ; if (write(tfile, (char *) a, cnt) != cnt) { oops: *zero = 0; filioerr(tfname); } *zero = 0; } flines = lineDOL(); lseek(tfile, 0l, 0); if (write(tfile, (char *) &H, sizeof H) != sizeof H) goto oops; #ifdef notdef /* * This will insure that exrecover gets as much * back after a crash as is absolutely possible, * but can result in pregnant pauses between commands * when the TSYNC call is made, so... */ #ifndef vms (void) fsync(tfile); #endif #endif } TSYNC() { if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */ #ifdef VMUNIX if (stilinc) tflush(); #endif dirtcnt = 0; synctmp(); } } /* * Named buffer routines. * These are implemented differently than the main buffer. * Each named buffer has a chain of blocks in the register file. * Each block contains roughly 508 chars of text, * and a previous and next block number. We also have information * about which blocks came from deletes of multiple partial lines, * e.g. deleting a sentence or a LISP object. * * We maintain a free map for the temp file. To free the blocks * in a register we must read the blocks to find how they are chained * together. * * BUG: The default savind of deleted lines in numbered * buffers may be rather inefficient; it hasn't been profiled. */ struct strreg { short rg_flags; short rg_nleft; short rg_first; short rg_last; } strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp; struct rbuf { short rb_prev; short rb_next; char rb_text[BUFSIZ - 2 * sizeof (short)]; } *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf; #ifdef VMUNIX short rused[256]; #else short rused[32]; #endif short rnleft; short rblock; short rnext; char *rbufcp; regio(b, iofcn) short b; int (*iofcn)(); { if (rfile == -1) { CP(rfname, tfname); *(strend(rfname) - EPOSITION) = 'R'; rfile = creat(rfname, 0600); if (rfile < 0) oops: filioerr(rfname); else close(rfile); rfile = open(rfname, 2); if (rfile < 0) goto oops; } lseek(rfile, (long) b * BUFSIZ, 0); if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ) goto oops; rblock = b; } REGblk() { register int i, j, m; for (i = 0; i < sizeof rused / sizeof rused[0]; i++) { m = (rused[i] ^ 0177777) & 0177777; if (i == 0) m &= ~1; if (m != 0) { j = 0; while ((m & 1) == 0) j++, m >>= 1; rused[i] |= (1 << j); #ifdef RDEBUG ex_printf("allocating block %d\n", i * 16 + j); #endif return (i * 16 + j); } } error("Out of register space (ugh)"); /*NOTREACHED*/ } struct strreg * mapreg(c) register int c; { if (isupper(c)) c = tolower(c); return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']); } int shread(); KILLreg(c) register int c; { register struct strreg *sp; rbuf = &KILLrbuf; sp = mapreg(c); rblock = sp->rg_first; sp->rg_first = sp->rg_last = 0; sp->rg_flags = sp->rg_nleft = 0; while (rblock != 0) { #ifdef RDEBUG ex_printf("freeing block %d\n", rblock); #endif rused[rblock / 16] &= ~(1 << (rblock % 16)); regio(rblock, shread); rblock = rbuf->rb_next; } } /*VARARGS*/ shread() { struct front { short a; short b; }; if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front)) return (sizeof (struct rbuf)); return (0); } int getREG(); putreg(c) char c; { register line *odot = dot; register line *odol = dol; register int cnt; deletenone(); appendnone(); rbuf = &putrbuf; rnleft = 0; rblock = 0; rnext = mapreg(c)->rg_first; if (rnext == 0) { if (inopen) { splitw++; vclean(); vgoto(WECHO, 0); } vreg = -1; error("Nothing in register %c", c); } if (inopen && partreg(c)) { if (!FIXUNDO) { splitw++; vclean(); vgoto(WECHO, 0); vreg = -1; error("Can't put partial line inside macro"); } squish(); addr1 = addr2 = dol; } cnt = append(getREG, addr2); if (inopen && partreg(c)) { unddol = dol; dol = odol; dot = odot; pragged(0); } killcnt(cnt); notecnt = cnt; } partreg(c) char c; { return (mapreg(c)->rg_flags); } notpart(c) register int c; { if (c) mapreg(c)->rg_flags = 0; } getREG() { register char *lp = linebuf; register int c; for (;;) { if (rnleft == 0) { if (rnext == 0) return (EOF); regio(rnext, read); rnext = rbuf->rb_next; rbufcp = rbuf->rb_text; rnleft = sizeof rbuf->rb_text; } c = *rbufcp; if (c == 0) return (EOF); rbufcp++, --rnleft; if (c == '\n') { *lp++ = 0; return (0); } *lp++ = c; } } YANKreg(c) register int c; { register line *addr; register struct strreg *sp; char savelb[LBSIZE]; if (isdigit(c)) kshift(); if (islower(c)) KILLreg(c); strp = sp = mapreg(c); sp->rg_flags = inopen && cursor && wcursor; rbuf = &YANKrbuf; if (sp->rg_last) { regio(sp->rg_last, read); rnleft = sp->rg_nleft; rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft]; } else { rblock = 0; rnleft = 0; } CP(savelb,linebuf); for (addr = addr1; addr <= addr2; addr++) { getline(*addr); if (sp->rg_flags) { if (addr == addr2) *wcursor = 0; if (addr == addr1) strcpy(linebuf, cursor); } YANKline(); } rbflush(); killed(); CP(linebuf,savelb); } kshift() { register int i; KILLreg('9'); for (i = '8'; i >= '0'; i--) copy(mapreg(i+1), mapreg(i), sizeof (struct strreg)); } YANKline() { register char *lp = linebuf; register struct rbuf *rp = rbuf; register int c; do { c = *lp++; if (c == 0) c = '\n'; if (rnleft == 0) { rp->rb_next = REGblk(); rbflush(); rblock = rp->rb_next; rp->rb_next = 0; rp->rb_prev = rblock; rnleft = sizeof rp->rb_text; rbufcp = rp->rb_text; } *rbufcp++ = c; --rnleft; } while (c != '\n'); if (rnleft) *rbufcp = 0; } rbflush() { register struct strreg *sp = strp; if (rblock == 0) return; regio(rblock, write); if (sp->rg_first == 0) sp->rg_first = rblock; sp->rg_last = rblock; sp->rg_nleft = rnleft; } /* Register c to char buffer buf of size buflen */ regbuf(c, buf, buflen) char c; char *buf; int buflen; { register char *p, *lp; rbuf = ®rbuf; rnleft = 0; rblock = 0; rnext = mapreg(c)->rg_first; if (rnext==0) { *buf = 0; error("Nothing in register %c",c); } p = buf; while (getREG()==0) { for (lp=linebuf; *lp;) { if (p >= &buf[buflen]) error("Register too long@to fit in memory"); *p++ = *lp++; } *p++ = '\n'; } if (partreg(c)) p--; *p = '\0'; getDOT(); } /* * Encryption routines. These are essentially unmodified from ed. */