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