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