xref: /original-bsd/bin/ed/ed.c (revision e58c8952)
1 /*-
2  * Copyright (c) 1991
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1991\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)ed.c	5.2 (Berkeley) 04/02/94";
16 #endif /* not lint */
17 
18 /*
19  * Editor
20  */
21 #define CRYPT
22 
23 #include <sys/param.h>
24 #include <sys/wait.h>
25 #include <signal.h>
26 #include <sgtty.h>
27 #undef CEOF
28 #include <fcntl.h>
29 #include <time.h>
30 #include <setjmp.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include "pathnames.h"
35 
36 #define	NULL	0
37 #define	LBSIZE	512
38 #define	ESIZE	128
39 #define	GBSIZE	256
40 #define	NBRA	5
41 #define	EOF	-1
42 
43 #define	CBRA	1
44 #define	CCHR	2
45 #define	CDOT	4
46 #define	CCL	6
47 #define	NCCL	8
48 #define	CDOL	10
49 #define	CEOF	11
50 #define	CKET	12
51 #define	CBACK	14
52 
53 #define	STAR	01
54 
55 char	Q[]	= "";
56 char	T[]	= "TMP";
57 #define	READ	0
58 #define	WRITE	1
59 
60 int	peekc;
61 int	lastc;
62 char	savedfile[MAXPATHLEN];
63 char	file[MAXPATHLEN];
64 char	linebuf[LBSIZE];
65 char	rhsbuf[LBSIZE/2];
66 char	expbuf[ESIZE+4];
67 int	circfl;
68 int	*zero;
69 int	*dot;
70 int	*dol;
71 int	*addr1;
72 int	*addr2;
73 char	genbuf[LBSIZE];
74 long	count;
75 char	*nextip;
76 char	*linebp;
77 int	ninbuf;
78 int	io;
79 int	pflag;
80 sig_t	oldhup;
81 sig_t	oldquit;
82 int	vflag	= 1;
83 
84 #ifdef CRYPT
85 /*
86  * Various flags and buffers needed by the encryption routines.
87  */
88 #define	KSIZE	9
89 int	xflag;
90 int	xtflag;
91 int	kflag;
92 char	key[KSIZE + 1];
93 char	crbuf[512];
94 char	perm[768];
95 char	tperm[768];
96 #endif CRYPT
97 
98 int	listf;
99 int	col;
100 char	*globp;
101 int	tfile	= -1;
102 int	tline;
103 char	tfname[sizeof(_PATH_TMP) + 20];
104 char	*loc1;
105 char	*loc2;
106 char	*locs;
107 char	ibuff[512];
108 int	iblock	= -1;
109 char	obuff[512];
110 int	oblock	= -1;
111 int	ichanged;
112 int	nleft;
113 char	WRERR[]	= "WRITE ERROR";
114 int	names[26];
115 int	anymarks;
116 char	*braslist[NBRA];
117 char	*braelist[NBRA];
118 int	nbra;
119 int	subnewa;
120 int	subolda;
121 int	fchange;
122 int	wrapp;
123 unsigned nlall = 128;
124 
125 int	*address();
126 char	*getline();
127 char	*getblock();
128 char	*place();
129 jmp_buf	savej;
130 
131 void onintr(), quit(), onhup();
132 
133 main(argc, argv)
134 	int argc;
135 	char **argv;
136 {
137 	register char *p1, *p2;
138 	sig_t oldintr;
139 
140 	oldquit = signal(SIGQUIT, SIG_IGN);
141 	oldhup = signal(SIGHUP, SIG_IGN);
142 	oldintr = signal(SIGINT, SIG_IGN);
143 	if ((int)signal(SIGTERM, SIG_IGN) == 0)
144 		signal(SIGTERM, quit);
145 	argv++;
146 	while (argc > 1 && **argv=='-') {
147 		switch((*argv)[1]) {
148 
149 		case '\0':
150 			vflag = 0;
151 			break;
152 
153 		case 'q':
154 			signal(SIGQUIT, SIG_DFL);
155 			vflag = 1;
156 			break;
157 
158 #ifdef CRYPT
159 		case 'x':
160 			xflag = 1;
161 			break;
162 #endif CRYPT
163 		}
164 		argv++;
165 		argc--;
166 	}
167 #ifdef CRYPT
168 	if(xflag){
169 		getkey();
170 		kflag = crinit(key, perm);
171 	}
172 #endif CRYPT
173 
174 	if (argc>1) {
175 		p1 = *argv;
176 		p2 = savedfile;
177 		while (*p2++ = *p1++)
178 			;
179 		globp = "r";
180 	}
181 	zero = (int *)malloc(nlall*sizeof(int));
182 	(void)strcpy(tfname, _PATH_TMP);
183 	(void)strcat(tfname, "_edXXXXXX");
184 	(void)mktemp(tfname);
185 	init();
186 	if (((int)oldintr&01) == 0)
187 		signal(SIGINT, onintr);
188 	if (((int)oldhup&01) == 0)
189 		signal(SIGHUP, onhup);
190 	setjmp(savej);
191 	commands();
192 	quit();
193 }
194 
195 commands()
196 {
197 	int getfile(), gettty();
198 	register *a1, c;
199 
200 	for (;;) {
201 	if (pflag) {
202 		pflag = 0;
203 		addr1 = addr2 = dot;
204 		goto print;
205 	}
206 	addr1 = 0;
207 	addr2 = 0;
208 	do {
209 		addr1 = addr2;
210 		if ((a1 = address())==0) {
211 			c = getchr();
212 			break;
213 		}
214 		addr2 = a1;
215 		if ((c=getchr()) == ';') {
216 			c = ',';
217 			dot = a1;
218 		}
219 	} while (c==',');
220 	if (addr1==0)
221 		addr1 = addr2;
222 	switch(c) {
223 
224 	case 'a':
225 		setdot();
226 		newline();
227 		append(gettty, addr2);
228 		continue;
229 
230 	case 'c':
231 		delete();
232 		append(gettty, addr1-1);
233 		continue;
234 
235 	case 'd':
236 		delete();
237 		continue;
238 
239 	case 'E':
240 		fchange = 0;
241 		c = 'e';
242 	case 'e':
243 		setnoaddr();
244 		if (vflag && fchange) {
245 			fchange = 0;
246 			error(Q);
247 		}
248 		filename(c);
249 		init();
250 		addr2 = zero;
251 		goto caseread;
252 
253 	case 'f':
254 		setnoaddr();
255 		filename(c);
256 		puts(savedfile);
257 		continue;
258 
259 	case 'g':
260 		global(1);
261 		continue;
262 
263 	case 'i':
264 		setdot();
265 		nonzero();
266 		newline();
267 		append(gettty, addr2-1);
268 		continue;
269 
270 
271 	case 'j':
272 		if (addr2==0) {
273 			addr1 = dot;
274 			addr2 = dot+1;
275 		}
276 		setdot();
277 		newline();
278 		nonzero();
279 		join();
280 		continue;
281 
282 	case 'k':
283 		if ((c = getchr()) < 'a' || c > 'z')
284 			error(Q);
285 		newline();
286 		setdot();
287 		nonzero();
288 		names[c-'a'] = *addr2 & ~01;
289 		anymarks |= 01;
290 		continue;
291 
292 	case 'm':
293 		move(0);
294 		continue;
295 
296 	case '\n':
297 		if (addr2==0)
298 			addr2 = dot+1;
299 		addr1 = addr2;
300 		goto print;
301 
302 	case 'l':
303 		listf++;
304 	case 'p':
305 	case 'P':
306 		newline();
307 	print:
308 		setdot();
309 		nonzero();
310 		a1 = addr1;
311 		do {
312 			puts(getline(*a1++));
313 		} while (a1 <= addr2);
314 		dot = addr2;
315 		listf = 0;
316 		continue;
317 
318 	case 'Q':
319 		fchange = 0;
320 	case 'q':
321 		setnoaddr();
322 		newline();
323 		quit();
324 
325 	case 'r':
326 		filename(c);
327 	caseread:
328 		if ((io = open(file, 0)) < 0) {
329 			lastc = '\n';
330 			error(file);
331 		}
332 		setall();
333 		ninbuf = 0;
334 		c = zero != dol;
335 		append(getfile, addr2);
336 		exfile();
337 		fchange = c;
338 		continue;
339 
340 	case 's':
341 		setdot();
342 		nonzero();
343 		substitute(globp!=0);
344 		continue;
345 
346 	case 't':
347 		move(1);
348 		continue;
349 
350 	case 'u':
351 		setdot();
352 		nonzero();
353 		newline();
354 		if ((*addr2&~01) != subnewa)
355 			error(Q);
356 		*addr2 = subolda;
357 		dot = addr2;
358 		continue;
359 
360 	case 'v':
361 		global(0);
362 		continue;
363 
364 	case 'W':
365 		wrapp++;
366 	case 'w':
367 		setall();
368 		nonzero();
369 		filename(c);
370 		if(!wrapp ||
371 		  ((io = open(file,1)) == -1) ||
372 		  ((lseek(io, 0L, 2)) == -1))
373 			if ((io = creat(file, 0666)) < 0)
374 				error(file);
375 		wrapp = 0;
376 		putfile();
377 		exfile();
378 		if (addr1==zero+1 && addr2==dol)
379 			fchange = 0;
380 		continue;
381 
382 #ifdef CRYPT
383 	case 'x':
384 		setnoaddr();
385 		newline();
386 		xflag = 1;
387 		puts("Entering encrypting mode!");
388 		getkey();
389 		kflag = crinit(key, perm);
390 		continue;
391 #endif CRYPT
392 
393 
394 	case '=':
395 		setall();
396 		newline();
397 		count = (addr2-zero)&077777;
398 		putd();
399 		putchr('\n');
400 		continue;
401 
402 	case '!':
403 		callunix();
404 		continue;
405 
406 	case EOF:
407 		return;
408 
409 	}
410 	error(Q);
411 	}
412 }
413 
414 int *
415 address()
416 {
417 	register *a1, minus, c;
418 	int n, relerr;
419 
420 	minus = 0;
421 	a1 = 0;
422 	for (;;) {
423 		c = getchr();
424 		if ('0'<=c && c<='9') {
425 			n = 0;
426 			do {
427 				n *= 10;
428 				n += c - '0';
429 			} while ((c = getchr())>='0' && c<='9');
430 			peekc = c;
431 			if (a1==0)
432 				a1 = zero;
433 			if (minus<0)
434 				n = -n;
435 			a1 += n;
436 			minus = 0;
437 			continue;
438 		}
439 		relerr = 0;
440 		if (a1 || minus)
441 			relerr++;
442 		switch(c) {
443 		case ' ':
444 		case '\t':
445 			continue;
446 
447 		case '+':
448 			minus++;
449 			if (a1==0)
450 				a1 = dot;
451 			continue;
452 
453 		case '-':
454 		case '^':
455 			minus--;
456 			if (a1==0)
457 				a1 = dot;
458 			continue;
459 
460 		case '?':
461 		case '/':
462 			compile(c);
463 			a1 = dot;
464 			for (;;) {
465 				if (c=='/') {
466 					a1++;
467 					if (a1 > dol)
468 						a1 = zero;
469 				} else {
470 					a1--;
471 					if (a1 < zero)
472 						a1 = dol;
473 				}
474 				if (execute(0, a1))
475 					break;
476 				if (a1==dot)
477 					error(Q);
478 			}
479 			break;
480 
481 		case '$':
482 			a1 = dol;
483 			break;
484 
485 		case '.':
486 			a1 = dot;
487 			break;
488 
489 		case '\'':
490 			if ((c = getchr()) < 'a' || c > 'z')
491 				error(Q);
492 			for (a1=zero; a1<=dol; a1++)
493 				if (names[c-'a'] == (*a1 & ~01))
494 					break;
495 			break;
496 
497 		default:
498 			peekc = c;
499 			if (a1==0)
500 				return(0);
501 			a1 += minus;
502 			if (a1<zero || a1>dol)
503 				error(Q);
504 			return(a1);
505 		}
506 		if (relerr)
507 			error(Q);
508 	}
509 }
510 
511 setdot()
512 {
513 	if (addr2 == 0)
514 		addr1 = addr2 = dot;
515 	if (addr1 > addr2)
516 		error(Q);
517 }
518 
519 setall()
520 {
521 	if (addr2==0) {
522 		addr1 = zero+1;
523 		addr2 = dol;
524 		if (dol==zero)
525 			addr1 = zero;
526 	}
527 	setdot();
528 }
529 
530 setnoaddr()
531 {
532 	if (addr2)
533 		error(Q);
534 }
535 
536 nonzero()
537 {
538 	if (addr1<=zero || addr2>dol)
539 		error(Q);
540 }
541 
542 newline()
543 {
544 	register c;
545 
546 	if ((c = getchr()) == '\n')
547 		return;
548 	if (c=='p' || c=='l') {
549 		pflag++;
550 		if (c=='l')
551 			listf++;
552 		if (getchr() == '\n')
553 			return;
554 	}
555 	error(Q);
556 }
557 
558 filename(comm)
559 {
560 	register char *p1, *p2;
561 	register c;
562 
563 	count = 0;
564 	c = getchr();
565 	if (c=='\n' || c==EOF) {
566 		p1 = savedfile;
567 		if (*p1==0 && comm!='f')
568 			error(Q);
569 		p2 = file;
570 		while (*p2++ = *p1++)
571 			;
572 		return;
573 	}
574 	if (c!=' ')
575 		error(Q);
576 	while ((c = getchr()) == ' ')
577 		;
578 	if (c=='\n')
579 		error(Q);
580 	p1 = file;
581 	do {
582 		*p1++ = c;
583 		if (c==' ' || c==EOF)
584 			error(Q);
585 	} while ((c = getchr()) != '\n');
586 	*p1++ = 0;
587 	if (savedfile[0]==0 || comm=='e' || comm=='f') {
588 		p1 = savedfile;
589 		p2 = file;
590 		while (*p1++ = *p2++)
591 			;
592 	}
593 }
594 
595 exfile()
596 {
597 	close(io);
598 	io = -1;
599 	if (vflag) {
600 		putd();
601 		putchr('\n');
602 	}
603 }
604 
605 void
606 onintr()
607 {
608 	/* not necessary: (void)signal(SIGINT, onintr); */
609 	putchr('\n');
610 	lastc = '\n';
611 	error(Q);
612 }
613 
614 void
615 onhup()
616 {
617 	/* not necessary: (void)signal(SIGINT, SIG_IGN); */
618 	/* not necessary: (void)signal(SIGHUP, SIG_IGN); */
619 	if (dol > zero) {
620 		addr1 = zero+1;
621 		addr2 = dol;
622 		io = creat("ed.hup", 0666);
623 		if (io > 0)
624 			putfile();
625 	}
626 	fchange = 0;
627 	quit();
628 }
629 
630 error(s)
631 char *s;
632 {
633 	register c;
634 
635 	wrapp = 0;
636 	listf = 0;
637 	putchr('?');
638 	puts(s);
639 	count = 0;
640 	lseek(0, (long)0, 2);
641 	pflag = 0;
642 	if (globp)
643 		lastc = '\n';
644 	globp = 0;
645 	peekc = lastc;
646 	if(lastc)
647 		while ((c = getchr()) != '\n' && c != EOF)
648 			;
649 	if (io > 0) {
650 		close(io);
651 		io = -1;
652 	}
653 	longjmp(savej, 1);
654 }
655 
656 getchr()
657 {
658 	char c;
659 	if (lastc=peekc) {
660 		peekc = 0;
661 		return(lastc);
662 	}
663 	if (globp) {
664 		if ((lastc = *globp++) != 0)
665 			return(lastc);
666 		globp = 0;
667 		return(EOF);
668 	}
669 	if (read(0, &c, 1) <= 0)
670 		return(lastc = EOF);
671 	lastc = c&0177;
672 	return(lastc);
673 }
674 
675 gettty()
676 {
677 	register c;
678 	register char *gf;
679 	register char *p;
680 
681 	p = linebuf;
682 	gf = globp;
683 	while ((c = getchr()) != '\n') {
684 		if (c==EOF) {
685 			if (gf)
686 				peekc = c;
687 			return(c);
688 		}
689 		if ((c &= 0177) == 0)
690 			continue;
691 		*p++ = c;
692 		if (p >= &linebuf[LBSIZE-2])
693 			error(Q);
694 	}
695 	*p++ = 0;
696 	if (linebuf[0]=='.' && linebuf[1]==0)
697 		return(EOF);
698 	return(0);
699 }
700 
701 getfile()
702 {
703 	register c;
704 	register char *lp, *fp;
705 
706 	lp = linebuf;
707 	fp = nextip;
708 	do {
709 		if (--ninbuf < 0) {
710 			if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
711 				return(EOF);
712 			fp = genbuf;
713 			while(fp < &genbuf[ninbuf]) {
714 				if (*fp++ & 0200) {
715 #ifdef CRYPT
716 					if (kflag)
717 						crblock(perm, genbuf, ninbuf+1, count);
718 #endif CRYPT
719 					break;
720 				}
721 			}
722 			fp = genbuf;
723 		}
724 		c = *fp++;
725 		if (c=='\0')
726 			continue;
727 		if (c&0200 || lp >= &linebuf[LBSIZE]) {
728 			lastc = '\n';
729 			error(Q);
730 		}
731 		*lp++ = c;
732 		count++;
733 	} while (c != '\n');
734 	*--lp = 0;
735 	nextip = fp;
736 	return(0);
737 }
738 
739 putfile()
740 {
741 	int *a1, n;
742 	register char *fp, *lp;
743 	register nib;
744 
745 	nib = 512;
746 	fp = genbuf;
747 	a1 = addr1;
748 	do {
749 		lp = getline(*a1++);
750 		for (;;) {
751 			if (--nib < 0) {
752 				n = fp-genbuf;
753 #ifdef CRYPT
754 				if(kflag)
755 					crblock(perm, genbuf, n, count-n);
756 #endif CRYPT
757 				if(write(io, genbuf, n) != n) {
758 					puts(WRERR);
759 					error(Q);
760 				}
761 				nib = 511;
762 				fp = genbuf;
763 			}
764 			count++;
765 			if ((*fp++ = *lp++) == 0) {
766 				fp[-1] = '\n';
767 				break;
768 			}
769 		}
770 	} while (a1 <= addr2);
771 	n = fp-genbuf;
772 #ifdef CRYPT
773 	if(kflag)
774 		crblock(perm, genbuf, n, count-n);
775 #endif CRYPT
776 	if(write(io, genbuf, n) != n) {
777 		puts(WRERR);
778 		error(Q);
779 	}
780 }
781 
782 append(f, a)
783 int *a;
784 int (*f)();
785 {
786 	register *a1, *a2, *rdot;
787 	int nline, tl;
788 
789 	nline = 0;
790 	dot = a;
791 	while ((*f)() == 0) {
792 		if ((dol-zero)+1 >= nlall) {
793 			int *ozero = zero;
794 			nlall += 512;
795 			if ((zero = (int *)realloc((char *)zero, nlall*sizeof(int)))==NULL) {
796 				lastc = '\n';
797 				zero = ozero;
798 				error("MEM?");
799 			}
800 			dot += zero - ozero;
801 			dol += zero - ozero;
802 		}
803 		tl = putline();
804 		nline++;
805 		a1 = ++dol;
806 		a2 = a1+1;
807 		rdot = ++dot;
808 		while (a1 > rdot)
809 			*--a2 = *--a1;
810 		*rdot = tl;
811 	}
812 	return(nline);
813 }
814 
815 callunix()
816 {
817 	register sig_t savint;
818 	register int pid, rpid;
819 	int retcode;
820 
821 	setnoaddr();
822 	if ((pid = fork()) == 0) {
823 		signal(SIGHUP, oldhup);
824 		signal(SIGQUIT, oldquit);
825 		execl(_PATH_BSHELL, "sh", "-t", 0);
826 		exit(0100);
827 	}
828 	savint = signal(SIGINT, SIG_IGN);
829 	while ((rpid = wait(&retcode)) != pid && rpid != -1)
830 		;
831 	signal(SIGINT, savint);
832 	puts("!");
833 }
834 
835 void
836 quit()
837 {
838 	if (vflag && fchange && dol!=zero) {
839 		fchange = 0;
840 		error(Q);
841 	}
842 	unlink(tfname);
843 	exit(0);
844 }
845 
846 delete()
847 {
848 	setdot();
849 	newline();
850 	nonzero();
851 	rdelete(addr1, addr2);
852 }
853 
854 rdelete(ad1, ad2)
855 int *ad1, *ad2;
856 {
857 	register *a1, *a2, *a3;
858 
859 	a1 = ad1;
860 	a2 = ad2+1;
861 	a3 = dol;
862 	dol -= a2 - a1;
863 	do {
864 		*a1++ = *a2++;
865 	} while (a2 <= a3);
866 	a1 = ad1;
867 	if (a1 > dol)
868 		a1 = dol;
869 	dot = a1;
870 	fchange = 1;
871 }
872 
873 gdelete()
874 {
875 	register *a1, *a2, *a3;
876 
877 	a3 = dol;
878 	for (a1=zero+1; (*a1&01)==0; a1++)
879 		if (a1>=a3)
880 			return;
881 	for (a2=a1+1; a2<=a3;) {
882 		if (*a2&01) {
883 			a2++;
884 			dot = a1;
885 		} else
886 			*a1++ = *a2++;
887 	}
888 	dol = a1-1;
889 	if (dot>dol)
890 		dot = dol;
891 	fchange = 1;
892 }
893 
894 char *
895 getline(tl)
896 {
897 	register char *bp, *lp;
898 	register nl;
899 
900 	lp = linebuf;
901 	bp = getblock(tl, READ);
902 	nl = nleft;
903 	tl &= ~0377;
904 	while (*lp++ = *bp++)
905 		if (--nl == 0) {
906 			bp = getblock(tl+=0400, READ);
907 			nl = nleft;
908 		}
909 	return(linebuf);
910 }
911 
912 putline()
913 {
914 	register char *bp, *lp;
915 	register nl;
916 	int tl;
917 
918 	fchange = 1;
919 	lp = linebuf;
920 	tl = tline;
921 	bp = getblock(tl, WRITE);
922 	nl = nleft;
923 	tl &= ~0377;
924 	while (*bp = *lp++) {
925 		if (*bp++ == '\n') {
926 			*--bp = 0;
927 			linebp = lp;
928 			break;
929 		}
930 		if (--nl == 0) {
931 			bp = getblock(tl+=0400, WRITE);
932 			nl = nleft;
933 		}
934 	}
935 	nl = tline;
936 	tline += (((lp-linebuf)+03)>>1)&077776;
937 	return(nl);
938 }
939 
940 char *
941 getblock(atl, iof)
942 {
943 	extern read(), write();
944 	register bno, off;
945 	register char *p1, *p2;
946 	register int n;
947 
948 	bno = (atl>>8)&0377;
949 	off = (atl<<1)&0774;
950 	if (bno >= 255) {
951 		lastc = '\n';
952 		error(T);
953 	}
954 	nleft = 512 - off;
955 	if (bno==iblock) {
956 		ichanged |= iof;
957 		return(ibuff+off);
958 	}
959 	if (bno==oblock)
960 		return(obuff+off);
961 	if (iof==READ) {
962 		if (ichanged) {
963 #ifdef CRYPT
964 			if(xtflag)
965 				crblock(tperm, ibuff, 512, (long)0);
966 #endif CRYPT
967 			blkio(iblock, ibuff, write);
968 		}
969 		ichanged = 0;
970 		iblock = bno;
971 		blkio(bno, ibuff, read);
972 #ifdef CRYPT
973 		if(xtflag)
974 			crblock(tperm, ibuff, 512, (long)0);
975 #endif CRYPT
976 		return(ibuff+off);
977 	}
978 	if (oblock>=0) {
979 #ifdef CRYPT
980 		if(xtflag) {
981 			p1 = obuff;
982 			p2 = crbuf;
983 			n = 512;
984 			while(n--)
985 				*p2++ = *p1++;
986 			crblock(tperm, crbuf, 512, (long)0);
987 			blkio(oblock, crbuf, write);
988 		} else
989 #endif CRYPT
990 			blkio(oblock, obuff, write);
991 	}
992 	oblock = bno;
993 	return(obuff+off);
994 }
995 
996 blkio(b, buf, iofcn)
997 char *buf;
998 int (*iofcn)();
999 {
1000 	lseek(tfile, (long)b<<9, 0);
1001 	if ((*iofcn)(tfile, buf, 512) != 512) {
1002 		error(T);
1003 	}
1004 }
1005 
1006 init()
1007 {
1008 	register *markp;
1009 
1010 	close(tfile);
1011 	tline = 2;
1012 	for (markp = names; markp < &names[26]; )
1013 		*markp++ = 0;
1014 	subnewa = 0;
1015 	anymarks = 0;
1016 	iblock = -1;
1017 	oblock = -1;
1018 	ichanged = 0;
1019 	close(creat(tfname, 0600));
1020 	tfile = open(tfname, 2);
1021 #ifdef CRYPT
1022 	if(xflag) {
1023 		xtflag = 1;
1024 		makekey(key, tperm);
1025 	}
1026 #endif CRYPT
1027 	dot = dol = zero;
1028 }
1029 
1030 global(k)
1031 {
1032 	register char *gp;
1033 	register c;
1034 	register int *a1;
1035 	char globuf[GBSIZE];
1036 
1037 	if (globp)
1038 		error(Q);
1039 	setall();
1040 	nonzero();
1041 	if ((c=getchr())=='\n')
1042 		error(Q);
1043 	compile(c);
1044 	gp = globuf;
1045 	while ((c = getchr()) != '\n') {
1046 		if (c==EOF)
1047 			error(Q);
1048 		if (c=='\\') {
1049 			c = getchr();
1050 			if (c!='\n')
1051 				*gp++ = '\\';
1052 		}
1053 		*gp++ = c;
1054 		if (gp >= &globuf[GBSIZE-2])
1055 			error(Q);
1056 	}
1057 	*gp++ = '\n';
1058 	*gp++ = 0;
1059 	for (a1=zero; a1<=dol; a1++) {
1060 		*a1 &= ~01;
1061 		if (a1>=addr1 && a1<=addr2 && execute(0, a1)==k)
1062 			*a1 |= 01;
1063 	}
1064 	/*
1065 	 * Special case: g/.../d (avoid n^2 algorithm)
1066 	 */
1067 	if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
1068 		gdelete();
1069 		return;
1070 	}
1071 	for (a1=zero; a1<=dol; a1++) {
1072 		if (*a1 & 01) {
1073 			*a1 &= ~01;
1074 			dot = a1;
1075 			globp = globuf;
1076 			commands();
1077 			a1 = zero;
1078 		}
1079 	}
1080 }
1081 
1082 join()
1083 {
1084 	register char *gp, *lp;
1085 	register *a1;
1086 
1087 	gp = genbuf;
1088 	for (a1=addr1; a1<=addr2; a1++) {
1089 		lp = getline(*a1);
1090 		while (*gp = *lp++)
1091 			if (gp++ >= &genbuf[LBSIZE-2])
1092 				error(Q);
1093 	}
1094 	lp = linebuf;
1095 	gp = genbuf;
1096 	while (*lp++ = *gp++)
1097 		;
1098 	*addr1 = putline();
1099 	if (addr1<addr2)
1100 		rdelete(addr1+1, addr2);
1101 	dot = addr1;
1102 }
1103 
1104 substitute(inglob)
1105 {
1106 	register *markp, *a1, nl;
1107 	int gsubf;
1108 	int getsub();
1109 
1110 	gsubf = compsub();
1111 	for (a1 = addr1; a1 <= addr2; a1++) {
1112 		int *ozero;
1113 		if (execute(0, a1)==0)
1114 			continue;
1115 		inglob |= 01;
1116 		dosub();
1117 		if (gsubf) {
1118 			while (*loc2) {
1119 				if (execute(1, (int *)0)==0)
1120 					break;
1121 				dosub();
1122 			}
1123 		}
1124 		subnewa = putline();
1125 		*a1 &= ~01;
1126 		if (anymarks) {
1127 			for (markp = names; markp < &names[26]; markp++)
1128 				if (*markp == *a1)
1129 					*markp = subnewa;
1130 		}
1131 		subolda = *a1;
1132 		*a1 = subnewa;
1133 		ozero = zero;
1134 		nl = append(getsub, a1);
1135 		nl += zero-ozero;
1136 		a1 += nl;
1137 		addr2 += nl;
1138 	}
1139 	if (inglob==0)
1140 		error(Q);
1141 }
1142 
1143 compsub()
1144 {
1145 	register seof, c;
1146 	register char *p;
1147 
1148 	if ((seof = getchr()) == '\n' || seof == ' ')
1149 		error(Q);
1150 	compile(seof);
1151 	p = rhsbuf;
1152 	for (;;) {
1153 		c = getchr();
1154 		if (c=='\\')
1155 			c = getchr() | 0200;
1156 		if (c=='\n') {
1157 			if (globp)
1158 				c |= 0200;
1159 			else
1160 				error(Q);
1161 		}
1162 		if (c==seof)
1163 			break;
1164 		*p++ = c;
1165 		if (p >= &rhsbuf[LBSIZE/2])
1166 			error(Q);
1167 	}
1168 	*p++ = 0;
1169 	if ((peekc = getchr()) == 'g') {
1170 		peekc = 0;
1171 		newline();
1172 		return(1);
1173 	}
1174 	newline();
1175 	return(0);
1176 }
1177 
1178 getsub()
1179 {
1180 	register char *p1, *p2;
1181 
1182 	p1 = linebuf;
1183 	if ((p2 = linebp) == 0)
1184 		return(EOF);
1185 	while (*p1++ = *p2++)
1186 		;
1187 	linebp = 0;
1188 	return(0);
1189 }
1190 
1191 dosub()
1192 {
1193 	register char *lp, *sp, *rp;
1194 	int c;
1195 
1196 	lp = linebuf;
1197 	sp = genbuf;
1198 	rp = rhsbuf;
1199 	while (lp < loc1)
1200 		*sp++ = *lp++;
1201 	while (c = *rp++&0377) {
1202 		if (c=='&') {
1203 			sp = place(sp, loc1, loc2);
1204 			continue;
1205 		} else if (c&0200 && (c &= 0177) >='1' && c < nbra+'1') {
1206 			sp = place(sp, braslist[c-'1'], braelist[c-'1']);
1207 			continue;
1208 		}
1209 		*sp++ = c&0177;
1210 		if (sp >= &genbuf[LBSIZE])
1211 			error(Q);
1212 	}
1213 	lp = loc2;
1214 	loc2 = sp - genbuf + linebuf;
1215 	while (*sp++ = *lp++)
1216 		if (sp >= &genbuf[LBSIZE])
1217 			error(Q);
1218 	lp = linebuf;
1219 	sp = genbuf;
1220 	while (*lp++ = *sp++)
1221 		;
1222 }
1223 
1224 char *
1225 place(sp, l1, l2)
1226 register char *sp, *l1, *l2;
1227 {
1228 
1229 	while (l1 < l2) {
1230 		*sp++ = *l1++;
1231 		if (sp >= &genbuf[LBSIZE])
1232 			error(Q);
1233 	}
1234 	return(sp);
1235 }
1236 
1237 move(cflag)
1238 {
1239 	register int *adt, *ad1, *ad2;
1240 	int getcopy();
1241 
1242 	setdot();
1243 	nonzero();
1244 	if ((adt = address())==0)
1245 		error(Q);
1246 	newline();
1247 	if (cflag) {
1248 		int *ozero, delta;
1249 		ad1 = dol;
1250 		ozero = zero;
1251 		append(getcopy, ad1++);
1252 		ad2 = dol;
1253 		delta = zero - ozero;
1254 		ad1 += delta;
1255 		adt += delta;
1256 	} else {
1257 		ad2 = addr2;
1258 		for (ad1 = addr1; ad1 <= ad2;)
1259 			*ad1++ &= ~01;
1260 		ad1 = addr1;
1261 	}
1262 	ad2++;
1263 	if (adt<ad1) {
1264 		dot = adt + (ad2-ad1);
1265 		if ((++adt)==ad1)
1266 			return;
1267 		reverse(adt, ad1);
1268 		reverse(ad1, ad2);
1269 		reverse(adt, ad2);
1270 	} else if (adt >= ad2) {
1271 		dot = adt++;
1272 		reverse(ad1, ad2);
1273 		reverse(ad2, adt);
1274 		reverse(ad1, adt);
1275 	} else
1276 		error(Q);
1277 	fchange = 1;
1278 }
1279 
1280 reverse(a1, a2)
1281 register int *a1, *a2;
1282 {
1283 	register int t;
1284 
1285 	for (;;) {
1286 		t = *--a2;
1287 		if (a2 <= a1)
1288 			return;
1289 		*a2 = *a1;
1290 		*a1++ = t;
1291 	}
1292 }
1293 
1294 getcopy()
1295 {
1296 	if (addr1 > addr2)
1297 		return(EOF);
1298 	getline(*addr1++);
1299 	return(0);
1300 }
1301 
1302 compile(aeof)
1303 {
1304 	register eof, c;
1305 	register char *ep;
1306 	char *lastep;
1307 	char bracket[NBRA], *bracketp;
1308 	int cclcnt;
1309 
1310 	ep = expbuf;
1311 	eof = aeof;
1312 	bracketp = bracket;
1313 	if ((c = getchr()) == eof) {
1314 		if (*ep==0)
1315 			error(Q);
1316 		return;
1317 	}
1318 	circfl = 0;
1319 	nbra = 0;
1320 	if (c=='^') {
1321 		c = getchr();
1322 		circfl++;
1323 	}
1324 	peekc = c;
1325 	lastep = 0;
1326 	for (;;) {
1327 		if (ep >= &expbuf[ESIZE])
1328 			goto cerror;
1329 		c = getchr();
1330 		if (c==eof) {
1331 			if (bracketp != bracket)
1332 				goto cerror;
1333 			*ep++ = CEOF;
1334 			return;
1335 		}
1336 		if (c!='*')
1337 			lastep = ep;
1338 		switch (c) {
1339 
1340 		case '\\':
1341 			if ((c = getchr())=='(') {
1342 				if (nbra >= NBRA)
1343 					goto cerror;
1344 				*bracketp++ = nbra;
1345 				*ep++ = CBRA;
1346 				*ep++ = nbra++;
1347 				continue;
1348 			}
1349 			if (c == ')') {
1350 				if (bracketp <= bracket)
1351 					goto cerror;
1352 				*ep++ = CKET;
1353 				*ep++ = *--bracketp;
1354 				continue;
1355 			}
1356 			if (c>='1' && c<'1'+NBRA) {
1357 				*ep++ = CBACK;
1358 				*ep++ = c-'1';
1359 				continue;
1360 			}
1361 			*ep++ = CCHR;
1362 			if (c=='\n')
1363 				goto cerror;
1364 			*ep++ = c;
1365 			continue;
1366 
1367 		case '.':
1368 			*ep++ = CDOT;
1369 			continue;
1370 
1371 		case '\n':
1372 			goto cerror;
1373 
1374 		case '*':
1375 			if (lastep==0 || *lastep==CBRA || *lastep==CKET)
1376 				goto defchar;
1377 			*lastep |= STAR;
1378 			continue;
1379 
1380 		case '$':
1381 			if ((peekc=getchr()) != eof)
1382 				goto defchar;
1383 			*ep++ = CDOL;
1384 			continue;
1385 
1386 		case '[':
1387 			*ep++ = CCL;
1388 			*ep++ = 0;
1389 			cclcnt = 1;
1390 			if ((c=getchr()) == '^') {
1391 				c = getchr();
1392 				ep[-2] = NCCL;
1393 			}
1394 			do {
1395 				if (c=='\n')
1396 					goto cerror;
1397 				if (c=='-' && ep[-1]!=0) {
1398 					if ((c=getchr())==']') {
1399 						*ep++ = '-';
1400 						cclcnt++;
1401 						break;
1402 					}
1403 					while (ep[-1]<c) {
1404 						*ep = ep[-1]+1;
1405 						ep++;
1406 						cclcnt++;
1407 						if (ep>=&expbuf[ESIZE])
1408 							goto cerror;
1409 					}
1410 				}
1411 				*ep++ = c;
1412 				cclcnt++;
1413 				if (ep >= &expbuf[ESIZE])
1414 					goto cerror;
1415 			} while ((c = getchr()) != ']');
1416 			lastep[1] = cclcnt;
1417 			continue;
1418 
1419 		defchar:
1420 		default:
1421 			*ep++ = CCHR;
1422 			*ep++ = c;
1423 		}
1424 	}
1425    cerror:
1426 	expbuf[0] = 0;
1427 	nbra = 0;
1428 	error(Q);
1429 }
1430 
1431 execute(gf, addr)
1432 int *addr;
1433 {
1434 	register char *p1, *p2, c;
1435 
1436 	for (c=0; c<NBRA; c++) {
1437 		braslist[c] = 0;
1438 		braelist[c] = 0;
1439 	}
1440 	if (gf) {
1441 		if (circfl)
1442 			return(0);
1443 		p1 = linebuf;
1444 		p2 = genbuf;
1445 		while (*p1++ = *p2++)
1446 			;
1447 		locs = p1 = loc2;
1448 	} else {
1449 		if (addr==zero)
1450 			return(0);
1451 		p1 = getline(*addr);
1452 		locs = 0;
1453 	}
1454 	p2 = expbuf;
1455 	if (circfl) {
1456 		loc1 = p1;
1457 		return(advance(p1, p2));
1458 	}
1459 	/* fast check for first character */
1460 	if (*p2==CCHR) {
1461 		c = p2[1];
1462 		do {
1463 			if (*p1!=c)
1464 				continue;
1465 			if (advance(p1, p2)) {
1466 				loc1 = p1;
1467 				return(1);
1468 			}
1469 		} while (*p1++);
1470 		return(0);
1471 	}
1472 	/* regular algorithm */
1473 	do {
1474 		if (advance(p1, p2)) {
1475 			loc1 = p1;
1476 			return(1);
1477 		}
1478 	} while (*p1++);
1479 	return(0);
1480 }
1481 
1482 advance(lp, ep)
1483 register char *ep, *lp;
1484 {
1485 	register char *curlp;
1486 	int i;
1487 
1488 	for (;;) switch (*ep++) {
1489 
1490 	case CCHR:
1491 		if (*ep++ == *lp++)
1492 			continue;
1493 		return(0);
1494 
1495 	case CDOT:
1496 		if (*lp++)
1497 			continue;
1498 		return(0);
1499 
1500 	case CDOL:
1501 		if (*lp==0)
1502 			continue;
1503 		return(0);
1504 
1505 	case CEOF:
1506 		loc2 = lp;
1507 		return(1);
1508 
1509 	case CCL:
1510 		if (cclass(ep, *lp++, 1)) {
1511 			ep += *ep;
1512 			continue;
1513 		}
1514 		return(0);
1515 
1516 	case NCCL:
1517 		if (cclass(ep, *lp++, 0)) {
1518 			ep += *ep;
1519 			continue;
1520 		}
1521 		return(0);
1522 
1523 	case CBRA:
1524 		braslist[*ep++] = lp;
1525 		continue;
1526 
1527 	case CKET:
1528 		braelist[*ep++] = lp;
1529 		continue;
1530 
1531 	case CBACK:
1532 		if (braelist[i = *ep++]==0)
1533 			error(Q);
1534 		if (backref(i, lp)) {
1535 			lp += braelist[i] - braslist[i];
1536 			continue;
1537 		}
1538 		return(0);
1539 
1540 	case CBACK|STAR:
1541 		if (braelist[i = *ep++] == 0)
1542 			error(Q);
1543 		curlp = lp;
1544 		while (backref(i, lp))
1545 			lp += braelist[i] - braslist[i];
1546 		while (lp >= curlp) {
1547 			if (advance(lp, ep))
1548 				return(1);
1549 			lp -= braelist[i] - braslist[i];
1550 		}
1551 		continue;
1552 
1553 	case CDOT|STAR:
1554 		curlp = lp;
1555 		while (*lp++)
1556 			;
1557 		goto star;
1558 
1559 	case CCHR|STAR:
1560 		curlp = lp;
1561 		while (*lp++ == *ep)
1562 			;
1563 		ep++;
1564 		goto star;
1565 
1566 	case CCL|STAR:
1567 	case NCCL|STAR:
1568 		curlp = lp;
1569 		while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)))
1570 			;
1571 		ep += *ep;
1572 		goto star;
1573 
1574 	star:
1575 		do {
1576 			lp--;
1577 			if (lp==locs)
1578 				break;
1579 			if (advance(lp, ep))
1580 				return(1);
1581 		} while (lp > curlp);
1582 		return(0);
1583 
1584 	default:
1585 		error(Q);
1586 	}
1587 }
1588 
1589 backref(i, lp)
1590 register i;
1591 register char *lp;
1592 {
1593 	register char *bp;
1594 
1595 	bp = braslist[i];
1596 	while (*bp++ == *lp++)
1597 		if (bp >= braelist[i])
1598 			return(1);
1599 	return(0);
1600 }
1601 
1602 cclass(set, c, af)
1603 register char *set, c;
1604 {
1605 	register n;
1606 
1607 	if (c==0)
1608 		return(0);
1609 	n = *set++;
1610 	while (--n)
1611 		if (*set++ == c)
1612 			return(af);
1613 	return(!af);
1614 }
1615 
1616 putd()
1617 {
1618 	register r;
1619 
1620 	r = count%10;
1621 	count /= 10;
1622 	if (count)
1623 		putd();
1624 	putchr(r + '0');
1625 }
1626 
1627 puts(sp)
1628 register char *sp;
1629 {
1630 	col = 0;
1631 	while (*sp)
1632 		putchr(*sp++);
1633 	putchr('\n');
1634 }
1635 
1636 char	line[70];
1637 char	*linp	= line;
1638 
1639 putchr(ac)
1640 {
1641 	register char *lp;
1642 	register c;
1643 
1644 	lp = linp;
1645 	c = ac;
1646 	if (listf) {
1647 		col++;
1648 		if (col >= 72) {
1649 			col = 0;
1650 			*lp++ = '\\';
1651 			*lp++ = '\n';
1652 		}
1653 		if (c=='\t') {
1654 			c = '>';
1655 			goto esc;
1656 		}
1657 		if (c=='\b') {
1658 			c = '<';
1659 		esc:
1660 			*lp++ = '-';
1661 			*lp++ = '\b';
1662 			*lp++ = c;
1663 			goto out;
1664 		}
1665 		if (c<' ' && c!= '\n') {
1666 			*lp++ = '\\';
1667 			*lp++ = (c>>3)+'0';
1668 			*lp++ = (c&07)+'0';
1669 			col += 2;
1670 			goto out;
1671 		}
1672 	}
1673 	*lp++ = c;
1674 out:
1675 	if(c == '\n' || lp >= &line[64]) {
1676 		linp = line;
1677 		write(1, line, lp-line);
1678 		return;
1679 	}
1680 	linp = lp;
1681 }
1682 
1683 #ifdef CRYPT
1684 /*
1685  * Begin routines for doing encryption.
1686  */
1687 crblock(permp, buf, nchar, startn)
1688 char *permp;
1689 char *buf;
1690 long startn;
1691 {
1692 	register char *p1;
1693 	int n1;
1694 	int n2;
1695 	register char *t1, *t2, *t3;
1696 
1697 	t1 = permp;
1698 	t2 = &permp[256];
1699 	t3 = &permp[512];
1700 
1701 	n1 = startn&0377;
1702 	n2 = (startn>>8)&0377;
1703 	p1 = buf;
1704 	while(nchar--) {
1705 		*p1 = t2[(t3[(t1[(*p1+n1)&0377]+n2)&0377]-n2)&0377]-n1;
1706 		n1++;
1707 		if(n1==256){
1708 			n1 = 0;
1709 			n2++;
1710 			if(n2==256) n2 = 0;
1711 		}
1712 		p1++;
1713 	}
1714 }
1715 
1716 getkey()
1717 {
1718 	struct sgttyb b;
1719 	int save;
1720 	sig_t sig;
1721 	register char *p;
1722 	register c;
1723 
1724 	sig = signal(SIGINT, SIG_IGN);
1725 	if (ioctl(0, TIOCGETP, &b) == -1)
1726 		error("Input not tty");
1727 	save = b.sg_flags;
1728 	b.sg_flags &= ~ECHO;
1729 	(void)ioctl(0, TIOCSETP, &b);
1730 	puts("Key:");
1731 	p = key;
1732 	while(((c=getchr()) != EOF) && (c!='\n')) {
1733 		if(p < &key[KSIZE])
1734 			*p++ = c;
1735 	}
1736 	*p = 0;
1737 	b.sg_flags = save;
1738 	(void)ioctl(0, TIOCSETP, &b);
1739 	signal(SIGINT, sig);
1740 	return(key[0] != 0);
1741 }
1742 
1743 /*
1744  * Besides initializing the encryption machine, this routine
1745  * returns 0 if the key is null, and 1 if it is non-null.
1746  */
1747 crinit(keyp, permp)
1748 char	*keyp, *permp;
1749 {
1750 	register char *t1, *t2, *t3;
1751 	register i;
1752 	int ic, k, temp, pf[2];
1753 	unsigned random;
1754 	char buf[13];
1755 	long seed;
1756 
1757 	t1 = permp;
1758 	t2 = &permp[256];
1759 	t3 = &permp[512];
1760 	if(*keyp == 0)
1761 		return(0);
1762 	strncpy(buf, keyp, 8);
1763 	while (*keyp)
1764 		*keyp++ = '\0';
1765 	buf[8] = buf[0];
1766 	buf[9] = buf[1];
1767 	if (pipe(pf)<0)
1768 		pf[0] = pf[1] = -1;
1769 	if (fork()==0) {
1770 		close(0);
1771 		close(1);
1772 		dup(pf[0]);
1773 		dup(pf[1]);
1774 		execl(_PATH_MAKEKEY, "-", 0);
1775 		exit(1);
1776 	}
1777 	write(pf[1], buf, 10);
1778 	if (wait((int *)NULL)==-1 || read(pf[0], buf, 13)!=13)
1779 		error("crypt: cannot generate key");
1780 	close(pf[0]);
1781 	close(pf[1]);
1782 	seed = 123;
1783 	for (i=0; i<13; i++)
1784 		seed = seed*buf[i] + i;
1785 	for(i=0;i<256;i++){
1786 		t1[i] = i;
1787 		t3[i] = 0;
1788 	}
1789 	for(i=0; i<256; i++) {
1790 		seed = 5*seed + buf[i%13];
1791 		random = seed % 65521;
1792 		k = 256-1 - i;
1793 		ic = (random&0377) % (k+1);
1794 		random >>= 8;
1795 		temp = t1[k];
1796 		t1[k] = t1[ic];
1797 		t1[ic] = temp;
1798 		if(t3[k]!=0) continue;
1799 		ic = (random&0377) % k;
1800 		while(t3[ic]!=0) ic = (ic+1) % k;
1801 		t3[k] = ic;
1802 		t3[ic] = k;
1803 	}
1804 	for(i=0; i<256; i++)
1805 		t2[t1[i]&0377] = i;
1806 	return(1);
1807 }
1808 
1809 makekey(a, b)
1810 char *a, *b;
1811 {
1812 	register int i;
1813 	long t;
1814 	char temp[KSIZE + 1];
1815 
1816 	for(i = 0; i < KSIZE; i++)
1817 		temp[i] = *a++;
1818 	time(&t);
1819 	t += getpid();
1820 	for(i = 0; i < 4; i++)
1821 		temp[i] ^= (t>>(8*i))&0377;
1822 	crinit(temp, b);
1823 }
1824 #endif CRYPT
1825