/* Copyright (c) 1981 Regents of the University of California */ static char *sccsid = "@(#)ex_temp.c 7.3 9/3/81"; #include "ex.h" #include "ex_temp.h" #include "ex_vis.h" #include "ex_tty.h" /* * Editor temporary file routines. * Very similar to those of ed, except uses 2 input buffers. */ #define READ 0 #define WRITE 1 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); 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)); if (stat(tfname, &stbuf)) { dumbness: if (setexit() == 0) filioerr(tfname); else putNFL(); cleanup(1); exit(1); } if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { errno = ENOTDIR; goto dumbness; } ichanged = 0; ichang2 = 0; ignore(strcat(tfname, "/ExXXXXX")); for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10) *--p = j % 10 | '0'; tfile = creat(tfname, 0600); if (tfile < 0) goto dumbness; #ifdef VMUNIX { extern stilinc; /* see below */ stilinc = 0; } #endif havetmp = 1; close(tfile); tfile = open(tfname, 2); if (tfile < 0) goto dumbness; /* brk((char *)fendcore); */ } cleanup(all) bool all; { if (all) { putpad(TE); flush(); } if (havetmp) unlink(tfname); havetmp = 0; if (all && rfile >= 0) { unlink(rfname); close(rfile); 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; register char *p1, *p2; register int n; 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) { #ifdef CRYPT if(xtflag) crblock(tperm, ibuff2, CRSIZE, (long)0); #endif blkio(iblock2, ibuff2, write); } ichang2 = 0; iblock2 = bno; blkio(bno, ibuff2, read); #ifdef CRYPT if(xtflag) crblock(tperm, ibuff2, CRSIZE, (long)0); #endif hitin2 = 1; return (ibuff2 + off); } hitin2 = 0; if (ichanged) { #ifdef CRYPT if(xtflag) crblock(tperm, ibuff, CRSIZE, (long)0); #endif blkio(iblock, ibuff, write); } ichanged = 0; iblock = bno; blkio(bno, ibuff, read); #ifdef CRYPT if(xtflag) crblock(tperm, ibuff, CRSIZE, (long)0); #endif return (ibuff + off); } if (oblock >= 0) { #ifdef CRYPT if(xtflag) { /* * Encrypt block before writing, so some devious * person can't look at temp file while editing. */ p1 = obuff; p2 = crbuf; n = CRSIZE; while(n--) *p2++ = *p1++; crblock(tperm, crbuf, CRSIZE, (long)0); blkio(oblock, crbuf, write); } else #endif blkio(oblock, obuff, write); } oblock = bno; return (obuff + off); } #ifdef VMUNIX #define INCORB 64 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; } 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) - 7) = 'R'; rfile = creat(rfname, 0600); if (rfile < 0) oops: filioerr(rfname); 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 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 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. */ #ifdef CRYPT /* * crblock: encrypt/decrypt a block of text. * buf is the buffer through which the text is both input and * output. nchar is the size of the buffer. permp is a work * buffer, and startn is the beginning of a sequence. */ crblock(permp, buf, nchar, startn) char *permp; char *buf; int nchar; long startn; { register char *p1; int n1; int n2; register char *t1, *t2, *t3; t1 = permp; t2 = &permp[256]; t3 = &permp[512]; n1 = startn&0377; n2 = (startn>>8)&0377; p1 = buf; while(nchar--) { *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1; n1++; if(n1==256){ n1 = 0; n2++; if(n2==256) n2 = 0; } p1++; } } /* * makekey: initialize buffers based on user key a. */ makekey(a, b) char *a, *b; { register int i; long t; char temp[KSIZE + 1]; for(i = 0; i < KSIZE; i++) temp[i] = *a++; time(&t); t += getpid(); for(i = 0; i < 4; i++) temp[i] ^= (t>>(8*i))&0377; crinit(temp, b); } /* * crinit: besides initializing the encryption machine, this routine * returns 0 if the key is null, and 1 if it is non-null. */ crinit(keyp, permp) char *keyp, *permp; { register char *t1, *t2, *t3; register i; int ic, k, temp; unsigned random; char buf[13]; long seed; t1 = permp; t2 = &permp[256]; t3 = &permp[512]; if(*keyp == 0) return(0); strncpy(buf, keyp, 8); while (*keyp) *keyp++ = '\0'; buf[8] = buf[0]; buf[9] = buf[1]; domakekey(buf); seed = 123; for (i=0; i<13; i++) seed = seed*buf[i] + i; for(i=0;i<256;i++){ t1[i] = i; t3[i] = 0; } for(i=0; i<256; i++) { seed = 5*seed + buf[i%13]; random = seed % 65521; k = 256-1 - i; ic = (random&0377) % (k+1); random >>= 8; temp = t1[k]; t1[k] = t1[ic]; t1[ic] = temp; if(t3[k]!=0) continue; ic = (random&0377) % k; while(t3[ic]!=0) ic = (ic+1) % k; t3[k] = ic; t3[ic] = k; } for(i=0; i<256; i++) t2[t1[i]&0377] = i; return(1); } /* * domakekey: the following is the major nonportable part of the encryption * mechanism. A 10 character key is supplied in buffer. * This string is fed to makekey (an external program) which * responds with a 13 character result. This result is placed * in buffer. */ domakekey(buffer) char *buffer; { int pf[2]; if (pipe(pf)<0) pf[0] = pf[1] = -1; if (fork()==0) { close(0); close(1); dup(pf[0]); dup(pf[1]); execl("/usr/lib/makekey", "-", 0); execl("/lib/makekey", "-", 0); exit(1); } write(pf[1], buffer, 10); if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13) error("crypt: cannot generate key"); close(pf[0]); close(pf[1]); /* end of nonportable part */ } #endif