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