Add copyright
[unix-history] / usr / src / usr.bin / ex / ex_temp.c
CommitLineData
299f2784 1/* Copyright (c) 1981 Regents of the University of California */
93fb1ab4 2static char *sccsid = "@(#)ex_temp.c 7.4 %G%";
d4a8288f
MH
3#include "ex.h"
4#include "ex_temp.h"
5#include "ex_vis.h"
6#include "ex_tty.h"
7
8/*
9 * Editor temporary file routines.
10 * Very similar to those of ed, except uses 2 input buffers.
11 */
12#define READ 0
13#define WRITE 1
14
15char tfname[40];
16char rfname[40];
17int havetmp;
cb3ac212 18short tfile = -1;
d4a8288f
MH
19short rfile = -1;
20
21fileinit()
22{
23 register char *p;
24 register int i, j;
25 struct stat stbuf;
26
44232d5b 27 if (tline == INCRMT * (HBLKS+2))
d4a8288f
MH
28 return;
29 cleanup(0);
30 close(tfile);
44232d5b
MH
31 tline = INCRMT * (HBLKS+2);
32 blocks[0] = HBLKS;
33 blocks[1] = HBLKS+1;
d4a8288f
MH
34 blocks[2] = -1;
35 dirtcnt = 0;
36 iblock = -1;
37 iblock2 = -1;
38 oblock = -1;
39 CP(tfname, svalue(DIRECTORY));
40 if (stat(tfname, &stbuf)) {
41dumbness:
42 if (setexit() == 0)
43 filioerr(tfname);
44 else
45 putNFL();
46 cleanup(1);
47 exit(1);
48 }
49 if ((stbuf.st_mode & S_IFMT) != S_IFDIR) {
50 errno = ENOTDIR;
51 goto dumbness;
52 }
53 ichanged = 0;
54 ichang2 = 0;
55 ignore(strcat(tfname, "/ExXXXXX"));
56 for (p = strend(tfname), i = 5, j = getpid(); i > 0; i--, j /= 10)
57 *--p = j % 10 | '0';
58 tfile = creat(tfname, 0600);
59 if (tfile < 0)
60 goto dumbness;
7c4625ef
MH
61#ifdef VMUNIX
62 {
63 extern stilinc; /* see below */
64 stilinc = 0;
65 }
66#endif
d4a8288f
MH
67 havetmp = 1;
68 close(tfile);
69 tfile = open(tfname, 2);
70 if (tfile < 0)
71 goto dumbness;
72/* brk((char *)fendcore); */
73}
74
75cleanup(all)
76 bool all;
77{
78 if (all) {
79 putpad(TE);
80 flush();
81 }
82 if (havetmp)
83 unlink(tfname);
84 havetmp = 0;
85 if (all && rfile >= 0) {
86 unlink(rfname);
87 close(rfile);
88 rfile = -1;
89 }
90}
91
92getline(tl)
93 line tl;
94{
95 register char *bp, *lp;
96 register int nl;
97
98 lp = linebuf;
99 bp = getblock(tl, READ);
100 nl = nleft;
101 tl &= ~OFFMSK;
102 while (*lp++ = *bp++)
103 if (--nl == 0) {
104 bp = getblock(tl += INCRMT, READ);
105 nl = nleft;
106 }
107}
108
109putline()
110{
111 register char *bp, *lp;
112 register int nl;
113 line tl;
114
115 dirtcnt++;
116 lp = linebuf;
117 change();
118 tl = tline;
119 bp = getblock(tl, WRITE);
120 nl = nleft;
121 tl &= ~OFFMSK;
122 while (*bp = *lp++) {
123 if (*bp++ == '\n') {
124 *--bp = 0;
125 linebp = lp;
126 break;
127 }
128 if (--nl == 0) {
129 bp = getblock(tl += INCRMT, WRITE);
130 nl = nleft;
131 }
132 }
133 tl = tline;
134 tline += (((lp - linebuf) + BNDRY - 1) >> SHFT) & 077776;
135 return (tl);
136}
137
138int read();
139int write();
140
141char *
142getblock(atl, iof)
143 line atl;
144 int iof;
145{
146 register int bno, off;
d266c416
MH
147 register char *p1, *p2;
148 register int n;
d4a8288f
MH
149
150 bno = (atl >> OFFBTS) & BLKMSK;
151 off = (atl << SHFT) & LBTMSK;
152 if (bno >= NMBLKS)
153 error(" Tmp file too large");
154 nleft = BUFSIZ - off;
155 if (bno == iblock) {
156 ichanged |= iof;
157 hitin2 = 0;
158 return (ibuff + off);
159 }
160 if (bno == iblock2) {
161 ichang2 |= iof;
162 hitin2 = 1;
163 return (ibuff2 + off);
164 }
165 if (bno == oblock)
166 return (obuff + off);
167 if (iof == READ) {
168 if (hitin2 == 0) {
d266c416 169 if (ichang2) {
1807bf33 170#ifdef CRYPT
d266c416
MH
171 if(xtflag)
172 crblock(tperm, ibuff2, CRSIZE, (long)0);
1807bf33 173#endif
d4a8288f 174 blkio(iblock2, ibuff2, write);
d266c416 175 }
d4a8288f
MH
176 ichang2 = 0;
177 iblock2 = bno;
178 blkio(bno, ibuff2, read);
1807bf33 179#ifdef CRYPT
d266c416
MH
180 if(xtflag)
181 crblock(tperm, ibuff2, CRSIZE, (long)0);
1807bf33 182#endif
d4a8288f
MH
183 hitin2 = 1;
184 return (ibuff2 + off);
185 }
186 hitin2 = 0;
d266c416 187 if (ichanged) {
1807bf33 188#ifdef CRYPT
d266c416
MH
189 if(xtflag)
190 crblock(tperm, ibuff, CRSIZE, (long)0);
1807bf33 191#endif
d4a8288f 192 blkio(iblock, ibuff, write);
d266c416 193 }
d4a8288f
MH
194 ichanged = 0;
195 iblock = bno;
196 blkio(bno, ibuff, read);
1807bf33 197#ifdef CRYPT
d266c416
MH
198 if(xtflag)
199 crblock(tperm, ibuff, CRSIZE, (long)0);
1807bf33 200#endif
d4a8288f
MH
201 return (ibuff + off);
202 }
d266c416 203 if (oblock >= 0) {
1807bf33 204#ifdef CRYPT
d266c416
MH
205 if(xtflag) {
206 /*
207 * Encrypt block before writing, so some devious
208 * person can't look at temp file while editing.
209 */
210 p1 = obuff;
211 p2 = crbuf;
212 n = CRSIZE;
213 while(n--)
214 *p2++ = *p1++;
215 crblock(tperm, crbuf, CRSIZE, (long)0);
216 blkio(oblock, crbuf, write);
217 } else
1807bf33 218#endif
d266c416
MH
219 blkio(oblock, obuff, write);
220 }
d4a8288f
MH
221 oblock = bno;
222 return (obuff + off);
223}
224
7c4625ef
MH
225#ifdef VMUNIX
226#define INCORB 64
227char incorb[INCORB+1][BUFSIZ];
228#define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1)))
229int stilinc; /* up to here not written yet */
230#endif
231
d4a8288f
MH
232blkio(b, buf, iofcn)
233 short b;
234 char *buf;
235 int (*iofcn)();
236{
237
7c4625ef
MH
238#ifdef VMUNIX
239 if (b < INCORB) {
240 if (iofcn == read) {
241 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ);
242 return;
243 }
244 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ);
245 if (laste) {
246 if (b >= stilinc)
247 stilinc = b + 1;
248 return;
249 }
250 } else if (stilinc)
251 tflush();
252#endif
d4a8288f
MH
253 lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
254 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
255 filioerr(tfname);
256}
257
7c4625ef
MH
258#ifdef VMUNIX
259tlaste()
260{
261
262 if (stilinc)
263 dirtcnt = 0;
264}
265
266tflush()
267{
268 int i = stilinc;
269
270 stilinc = 0;
271 lseek(tfile, (long) 0, 0);
272 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
273 filioerr(tfname);
274}
275#endif
276
d4a8288f
MH
277/*
278 * Synchronize the state of the temporary file in case
279 * a crash occurs.
280 */
281synctmp()
282{
283 register int cnt;
284 register line *a;
285 register short *bp;
286
7c4625ef
MH
287#ifdef VMUNIX
288 if (stilinc)
289 return;
290#endif
d4a8288f
MH
291 if (dol == zero)
292 return;
293 if (ichanged)
294 blkio(iblock, ibuff, write);
295 ichanged = 0;
296 if (ichang2)
297 blkio(iblock2, ibuff2, write);
298 ichang2 = 0;
299 if (oblock != -1)
300 blkio(oblock, obuff, write);
301 time(&H.Time);
302 uid = getuid();
303 *zero = (line) H.Time;
304 for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
305 if (*bp < 0) {
306 tline = (tline + OFFMSK) &~ OFFMSK;
307 *bp = ((tline >> OFFBTS) & BLKMSK);
d266c416
MH
308 if (*bp > NMBLKS)
309 error(" Tmp file too large");
d4a8288f
MH
310 tline += INCRMT;
311 oblock = *bp + 1;
312 bp[1] = -1;
313 }
314 lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0);
315 cnt = ((dol - a) + 2) * sizeof (line);
316 if (cnt > BUFSIZ)
317 cnt = BUFSIZ;
318 if (write(tfile, (char *) a, cnt) != cnt) {
319oops:
320 *zero = 0;
321 filioerr(tfname);
322 }
323 *zero = 0;
324 }
325 flines = lineDOL();
326 lseek(tfile, 0l, 0);
327 if (write(tfile, (char *) &H, sizeof H) != sizeof H)
328 goto oops;
a7a51e4a
SL
329#ifdef notdef
330 /*
331 * This will insure that exrecover gets as much
332 * back after a crash as is absolutely possible,
333 * but can result in pregnant pauses between commands
334 * when the TSYNC call is made, so...
335 */
336 (void) fsync(tfile);
337#endif
d4a8288f
MH
338}
339
340TSYNC()
341{
342
299f2784 343 if (dirtcnt > MAXDIRT) { /* mjm: 12 --> MAXDIRT */
7c4625ef
MH
344#ifdef VMUNIX
345 if (stilinc)
346 tflush();
347#endif
d4a8288f
MH
348 dirtcnt = 0;
349 synctmp();
350 }
351}
352
353/*
354 * Named buffer routines.
355 * These are implemented differently than the main buffer.
356 * Each named buffer has a chain of blocks in the register file.
357 * Each block contains roughly 508 chars of text,
358 * and a previous and next block number. We also have information
359 * about which blocks came from deletes of multiple partial lines,
360 * e.g. deleting a sentence or a LISP object.
361 *
362 * We maintain a free map for the temp file. To free the blocks
363 * in a register we must read the blocks to find how they are chained
364 * together.
365 *
366 * BUG: The default savind of deleted lines in numbered
367 * buffers may be rather inefficient; it hasn't been profiled.
368 */
369struct strreg {
370 short rg_flags;
371 short rg_nleft;
372 short rg_first;
373 short rg_last;
374} strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
375
376struct rbuf {
377 short rb_prev;
378 short rb_next;
379 char rb_text[BUFSIZ - 2 * sizeof (short)];
3c7b865a 380} *rbuf, KILLrbuf, putrbuf, YANKrbuf, regrbuf;
887e3e0d
MH
381#ifdef VMUNIX
382short rused[256];
383#else
d4a8288f 384short rused[32];
887e3e0d 385#endif
d4a8288f
MH
386short rnleft;
387short rblock;
388short rnext;
389char *rbufcp;
390
391regio(b, iofcn)
392 short b;
393 int (*iofcn)();
394{
395
396 if (rfile == -1) {
397 CP(rfname, tfname);
398 *(strend(rfname) - 7) = 'R';
399 rfile = creat(rfname, 0600);
400 if (rfile < 0)
401oops:
402 filioerr(rfname);
403 close(rfile);
404 rfile = open(rfname, 2);
405 if (rfile < 0)
406 goto oops;
407 }
408 lseek(rfile, (long) b * BUFSIZ, 0);
409 if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
410 goto oops;
411 rblock = b;
412}
413
414REGblk()
415{
416 register int i, j, m;
417
418 for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
419 m = (rused[i] ^ 0177777) & 0177777;
420 if (i == 0)
421 m &= ~1;
422 if (m != 0) {
423 j = 0;
424 while ((m & 1) == 0)
425 j++, m >>= 1;
426 rused[i] |= (1 << j);
427#ifdef RDEBUG
428 printf("allocating block %d\n", i * 16 + j);
429#endif
430 return (i * 16 + j);
431 }
432 }
433 error("Out of register space (ugh)");
434 /*NOTREACHED*/
435}
436
437struct strreg *
438mapreg(c)
439 register int c;
440{
441
442 if (isupper(c))
443 c = tolower(c);
444 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
445}
446
447int shread();
448
449KILLreg(c)
450 register int c;
451{
d4a8288f
MH
452 register struct strreg *sp;
453
3c7b865a 454 rbuf = &KILLrbuf;
d4a8288f
MH
455 sp = mapreg(c);
456 rblock = sp->rg_first;
457 sp->rg_first = sp->rg_last = 0;
458 sp->rg_flags = sp->rg_nleft = 0;
459 while (rblock != 0) {
460#ifdef RDEBUG
461 printf("freeing block %d\n", rblock);
462#endif
463 rused[rblock / 16] &= ~(1 << (rblock % 16));
464 regio(rblock, shread);
465 rblock = rbuf->rb_next;
466 }
467}
468
469/*VARARGS*/
470shread()
471{
472 struct front { short a; short b; };
473
474 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
475 return (sizeof (struct rbuf));
476 return (0);
477}
478
479int getREG();
480
481putreg(c)
482 char c;
483{
d4a8288f
MH
484 register line *odot = dot;
485 register line *odol = dol;
486 register int cnt;
487
488 deletenone();
489 appendnone();
3c7b865a 490 rbuf = &putrbuf;
d4a8288f
MH
491 rnleft = 0;
492 rblock = 0;
493 rnext = mapreg(c)->rg_first;
494 if (rnext == 0) {
495 if (inopen) {
496 splitw++;
497 vclean();
498 vgoto(WECHO, 0);
499 }
500 vreg = -1;
501 error("Nothing in register %c", c);
502 }
503 if (inopen && partreg(c)) {
887e3e0d
MH
504 if (!FIXUNDO) {
505 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
506 error("Can't put partial line inside macro");
507 }
d4a8288f
MH
508 squish();
509 addr1 = addr2 = dol;
510 }
887e3e0d 511 cnt = append(getREG, addr2);
d4a8288f
MH
512 if (inopen && partreg(c)) {
513 unddol = dol;
514 dol = odol;
515 dot = odot;
516 pragged(0);
517 }
d4a8288f
MH
518 killcnt(cnt);
519 notecnt = cnt;
520}
521
522partreg(c)
523 char c;
524{
525
526 return (mapreg(c)->rg_flags);
527}
528
529notpart(c)
530 register int c;
531{
532
533 if (c)
534 mapreg(c)->rg_flags = 0;
535}
536
537getREG()
538{
539 register char *lp = linebuf;
540 register int c;
541
542 for (;;) {
543 if (rnleft == 0) {
544 if (rnext == 0)
545 return (EOF);
546 regio(rnext, read);
547 rnext = rbuf->rb_next;
548 rbufcp = rbuf->rb_text;
549 rnleft = sizeof rbuf->rb_text;
550 }
551 c = *rbufcp;
552 if (c == 0)
553 return (EOF);
554 rbufcp++, --rnleft;
555 if (c == '\n') {
556 *lp++ = 0;
557 return (0);
558 }
559 *lp++ = c;
560 }
561}
562
563YANKreg(c)
564 register int c;
565{
d4a8288f
MH
566 register line *addr;
567 register struct strreg *sp;
f0f2d980 568 char savelb[LBSIZE];
d4a8288f
MH
569
570 if (isdigit(c))
571 kshift();
572 if (islower(c))
573 KILLreg(c);
574 strp = sp = mapreg(c);
575 sp->rg_flags = inopen && cursor && wcursor;
3c7b865a 576 rbuf = &YANKrbuf;
d4a8288f
MH
577 if (sp->rg_last) {
578 regio(sp->rg_last, read);
579 rnleft = sp->rg_nleft;
580 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
581 } else {
582 rblock = 0;
583 rnleft = 0;
584 }
f0f2d980 585 CP(savelb,linebuf);
d4a8288f
MH
586 for (addr = addr1; addr <= addr2; addr++) {
587 getline(*addr);
588 if (sp->rg_flags) {
589 if (addr == addr2)
590 *wcursor = 0;
591 if (addr == addr1)
592 strcpy(linebuf, cursor);
593 }
594 YANKline();
595 }
596 rbflush();
597 killed();
f0f2d980 598 CP(linebuf,savelb);
d4a8288f
MH
599}
600
601kshift()
602{
603 register int i;
604
605 KILLreg('9');
606 for (i = '8'; i >= '0'; i--)
607 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
608}
609
610YANKline()
611{
612 register char *lp = linebuf;
613 register struct rbuf *rp = rbuf;
614 register int c;
615
616 do {
617 c = *lp++;
618 if (c == 0)
619 c = '\n';
620 if (rnleft == 0) {
621 rp->rb_next = REGblk();
622 rbflush();
623 rblock = rp->rb_next;
624 rp->rb_next = 0;
625 rp->rb_prev = rblock;
626 rnleft = sizeof rp->rb_text;
627 rbufcp = rp->rb_text;
628 }
629 *rbufcp++ = c;
630 --rnleft;
631 } while (c != '\n');
632 if (rnleft)
633 *rbufcp = 0;
634}
635
636rbflush()
637{
638 register struct strreg *sp = strp;
639
640 if (rblock == 0)
641 return;
642 regio(rblock, write);
643 if (sp->rg_first == 0)
644 sp->rg_first = rblock;
645 sp->rg_last = rblock;
646 sp->rg_nleft = rnleft;
647}
648
649/* Register c to char buffer buf of size buflen */
650regbuf(c, buf, buflen)
651char c;
652char *buf;
653int buflen;
654{
d4a8288f
MH
655 register char *p, *lp;
656
3c7b865a 657 rbuf = &regrbuf;
d4a8288f
MH
658 rnleft = 0;
659 rblock = 0;
660 rnext = mapreg(c)->rg_first;
661 if (rnext==0) {
662 *buf = 0;
663 error("Nothing in register %c",c);
664 }
665 p = buf;
666 while (getREG()==0) {
667 for (lp=linebuf; *lp;) {
668 if (p >= &buf[buflen])
669 error("Register too long@to fit in memory");
670 *p++ = *lp++;
671 }
672 *p++ = '\n';
673 }
674 if (partreg(c)) p--;
675 *p = '\0';
676 getDOT();
677}
d266c416
MH
678
679/*
680 * Encryption routines. These are essentially unmodified from ed.
681 */
682
1807bf33 683#ifdef CRYPT
d266c416
MH
684/*
685 * crblock: encrypt/decrypt a block of text.
686 * buf is the buffer through which the text is both input and
687 * output. nchar is the size of the buffer. permp is a work
688 * buffer, and startn is the beginning of a sequence.
689 */
690crblock(permp, buf, nchar, startn)
691char *permp;
692char *buf;
693int nchar;
694long startn;
695{
696 register char *p1;
697 int n1;
698 int n2;
699 register char *t1, *t2, *t3;
700
701 t1 = permp;
702 t2 = &permp[256];
703 t3 = &permp[512];
704
705 n1 = startn&0377;
706 n2 = (startn>>8)&0377;
707 p1 = buf;
708 while(nchar--) {
709 *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
710 n1++;
711 if(n1==256){
712 n1 = 0;
713 n2++;
714 if(n2==256) n2 = 0;
715 }
716 p1++;
717 }
718}
719
720/*
721 * makekey: initialize buffers based on user key a.
722 */
723makekey(a, b)
724char *a, *b;
725{
726 register int i;
727 long t;
728 char temp[KSIZE + 1];
729
730 for(i = 0; i < KSIZE; i++)
731 temp[i] = *a++;
732 time(&t);
733 t += getpid();
734 for(i = 0; i < 4; i++)
735 temp[i] ^= (t>>(8*i))&0377;
736 crinit(temp, b);
737}
738
739/*
740 * crinit: besides initializing the encryption machine, this routine
741 * returns 0 if the key is null, and 1 if it is non-null.
742 */
743crinit(keyp, permp)
744char *keyp, *permp;
745{
746 register char *t1, *t2, *t3;
747 register i;
748 int ic, k, temp;
749 unsigned random;
750 char buf[13];
751 long seed;
752
753 t1 = permp;
754 t2 = &permp[256];
755 t3 = &permp[512];
756 if(*keyp == 0)
757 return(0);
758 strncpy(buf, keyp, 8);
759 while (*keyp)
760 *keyp++ = '\0';
761
762 buf[8] = buf[0];
763 buf[9] = buf[1];
764 domakekey(buf);
765
766 seed = 123;
767 for (i=0; i<13; i++)
768 seed = seed*buf[i] + i;
769 for(i=0;i<256;i++){
770 t1[i] = i;
771 t3[i] = 0;
772 }
773 for(i=0; i<256; i++) {
774 seed = 5*seed + buf[i%13];
775 random = seed % 65521;
776 k = 256-1 - i;
777 ic = (random&0377) % (k+1);
778 random >>= 8;
779 temp = t1[k];
780 t1[k] = t1[ic];
781 t1[ic] = temp;
782 if(t3[k]!=0) continue;
783 ic = (random&0377) % k;
784 while(t3[ic]!=0) ic = (ic+1) % k;
785 t3[k] = ic;
786 t3[ic] = k;
787 }
788 for(i=0; i<256; i++)
789 t2[t1[i]&0377] = i;
790 return(1);
791}
792
793/*
794 * domakekey: the following is the major nonportable part of the encryption
795 * mechanism. A 10 character key is supplied in buffer.
796 * This string is fed to makekey (an external program) which
797 * responds with a 13 character result. This result is placed
798 * in buffer.
799 */
800domakekey(buffer)
801char *buffer;
802{
803 int pf[2];
804
805 if (pipe(pf)<0)
806 pf[0] = pf[1] = -1;
807 if (fork()==0) {
808 close(0);
809 close(1);
810 dup(pf[0]);
811 dup(pf[1]);
812 execl("/usr/lib/makekey", "-", 0);
813 execl("/lib/makekey", "-", 0);
814 exit(1);
815 }
816 write(pf[1], buffer, 10);
817 if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13)
818 error("crypt: cannot generate key");
819 close(pf[0]);
820 close(pf[1]);
821 /* end of nonportable part */
822}
1807bf33 823#endif