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