xref: /original-bsd/usr.bin/ex/ex_temp.c (revision d25e1985)
1 /* Copyright (c) 1980 Regents of the University of California */
2 static char *sccsid = "@(#)ex_temp.c	5.1 08/20/80";
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 > 12) {
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;
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 	struct rbuf arbuf;
444 	register struct strreg *sp;
445 
446 	rbuf = &arbuf;
447 	sp = mapreg(c);
448 	rblock = sp->rg_first;
449 	sp->rg_first = sp->rg_last = 0;
450 	sp->rg_flags = sp->rg_nleft = 0;
451 	while (rblock != 0) {
452 #ifdef RDEBUG
453 		printf("freeing block %d\n", rblock);
454 #endif
455 		rused[rblock / 16] &= ~(1 << (rblock % 16));
456 		regio(rblock, shread);
457 		rblock = rbuf->rb_next;
458 	}
459 }
460 
461 /*VARARGS*/
462 shread()
463 {
464 	struct front { short a; short b; };
465 
466 	if (read(rfile, (char *) rbuf, sizeof (struct front)) == sizeof (struct front))
467 		return (sizeof (struct rbuf));
468 	return (0);
469 }
470 
471 int	getREG();
472 
473 putreg(c)
474 	char c;
475 {
476 	struct rbuf arbuf;
477 	register line *odot = dot;
478 	register line *odol = dol;
479 	register int cnt;
480 
481 	deletenone();
482 	appendnone();
483 	rbuf = &arbuf;
484 	rnleft = 0;
485 	rblock = 0;
486 	rnext = mapreg(c)->rg_first;
487 	if (rnext == 0) {
488 		if (inopen) {
489 			splitw++;
490 			vclean();
491 			vgoto(WECHO, 0);
492 		}
493 		vreg = -1;
494 		error("Nothing in register %c", c);
495 	}
496 	if (inopen && partreg(c)) {
497 		if (!FIXUNDO) {
498 			splitw++; vclean(); vgoto(WECHO, 0); vreg = -1;
499 			error("Can't put partial line inside macro");
500 		}
501 		squish();
502 		addr1 = addr2 = dol;
503 	}
504 	cnt = append(getREG, addr2);
505 	if (inopen && partreg(c)) {
506 		unddol = dol;
507 		dol = odol;
508 		dot = odot;
509 		pragged(0);
510 	}
511 	killcnt(cnt);
512 	notecnt = cnt;
513 }
514 
515 partreg(c)
516 	char c;
517 {
518 
519 	return (mapreg(c)->rg_flags);
520 }
521 
522 notpart(c)
523 	register int c;
524 {
525 
526 	if (c)
527 		mapreg(c)->rg_flags = 0;
528 }
529 
530 getREG()
531 {
532 	register char *lp = linebuf;
533 	register int c;
534 
535 	for (;;) {
536 		if (rnleft == 0) {
537 			if (rnext == 0)
538 				return (EOF);
539 			regio(rnext, read);
540 			rnext = rbuf->rb_next;
541 			rbufcp = rbuf->rb_text;
542 			rnleft = sizeof rbuf->rb_text;
543 		}
544 		c = *rbufcp;
545 		if (c == 0)
546 			return (EOF);
547 		rbufcp++, --rnleft;
548 		if (c == '\n') {
549 			*lp++ = 0;
550 			return (0);
551 		}
552 		*lp++ = c;
553 	}
554 }
555 
556 YANKreg(c)
557 	register int c;
558 {
559 	struct rbuf arbuf;
560 	register line *addr;
561 	register struct strreg *sp;
562 
563 	if (isdigit(c))
564 		kshift();
565 	if (islower(c))
566 		KILLreg(c);
567 	strp = sp = mapreg(c);
568 	sp->rg_flags = inopen && cursor && wcursor;
569 	rbuf = &arbuf;
570 	if (sp->rg_last) {
571 		regio(sp->rg_last, read);
572 		rnleft = sp->rg_nleft;
573 		rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
574 	} else {
575 		rblock = 0;
576 		rnleft = 0;
577 	}
578 	for (addr = addr1; addr <= addr2; addr++) {
579 		getline(*addr);
580 		if (sp->rg_flags) {
581 			if (addr == addr2)
582 				*wcursor = 0;
583 			if (addr == addr1)
584 				strcpy(linebuf, cursor);
585 		}
586 		YANKline();
587 	}
588 	rbflush();
589 	killed();
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 	struct rbuf arbuf;
647 	register char *p, *lp;
648 
649 	rbuf = &arbuf;
650 	rnleft = 0;
651 	rblock = 0;
652 	rnext = mapreg(c)->rg_first;
653 	if (rnext==0) {
654 		*buf = 0;
655 		error("Nothing in register %c",c);
656 	}
657 	p = buf;
658 	while (getREG()==0) {
659 		for (lp=linebuf; *lp;) {
660 			if (p >= &buf[buflen])
661 				error("Register too long@to fit in memory");
662 			*p++ = *lp++;
663 		}
664 		*p++ = '\n';
665 	}
666 	if (partreg(c)) p--;
667 	*p = '\0';
668 	getDOT();
669 }
670 
671 /*
672  * Encryption routines.  These are essentially unmodified from ed.
673  */
674 
675 #ifdef CRYPT
676 /*
677  * crblock: encrypt/decrypt a block of text.
678  * buf is the buffer through which the text is both input and
679  * output. nchar is the size of the buffer. permp is a work
680  * buffer, and startn is the beginning of a sequence.
681  */
682 crblock(permp, buf, nchar, startn)
683 char *permp;
684 char *buf;
685 int nchar;
686 long startn;
687 {
688 	register char *p1;
689 	int n1;
690 	int n2;
691 	register char *t1, *t2, *t3;
692 
693 	t1 = permp;
694 	t2 = &permp[256];
695 	t3 = &permp[512];
696 
697 	n1 = startn&0377;
698 	n2 = (startn>>8)&0377;
699 	p1 = buf;
700 	while(nchar--) {
701 		*p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
702 		n1++;
703 		if(n1==256){
704 			n1 = 0;
705 			n2++;
706 			if(n2==256) n2 = 0;
707 		}
708 		p1++;
709 	}
710 }
711 
712 /*
713  * makekey: initialize buffers based on user key a.
714  */
715 makekey(a, b)
716 char *a, *b;
717 {
718        register int i;
719 	long t;
720 	char temp[KSIZE + 1];
721 
722 	for(i = 0; i < KSIZE; i++)
723 		temp[i] = *a++;
724 	time(&t);
725 	t += getpid();
726 	for(i = 0; i < 4; i++)
727 		temp[i] ^= (t>>(8*i))&0377;
728 	crinit(temp, b);
729 }
730 
731 /*
732  * crinit: besides initializing the encryption machine, this routine
733  * returns 0 if the key is null, and 1 if it is non-null.
734  */
735 crinit(keyp, permp)
736 char    *keyp, *permp;
737 {
738        register char *t1, *t2, *t3;
739 	register i;
740 	int ic, k, temp;
741 	unsigned random;
742 	char buf[13];
743 	long seed;
744 
745 	t1 = permp;
746 	t2 = &permp[256];
747 	t3 = &permp[512];
748 	if(*keyp == 0)
749 		return(0);
750 	strncpy(buf, keyp, 8);
751 	while (*keyp)
752 		*keyp++ = '\0';
753 
754 	buf[8] = buf[0];
755 	buf[9] = buf[1];
756 	domakekey(buf);
757 
758 	seed = 123;
759 	for (i=0; i<13; i++)
760 		seed = seed*buf[i] + i;
761 	for(i=0;i<256;i++){
762 		t1[i] = i;
763 		t3[i] = 0;
764 	}
765 	for(i=0; i<256; i++) {
766 		seed = 5*seed + buf[i%13];
767 		random = seed % 65521;
768 		k = 256-1 - i;
769 		ic = (random&0377) % (k+1);
770 		random >>= 8;
771 		temp = t1[k];
772 		t1[k] = t1[ic];
773 		t1[ic] = temp;
774 		if(t3[k]!=0) continue;
775 		ic = (random&0377) % k;
776 		while(t3[ic]!=0) ic = (ic+1) % k;
777 		t3[k] = ic;
778 		t3[ic] = k;
779 	}
780 	for(i=0; i<256; i++)
781 		t2[t1[i]&0377] = i;
782 	return(1);
783 }
784 
785 /*
786  * domakekey: the following is the major nonportable part of the encryption
787  * mechanism. A 10 character key is supplied in buffer.
788  * This string is fed to makekey (an external program) which
789  * responds with a 13 character result. This result is placed
790  * in buffer.
791  */
792 domakekey(buffer)
793 char *buffer;
794 {
795        int pf[2];
796 
797 	if (pipe(pf)<0)
798 		pf[0] = pf[1] = -1;
799 	if (fork()==0) {
800 		close(0);
801 		close(1);
802 		dup(pf[0]);
803 		dup(pf[1]);
804 		execl("/usr/lib/makekey", "-", 0);
805 		execl("/lib/makekey", "-", 0);
806 		exit(1);
807 	}
808 	write(pf[1], buffer, 10);
809 	if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13)
810 		error("crypt: cannot generate key");
811 	close(pf[0]);
812 	close(pf[1]);
813 	/* end of nonportable part */
814 }
815 #endif
816