plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

ed.c (23093B)


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