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