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