Bill added more buffers, and I put in sccs.
[unix-history] / usr / src / usr.bin / ex / ex_temp.c
CommitLineData
7c4625ef
MH
1/* Copyright (c) 1980 Regents of the University of California */
2static char *sccsid = "@(#)ex_temp.c 4.2 %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;
18short tfile = -1;
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
MH
169 if (ichang2) {
170 if(xtflag)
171 crblock(tperm, ibuff2, CRSIZE, (long)0);
d4a8288f 172 blkio(iblock2, ibuff2, write);
d266c416 173 }
d4a8288f
MH
174 ichang2 = 0;
175 iblock2 = bno;
176 blkio(bno, ibuff2, read);
d266c416
MH
177 if(xtflag)
178 crblock(tperm, ibuff2, CRSIZE, (long)0);
d4a8288f
MH
179 hitin2 = 1;
180 return (ibuff2 + off);
181 }
182 hitin2 = 0;
d266c416
MH
183 if (ichanged) {
184 if(xtflag)
185 crblock(tperm, ibuff, CRSIZE, (long)0);
d4a8288f 186 blkio(iblock, ibuff, write);
d266c416 187 }
d4a8288f
MH
188 ichanged = 0;
189 iblock = bno;
190 blkio(bno, ibuff, read);
d266c416
MH
191 if(xtflag)
192 crblock(tperm, ibuff, CRSIZE, (long)0);
d4a8288f
MH
193 return (ibuff + off);
194 }
d266c416
MH
195 if (oblock >= 0) {
196 if(xtflag) {
197 /*
198 * Encrypt block before writing, so some devious
199 * person can't look at temp file while editing.
200 */
201 p1 = obuff;
202 p2 = crbuf;
203 n = CRSIZE;
204 while(n--)
205 *p2++ = *p1++;
206 crblock(tperm, crbuf, CRSIZE, (long)0);
207 blkio(oblock, crbuf, write);
208 } else
209 blkio(oblock, obuff, write);
210 }
d4a8288f
MH
211 oblock = bno;
212 return (obuff + off);
213}
214
7c4625ef
MH
215#ifdef VMUNIX
216#define INCORB 64
217char incorb[INCORB+1][BUFSIZ];
218#define pagrnd(a) ((char *)(((int)a)&~(BUFSIZ-1)))
219int stilinc; /* up to here not written yet */
220#endif
221
d4a8288f
MH
222blkio(b, buf, iofcn)
223 short b;
224 char *buf;
225 int (*iofcn)();
226{
227
7c4625ef
MH
228#ifdef VMUNIX
229 if (b < INCORB) {
230 if (iofcn == read) {
231 bcopy(pagrnd(incorb[b+1]), buf, BUFSIZ);
232 return;
233 }
234 bcopy(buf, pagrnd(incorb[b+1]), BUFSIZ);
235 if (laste) {
236 if (b >= stilinc)
237 stilinc = b + 1;
238 return;
239 }
240 } else if (stilinc)
241 tflush();
242#endif
d4a8288f
MH
243 lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
244 if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
245 filioerr(tfname);
246}
247
7c4625ef
MH
248#ifdef VMUNIX
249tlaste()
250{
251
252 if (stilinc)
253 dirtcnt = 0;
254}
255
256tflush()
257{
258 int i = stilinc;
259
260 stilinc = 0;
261 lseek(tfile, (long) 0, 0);
262 if (write(tfile, pagrnd(incorb[1]), i * BUFSIZ) != (i * BUFSIZ))
263 filioerr(tfname);
264}
265#endif
266
d4a8288f
MH
267/*
268 * Synchronize the state of the temporary file in case
269 * a crash occurs.
270 */
271synctmp()
272{
273 register int cnt;
274 register line *a;
275 register short *bp;
276
7c4625ef
MH
277#ifdef VMUNIX
278 if (stilinc)
279 return;
280#endif
d4a8288f
MH
281 if (dol == zero)
282 return;
283 if (ichanged)
284 blkio(iblock, ibuff, write);
285 ichanged = 0;
286 if (ichang2)
287 blkio(iblock2, ibuff2, write);
288 ichang2 = 0;
289 if (oblock != -1)
290 blkio(oblock, obuff, write);
291 time(&H.Time);
292 uid = getuid();
293 *zero = (line) H.Time;
294 for (a = zero, bp = blocks; a <= dol; a += BUFSIZ / sizeof *a, bp++) {
295 if (*bp < 0) {
296 tline = (tline + OFFMSK) &~ OFFMSK;
297 *bp = ((tline >> OFFBTS) & BLKMSK);
d266c416
MH
298 if (*bp > NMBLKS)
299 error(" Tmp file too large");
d4a8288f
MH
300 tline += INCRMT;
301 oblock = *bp + 1;
302 bp[1] = -1;
303 }
304 lseek(tfile, (long) (unsigned) *bp * BUFSIZ, 0);
305 cnt = ((dol - a) + 2) * sizeof (line);
306 if (cnt > BUFSIZ)
307 cnt = BUFSIZ;
308 if (write(tfile, (char *) a, cnt) != cnt) {
309oops:
310 *zero = 0;
311 filioerr(tfname);
312 }
313 *zero = 0;
314 }
315 flines = lineDOL();
316 lseek(tfile, 0l, 0);
317 if (write(tfile, (char *) &H, sizeof H) != sizeof H)
318 goto oops;
319}
320
321TSYNC()
322{
323
324 if (dirtcnt > 12) {
7c4625ef
MH
325#ifdef VMUNIX
326 if (stilinc)
327 tflush();
328#endif
d4a8288f
MH
329 dirtcnt = 0;
330 synctmp();
331 }
332}
333
334/*
335 * Named buffer routines.
336 * These are implemented differently than the main buffer.
337 * Each named buffer has a chain of blocks in the register file.
338 * Each block contains roughly 508 chars of text,
339 * and a previous and next block number. We also have information
340 * about which blocks came from deletes of multiple partial lines,
341 * e.g. deleting a sentence or a LISP object.
342 *
343 * We maintain a free map for the temp file. To free the blocks
344 * in a register we must read the blocks to find how they are chained
345 * together.
346 *
347 * BUG: The default savind of deleted lines in numbered
348 * buffers may be rather inefficient; it hasn't been profiled.
349 */
350struct strreg {
351 short rg_flags;
352 short rg_nleft;
353 short rg_first;
354 short rg_last;
355} strregs[('z'-'a'+1) + ('9'-'0'+1)], *strp;
356
357struct rbuf {
358 short rb_prev;
359 short rb_next;
360 char rb_text[BUFSIZ - 2 * sizeof (short)];
361} *rbuf;
887e3e0d
MH
362#ifdef VMUNIX
363short rused[256];
364#else
d4a8288f 365short rused[32];
887e3e0d 366#endif
d4a8288f
MH
367short rnleft;
368short rblock;
369short rnext;
370char *rbufcp;
371
372regio(b, iofcn)
373 short b;
374 int (*iofcn)();
375{
376
377 if (rfile == -1) {
378 CP(rfname, tfname);
379 *(strend(rfname) - 7) = 'R';
380 rfile = creat(rfname, 0600);
381 if (rfile < 0)
382oops:
383 filioerr(rfname);
384 close(rfile);
385 rfile = open(rfname, 2);
386 if (rfile < 0)
387 goto oops;
388 }
389 lseek(rfile, (long) b * BUFSIZ, 0);
390 if ((*iofcn)(rfile, rbuf, BUFSIZ) != BUFSIZ)
391 goto oops;
392 rblock = b;
393}
394
395REGblk()
396{
397 register int i, j, m;
398
399 for (i = 0; i < sizeof rused / sizeof rused[0]; i++) {
400 m = (rused[i] ^ 0177777) & 0177777;
401 if (i == 0)
402 m &= ~1;
403 if (m != 0) {
404 j = 0;
405 while ((m & 1) == 0)
406 j++, m >>= 1;
407 rused[i] |= (1 << j);
408#ifdef RDEBUG
409 printf("allocating block %d\n", i * 16 + j);
410#endif
411 return (i * 16 + j);
412 }
413 }
414 error("Out of register space (ugh)");
415 /*NOTREACHED*/
416}
417
418struct strreg *
419mapreg(c)
420 register int c;
421{
422
423 if (isupper(c))
424 c = tolower(c);
425 return (isdigit(c) ? &strregs[('z'-'a'+1)+(c-'0')] : &strregs[c-'a']);
426}
427
428int shread();
429
430KILLreg(c)
431 register int c;
432{
433 struct rbuf arbuf;
434 register struct strreg *sp;
435
436 rbuf = &arbuf;
437 sp = mapreg(c);
438 rblock = sp->rg_first;
439 sp->rg_first = sp->rg_last = 0;
440 sp->rg_flags = sp->rg_nleft = 0;
441 while (rblock != 0) {
442#ifdef RDEBUG
443 printf("freeing block %d\n", rblock);
444#endif
445 rused[rblock / 16] &= ~(1 << (rblock % 16));
446 regio(rblock, shread);
447 rblock = rbuf->rb_next;
448 }
449}
450
451/*VARARGS*/
452shread()
453{
454 struct front { short a; short b; };
455
456 if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
457 return (sizeof (struct rbuf));
458 return (0);
459}
460
461int getREG();
462
463putreg(c)
464 char c;
465{
466 struct rbuf arbuf;
467 register line *odot = dot;
468 register line *odol = dol;
469 register int cnt;
470
471 deletenone();
472 appendnone();
473 rbuf = &arbuf;
474 rnleft = 0;
475 rblock = 0;
476 rnext = mapreg(c)->rg_first;
477 if (rnext == 0) {
478 if (inopen) {
479 splitw++;
480 vclean();
481 vgoto(WECHO, 0);
482 }
483 vreg = -1;
484 error("Nothing in register %c", c);
485 }
486 if (inopen && partreg(c)) {
887e3e0d
MH
487 if (!FIXUNDO) {
488 splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
489 error("Can't put partial line inside macro");
490 }
d4a8288f
MH
491 squish();
492 addr1 = addr2 = dol;
493 }
887e3e0d 494 cnt = append(getREG, addr2);
d4a8288f
MH
495 if (inopen && partreg(c)) {
496 unddol = dol;
497 dol = odol;
498 dot = odot;
499 pragged(0);
500 }
d4a8288f
MH
501 killcnt(cnt);
502 notecnt = cnt;
503}
504
505partreg(c)
506 char c;
507{
508
509 return (mapreg(c)->rg_flags);
510}
511
512notpart(c)
513 register int c;
514{
515
516 if (c)
517 mapreg(c)->rg_flags = 0;
518}
519
520getREG()
521{
522 register char *lp = linebuf;
523 register int c;
524
525 for (;;) {
526 if (rnleft == 0) {
527 if (rnext == 0)
528 return (EOF);
529 regio(rnext, read);
530 rnext = rbuf->rb_next;
531 rbufcp = rbuf->rb_text;
532 rnleft = sizeof rbuf->rb_text;
533 }
534 c = *rbufcp;
535 if (c == 0)
536 return (EOF);
537 rbufcp++, --rnleft;
538 if (c == '\n') {
539 *lp++ = 0;
540 return (0);
541 }
542 *lp++ = c;
543 }
544}
545
546YANKreg(c)
547 register int c;
548{
549 struct rbuf arbuf;
550 register line *addr;
551 register struct strreg *sp;
552
553 if (isdigit(c))
554 kshift();
555 if (islower(c))
556 KILLreg(c);
557 strp = sp = mapreg(c);
558 sp->rg_flags = inopen && cursor && wcursor;
559 rbuf = &arbuf;
560 if (sp->rg_last) {
561 regio(sp->rg_last, read);
562 rnleft = sp->rg_nleft;
563 rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
564 } else {
565 rblock = 0;
566 rnleft = 0;
567 }
568 for (addr = addr1; addr <= addr2; addr++) {
569 getline(*addr);
570 if (sp->rg_flags) {
571 if (addr == addr2)
572 *wcursor = 0;
573 if (addr == addr1)
574 strcpy(linebuf, cursor);
575 }
576 YANKline();
577 }
578 rbflush();
579 killed();
580}
581
582kshift()
583{
584 register int i;
585
586 KILLreg('9');
587 for (i = '8'; i >= '0'; i--)
588 copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
589}
590
591YANKline()
592{
593 register char *lp = linebuf;
594 register struct rbuf *rp = rbuf;
595 register int c;
596
597 do {
598 c = *lp++;
599 if (c == 0)
600 c = '\n';
601 if (rnleft == 0) {
602 rp->rb_next = REGblk();
603 rbflush();
604 rblock = rp->rb_next;
605 rp->rb_next = 0;
606 rp->rb_prev = rblock;
607 rnleft = sizeof rp->rb_text;
608 rbufcp = rp->rb_text;
609 }
610 *rbufcp++ = c;
611 --rnleft;
612 } while (c != '\n');
613 if (rnleft)
614 *rbufcp = 0;
615}
616
617rbflush()
618{
619 register struct strreg *sp = strp;
620
621 if (rblock == 0)
622 return;
623 regio(rblock, write);
624 if (sp->rg_first == 0)
625 sp->rg_first = rblock;
626 sp->rg_last = rblock;
627 sp->rg_nleft = rnleft;
628}
629
630/* Register c to char buffer buf of size buflen */
631regbuf(c, buf, buflen)
632char c;
633char *buf;
634int buflen;
635{
636 struct rbuf arbuf;
637 register char *p, *lp;
638
639 rbuf = &arbuf;
640 rnleft = 0;
641 rblock = 0;
642 rnext = mapreg(c)->rg_first;
643 if (rnext==0) {
644 *buf = 0;
645 error("Nothing in register %c",c);
646 }
647 p = buf;
648 while (getREG()==0) {
649 for (lp=linebuf; *lp;) {
650 if (p >= &buf[buflen])
651 error("Register too long@to fit in memory");
652 *p++ = *lp++;
653 }
654 *p++ = '\n';
655 }
656 if (partreg(c)) p--;
657 *p = '\0';
658 getDOT();
659}
d266c416
MH
660
661/*
662 * Encryption routines. These are essentially unmodified from ed.
663 */
664
665/*
666 * crblock: encrypt/decrypt a block of text.
667 * buf is the buffer through which the text is both input and
668 * output. nchar is the size of the buffer. permp is a work
669 * buffer, and startn is the beginning of a sequence.
670 */
671crblock(permp, buf, nchar, startn)
672char *permp;
673char *buf;
674int nchar;
675long startn;
676{
677 register char *p1;
678 int n1;
679 int n2;
680 register char *t1, *t2, *t3;
681
682 t1 = permp;
683 t2 = &permp[256];
684 t3 = &permp[512];
685
686 n1 = startn&0377;
687 n2 = (startn>>8)&0377;
688 p1 = buf;
689 while(nchar--) {
690 *p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
691 n1++;
692 if(n1==256){
693 n1 = 0;
694 n2++;
695 if(n2==256) n2 = 0;
696 }
697 p1++;
698 }
699}
700
701/*
702 * makekey: initialize buffers based on user key a.
703 */
704makekey(a, b)
705char *a, *b;
706{
707 register int i;
708 long t;
709 char temp[KSIZE + 1];
710
711 for(i = 0; i < KSIZE; i++)
712 temp[i] = *a++;
713 time(&t);
714 t += getpid();
715 for(i = 0; i < 4; i++)
716 temp[i] ^= (t>>(8*i))&0377;
717 crinit(temp, b);
718}
719
720/*
721 * crinit: besides initializing the encryption machine, this routine
722 * returns 0 if the key is null, and 1 if it is non-null.
723 */
724crinit(keyp, permp)
725char *keyp, *permp;
726{
727 register char *t1, *t2, *t3;
728 register i;
729 int ic, k, temp;
730 unsigned random;
731 char buf[13];
732 long seed;
733
734 t1 = permp;
735 t2 = &permp[256];
736 t3 = &permp[512];
737 if(*keyp == 0)
738 return(0);
739 strncpy(buf, keyp, 8);
740 while (*keyp)
741 *keyp++ = '\0';
742
743 buf[8] = buf[0];
744 buf[9] = buf[1];
745 domakekey(buf);
746
747 seed = 123;
748 for (i=0; i<13; i++)
749 seed = seed*buf[i] + i;
750 for(i=0;i<256;i++){
751 t1[i] = i;
752 t3[i] = 0;
753 }
754 for(i=0; i<256; i++) {
755 seed = 5*seed + buf[i%13];
756 random = seed % 65521;
757 k = 256-1 - i;
758 ic = (random&0377) % (k+1);
759 random >>= 8;
760 temp = t1[k];
761 t1[k] = t1[ic];
762 t1[ic] = temp;
763 if(t3[k]!=0) continue;
764 ic = (random&0377) % k;
765 while(t3[ic]!=0) ic = (ic+1) % k;
766 t3[k] = ic;
767 t3[ic] = k;
768 }
769 for(i=0; i<256; i++)
770 t2[t1[i]&0377] = i;
771 return(1);
772}
773
774/*
775 * domakekey: the following is the major nonportable part of the encryption
776 * mechanism. A 10 character key is supplied in buffer.
777 * This string is fed to makekey (an external program) which
778 * responds with a 13 character result. This result is placed
779 * in buffer.
780 */
781domakekey(buffer)
782char *buffer;
783{
784 int pf[2];
785
786 if (pipe(pf)<0)
787 pf[0] = pf[1] = -1;
788 if (fork()==0) {
789 close(0);
790 close(1);
791 dup(pf[0]);
792 dup(pf[1]);
793 execl("/usr/lib/makekey", "-", 0);
794 execl("/lib/makekey", "-", 0);
795 exit(1);
796 }
797 write(pf[1], buffer, 10);
798 if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13)
799 error("crypt: cannot generate key");
800 close(pf[0]);
801 close(pf[1]);
802 /* end of nonportable part */
803}