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