#include "sed.h"

execute(file)
{
	extern	fout;
	register char *p1, *p2;
	register	c;
	int	i, fi;
	char	cflag;

	if (file) {
		if ((f = open(file, 0)) < 0) {
			printf2("Can't open %s\n", file);
		}
	} else
		f = 0;

	ebp = ibuf;
	cbp = ibuf;

	if(pending) {
		rep = pending;
		cflag = 1;
		pending = 0;
		goto com;
	}

	for(;;) {
		if((spend = gline(linebuf)) == -1) {
			close(f);
			return(0);
		}

		for(rep = ptrspace; rep->command; ) {

			p1 = rep->ad1;
			p2 = rep->ad2;
			cflag = 0;

			if(p1) {

				if(rep->inar) {
					cflag++;
					if(*p2 == CEND) {
						p1 = 0;
						goto com;
					}
					if(*p2 == CLNUM) {
						c = p2[1];
						if(lnum == tlno[c]) {
							rep->inar = 0;
						}
						if(lnum > tlno[c])
							rep->inar =
							cflag = 0;

						goto com;
					}
					if(match(p2, 0) || dolflag){
						rep->inar = 0;
					}
				} else if(*p1 == CEND) {
					if(dolflag)	cflag++;
					goto com;
				}else if(*p1 == CLNUM) {
					c = p1[1];
					if(lnum == tlno[c]) {
						cflag++;
						if(p2)
							rep->inar = 1;
						goto com;
					}
					if(lnum > tlno[c]) {
						rep++;
						continue;
					}
				} else {
					if(match(p1, 0)) {
						cflag++;
						if(p2)
							rep->inar = 1;
					}
				}
			} else
				cflag++;
com:
			if(cflag)	command();
			if(delflag)
				break;

			if(jflag) {
				jflag = 0;
				rep = rep->re1;
			} else
				rep++;

		}
		if(!nflag && !delflag)
			printf("%s\n", linebuf);

		if(aptr > abuf) {
			arout();
		}

		delflag = 0;

	}
}
match(expbuf, gf)
char	*expbuf;
{
	register char	*p1, *p2, c;

	if(gf) {
		if(*expbuf)	return(0);
		p1 = linebuf;
		p2 = genbuf;
		while(*p1++ = *p2++);
		locs = p1 = loc2;
	} else {
		p1 = linebuf;
		locs = 0;
	}

	p2 = expbuf;
	if(*p2++) {
		loc1 = p1;
		return(advance(p1, p2));
	}

	/* fast check for first character */

	if(*p2 == CCHR) {
		c = p2[1];
		do {
			if(*p1 != c)
				continue;
			if(advance(p1, p2)) {
				loc1 = p1;
				return(1);
			}
		} while(*p1++);
		return(0);
	}

	do {
		if(advance(p1, p2)) {
			loc1 = p1;
			return(1);
		}
	} while(*p1++);
	return(0);
}
advance(alp, aep)
{
	register char *lp, *ep, *curlp;
	char	c;
	char *nextep, *bbeg;
	int	ct;

/*	printf("*lp = %c, %o\n*ep = %c, %o\n", *lp, *lp, *ep, *ep);	/*DEBUG*/

	lp = alp;
	ep = aep;
	for (;;) switch (*ep++) {

	case CCHR:
		if (*ep++ == *lp++)
			continue;
		return(0);

	case CDOT:
		if (*lp++)
			continue;
		return(0);

	case CNL:
	case CDOL:
		if (*lp==0)
			continue;
		return(0);

	case CEOF:
		loc2 = lp;
		return(1);

	case CCL:
		c = *lp++ & 0177;
		if(ep[c>>3] & bittab[c & 07]) {
			ep =+ 16;
			continue;
		}
		return(0);

	case CBRA:
		braslist[*ep++] = lp;
		continue;

	case CKET:
		braelist[*ep++] = lp;
		continue;

	case CBACK:
		bbeg = braslist[*ep];
		ct = braelist[*ep++] - bbeg;

		if(ecmp(bbeg, lp, ct)) {
			lp =+ ct;
			continue;
		}
		return(0);

	case CBACK|STAR:
		bbeg = braslist[*ep];
		ct = braelist[*ep++] - bbeg;
		curlp = lp;
		while(ecmp(bbeg, lp, ct))
			lp =+ ct;

		while(lp >= curlp) {
			if(advance(lp, ep))	return(1);
			lp =- ct;
		}
		return(0);


	case CDOT|STAR:
		curlp = lp;
		while (*lp++);
		goto star;

	case CCHR|STAR:
		curlp = lp;
		while (*lp++ == *ep);
		ep++;
		goto star;

	case CCL|STAR:
		curlp = lp;
		do {
			c = *lp++ & 0177;
		} while(ep[c>>3] & bittab[c & 07]);
		ep =+ 16;
		goto star;

	star:
		if(--lp == curlp) {
			continue;
		}

		if(*ep == CCHR) {
			c = ep[1];
			do {
				if(*lp != c)
					continue;
				if(advance(lp, ep))
					return(1);
			} while(lp-- > curlp);
			return(0);
		}

		do {
			if(lp == locs)	break;
			if (advance(lp, ep))
				return(1);
		} while (lp-- > curlp);
		return(0);

	default:
		printf2("RE botch\n");
	}
}
substitute()
{
	if(match(rep->re1, 0) == 0)	return(0);

	sflag = 1;
	dosub(rep->rhs);

	if(rep->gfl) {
		while(*loc2) {
			if(match(rep->re1, 1) == 0) break;
			dosub(rep->rhs);
		}
	}
	return(1);
}
cclass(aset, ac, af)
{
	register char *set, c;
	register n;

	set = aset;
	if ((c = ac) == 0)
		return(0);
	n = *set++;
	while (--n)
		if (*set++ == c)
			return(af);
	return(!af);
}
dosub(rhsbuf)
char	*rhsbuf;
{
	register char *lp, *sp, *rp;
	int c;

	lp = linebuf;
	sp = genbuf;
	rp = rhsbuf;
	while (lp < loc1)
		*sp++ = *lp++;
	while(c = *rp++) {
		if (c=='&') {
			sp = place(sp, loc1, loc2);
			continue;
		} else if (c<0 && (c =& 0177) >='1' && c < NBRA+'1') {
			sp = place(sp, braslist[c-'1'], braelist[c-'1']);
			continue;
		}
		*sp++ = c&0177;
		if (sp >= &genbuf[LBSIZE])
			printf2("output line too long.\n");
	}
	lp = loc2;
	loc2 = sp + linebuf - genbuf;
	while (*sp++ = *lp++)
		if (sp >= &genbuf[LBSIZE]) {
			printf2("Output line too long.\n");
		}
	lp = linebuf;
	sp = genbuf;
	while (*lp++ = *sp++);
	spend = lp;
}
place(asp, al1, al2)
{
	register char *sp, *l1, *l2;

	sp = asp;
	l1 = al1;
	l2 = al2;
	while (l1 < l2) {
		*sp++ = *l1++;
		if (sp >= &genbuf[LBSIZE])
			printf2("Output line too long.\n");
	}
	return(sp);
}

command()
{
	register int	i;
	register char	*p1, *p2;

	if(rep->command & GCOM)
		if(match(rep->re2, 0) == 0)
			return;
	if(rep->command & VCOM)
		if(match(rep->re2, 0) == 1)
			return;

	switch(rep->command & ~(GCOM | VCOM)) {

		case ACOM:
			*aptr++ = rep;
			if(aptr >= &abuf[ABUFSIZE]) {
				printf2("Too many appends after line %ld\n",
					lnum);
			}
			*aptr = 0;
			break;

		case CCOM:
			delflag = 1;
			if(!rep->inar)
				printf("%s\n", rep->re1);
			break;
		case DCOM:
			delflag++;
			break;
		case CDCOM:
			p1 = p2 = linebuf;

			while(*p1 != '\n') {
				if(*p1++ == 0) {
					delflag++;
					return(0);
				}
			}

			p1++;
			while(*p2++ = *p1++);
			spend = p2;
			jflag++;
			break;

		case EQCOM:
			printf("%ld\n", lnum);
			break;


		case ICOM:
			printf("%s\n", rep->re1);
			break;

		case JCOM:
			jflag = 1;
			break;

		case LCOM:
			break;

		case NCOM:
			if(!nflag)
				printf("%s\n", linebuf);

			if(aptr > abuf)
				arout();
			if((spend = gline(linebuf)) == -1) {
				pending = rep;
				delflag = 1;
			}

			break;
		case CNCOM:
			if(aptr > abuf)
				arout();
			spend[-1] = '\n';
			if((spend = gline(spend)) == -1) {
				pending = rep;
				delflag = 1;
			}
			break;


		case PCOM:
			if(nflag)
				printf("%s\n", linebuf);
			break;
		case CPCOM:
			if(nflag) {
	cpcom:
				p1 = linebuf;
				while(*p1 != '\n' && *p1 != '\0')
					p1++;
				i = *p1;
				*p1 = '\0';
				printf("%s\n", linebuf);
				*p1 = i;
			}
			break;

		case QCOM:
			if(!nflag)
				printf("%s\n", linebuf);
			if(aptr > abuf)	arout();
			flush();
			exit(0);
		case RCOM:

			*aptr++ = rep;
			if(aptr >= &abuf[ABUFSIZE])
				printf2("Too many reads after line%ld\n",
					lnum);

			*aptr = 0;

			break;

		case SCOM:
			i = substitute();
			if(i && nflag && rep->pfl)
				if(rep->pfl == 1)
					printf("%s\n", linebuf);
				else
					goto cpcom;
			if(i && rep->fcode)
				goto wcom;
			break;

		case TCOM:
			if(sflag == 0)	break;
			sflag = 0;
			jflag = 1;
			break;

		wcom:
		case WCOM:
			i = 0;
			while(linebuf[i++]);
			linebuf[--i] = '\n';
			write(rep->fcode, linebuf, i + 1);
			linebuf[i] = '\0';
			break;
	}

}

gline(address)
char	*address;
{
	register char	*p1, *p2;
	register	c;
	p1 = address;
	p2 = cbp;
	for (;;) {
		if (p2 >= ebp) {
			if ((c = read(f, ibuf, 512)) <= 0) {
				return(-1);
			}
			p2 = ibuf;
			ebp = ibuf+c;
		}
		if ((c = *p2++) == '\n') {
			if(p2 >=  ebp) {
				if((c = read(f, ibuf, 512)) <= 0) {
					close(f);
					if(eargc == 0)
							dolflag = 1;
				}

					dolflag = 1;
				p2 = ibuf;
				ebp = ibuf + c;
			}
			break;
		}
		if(c)
		if(p1 < lbend)
			*p1++ = c;
	}
	lnum++;
	*p1++ = 0;
	cbp = p2;

	return(p1);
}
ecmp(a, b, count)
char	*a, *b;
{
	while(count--)
		if(*a++ != *b++)	return(0);
	return(1);
}

arout()
{
	int	i, fi;
	aptr = abuf - 1;
	while(*++aptr) {
		if(((*aptr)->command & ~(GCOM|VCOM))==ACOM)
			printf("%s\n", (*aptr)->re1);
		else {
			if((fi = open((*aptr)->re1, 0))
				< 0)
				continue;
			flush();
			while((i = read(fi, genbuf, 512))
				== 512)
				write(fout, genbuf, 512);
			if(i)	write(fout, genbuf, i);
			close(fi);
		}
	}
	aptr = abuf;
	*aptr = 0;
}

