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