xref: /original-bsd/usr.bin/ex/ex_temp.c (revision de38840f)
1 /* Copyright (c) 1981 Regents of the University of California */
2 static char *sccsid = "@(#)ex_temp.c	7.1	07/08/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;	mjm: in ex_space.c */
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;
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 	char savelb[LBSIZE];
563 
564 	if (isdigit(c))
565 		kshift();
566 	if (islower(c))
567 		KILLreg(c);
568 	strp = sp = mapreg(c);
569 	sp->rg_flags = inopen && cursor && wcursor;
570 	rbuf = &arbuf;
571 	if (sp->rg_last) {
572 		regio(sp->rg_last, read);
573 		rnleft = sp->rg_nleft;
574 		rbufcp = &rbuf->rb_text[sizeof rbuf->rb_text - rnleft];
575 	} else {
576 		rblock = 0;
577 		rnleft = 0;
578 	}
579 	CP(savelb,linebuf);
580 	for (addr = addr1; addr <= addr2; addr++) {
581 		getline(*addr);
582 		if (sp->rg_flags) {
583 			if (addr == addr2)
584 				*wcursor = 0;
585 			if (addr == addr1)
586 				strcpy(linebuf, cursor);
587 		}
588 		YANKline();
589 	}
590 	rbflush();
591 	killed();
592 	CP(linebuf,savelb);
593 }
594 
595 kshift()
596 {
597 	register int i;
598 
599 	KILLreg('9');
600 	for (i = '8'; i >= '0'; i--)
601 		copy(mapreg(i+1), mapreg(i), sizeof (struct strreg));
602 }
603 
604 YANKline()
605 {
606 	register char *lp = linebuf;
607 	register struct rbuf *rp = rbuf;
608 	register int c;
609 
610 	do {
611 		c = *lp++;
612 		if (c == 0)
613 			c = '\n';
614 		if (rnleft == 0) {
615 			rp->rb_next = REGblk();
616 			rbflush();
617 			rblock = rp->rb_next;
618 			rp->rb_next = 0;
619 			rp->rb_prev = rblock;
620 			rnleft = sizeof rp->rb_text;
621 			rbufcp = rp->rb_text;
622 		}
623 		*rbufcp++ = c;
624 		--rnleft;
625 	} while (c != '\n');
626 	if (rnleft)
627 		*rbufcp = 0;
628 }
629 
630 rbflush()
631 {
632 	register struct strreg *sp = strp;
633 
634 	if (rblock == 0)
635 		return;
636 	regio(rblock, write);
637 	if (sp->rg_first == 0)
638 		sp->rg_first = rblock;
639 	sp->rg_last = rblock;
640 	sp->rg_nleft = rnleft;
641 }
642 
643 /* Register c to char buffer buf of size buflen */
644 regbuf(c, buf, buflen)
645 char c;
646 char *buf;
647 int buflen;
648 {
649 	struct rbuf arbuf;
650 	register char *p, *lp;
651 
652 	rbuf = &arbuf;
653 	rnleft = 0;
654 	rblock = 0;
655 	rnext = mapreg(c)->rg_first;
656 	if (rnext==0) {
657 		*buf = 0;
658 		error("Nothing in register %c",c);
659 	}
660 	p = buf;
661 	while (getREG()==0) {
662 		for (lp=linebuf; *lp;) {
663 			if (p >= &buf[buflen])
664 				error("Register too long@to fit in memory");
665 			*p++ = *lp++;
666 		}
667 		*p++ = '\n';
668 	}
669 	if (partreg(c)) p--;
670 	*p = '\0';
671 	getDOT();
672 }
673 
674 /*
675  * Encryption routines.  These are essentially unmodified from ed.
676  */
677 
678 #ifdef CRYPT
679 /*
680  * crblock: encrypt/decrypt a block of text.
681  * buf is the buffer through which the text is both input and
682  * output. nchar is the size of the buffer. permp is a work
683  * buffer, and startn is the beginning of a sequence.
684  */
685 crblock(permp, buf, nchar, startn)
686 char *permp;
687 char *buf;
688 int nchar;
689 long startn;
690 {
691 	register char *p1;
692 	int n1;
693 	int n2;
694 	register char *t1, *t2, *t3;
695 
696 	t1 = permp;
697 	t2 = &permp[256];
698 	t3 = &permp[512];
699 
700 	n1 = startn&0377;
701 	n2 = (startn>>8)&0377;
702 	p1 = buf;
703 	while(nchar--) {
704 		*p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
705 		n1++;
706 		if(n1==256){
707 			n1 = 0;
708 			n2++;
709 			if(n2==256) n2 = 0;
710 		}
711 		p1++;
712 	}
713 }
714 
715 /*
716  * makekey: initialize buffers based on user key a.
717  */
718 makekey(a, b)
719 char *a, *b;
720 {
721        register int i;
722 	long t;
723 	char temp[KSIZE + 1];
724 
725 	for(i = 0; i < KSIZE; i++)
726 		temp[i] = *a++;
727 	time(&t);
728 	t += getpid();
729 	for(i = 0; i < 4; i++)
730 		temp[i] ^= (t>>(8*i))&0377;
731 	crinit(temp, b);
732 }
733 
734 /*
735  * crinit: besides initializing the encryption machine, this routine
736  * returns 0 if the key is null, and 1 if it is non-null.
737  */
738 crinit(keyp, permp)
739 char    *keyp, *permp;
740 {
741        register char *t1, *t2, *t3;
742 	register i;
743 	int ic, k, temp;
744 	unsigned random;
745 	char buf[13];
746 	long seed;
747 
748 	t1 = permp;
749 	t2 = &permp[256];
750 	t3 = &permp[512];
751 	if(*keyp == 0)
752 		return(0);
753 	strncpy(buf, keyp, 8);
754 	while (*keyp)
755 		*keyp++ = '\0';
756 
757 	buf[8] = buf[0];
758 	buf[9] = buf[1];
759 	domakekey(buf);
760 
761 	seed = 123;
762 	for (i=0; i<13; i++)
763 		seed = seed*buf[i] + i;
764 	for(i=0;i<256;i++){
765 		t1[i] = i;
766 		t3[i] = 0;
767 	}
768 	for(i=0; i<256; i++) {
769 		seed = 5*seed + buf[i%13];
770 		random = seed % 65521;
771 		k = 256-1 - i;
772 		ic = (random&0377) % (k+1);
773 		random >>= 8;
774 		temp = t1[k];
775 		t1[k] = t1[ic];
776 		t1[ic] = temp;
777 		if(t3[k]!=0) continue;
778 		ic = (random&0377) % k;
779 		while(t3[ic]!=0) ic = (ic+1) % k;
780 		t3[k] = ic;
781 		t3[ic] = k;
782 	}
783 	for(i=0; i<256; i++)
784 		t2[t1[i]&0377] = i;
785 	return(1);
786 }
787 
788 /*
789  * domakekey: the following is the major nonportable part of the encryption
790  * mechanism. A 10 character key is supplied in buffer.
791  * This string is fed to makekey (an external program) which
792  * responds with a 13 character result. This result is placed
793  * in buffer.
794  */
795 domakekey(buffer)
796 char *buffer;
797 {
798        int pf[2];
799 
800 	if (pipe(pf)<0)
801 		pf[0] = pf[1] = -1;
802 	if (fork()==0) {
803 		close(0);
804 		close(1);
805 		dup(pf[0]);
806 		dup(pf[1]);
807 		execl("/usr/lib/makekey", "-", 0);
808 		execl("/lib/makekey", "-", 0);
809 		exit(1);
810 	}
811 	write(pf[1], buffer, 10);
812 	if (wait((int *)NULL)==-1 || read(pf[0], buffer, 13)!=13)
813 		error("crypt: cannot generate key");
814 	close(pf[0]);
815 	close(pf[1]);
816 	/* end of nonportable part */
817 }
818 #endif
819