BSD 4_2 release
[unix-history] / usr / src / ucb / ex / ex_temp.c
/* Copyright (c) 1981 Regents of the University of California */
static char *sccsid = "@(#)ex_temp.c 7.4 7/30/83";
#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;
#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...
*/
(void) fsync(tfile);
#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) - 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 = &regrbuf;
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