xref: /csrg-svn/lib/libc/regex/engine.c (revision 65332)
155845Sbostic /*-
255845Sbostic  * Copyright (c) 1992 Henry Spencer.
361162Sbostic  * Copyright (c) 1992, 1993
461162Sbostic  *	The Regents of the University of California.  All rights reserved.
555845Sbostic  *
655845Sbostic  * This code is derived from software contributed to Berkeley by
755845Sbostic  * Henry Spencer of the University of Toronto.
855845Sbostic  *
955845Sbostic  * %sccs.include.redist.c%
1055845Sbostic  *
11*65332Sbostic  *	@(#)engine.c	8.2 (Berkeley) 01/02/94
1255845Sbostic  */
1355845Sbostic 
1455845Sbostic /*
1555845Sbostic  * The matching engine and friends.  This file is #included by regexec.c
1655845Sbostic  * after suitable #defines of a variety of macros used herein, so that
1755845Sbostic  * different state representations can be used without duplicating masses
1855845Sbostic  * of code.
1955845Sbostic  */
2055845Sbostic 
2155845Sbostic #ifdef SNAMES
2255845Sbostic #define	matcher	smatcher
2355845Sbostic #define	fast	sfast
2455845Sbostic #define	slow	sslow
2555845Sbostic #define	dissect	sdissect
2655845Sbostic #define	backref	sbackref
2755845Sbostic #define	step	sstep
2855845Sbostic #define	print	sprint
2956355Sbostic #define	at	sat
3055845Sbostic #define	match	smat
3155845Sbostic #endif
3255845Sbostic #ifdef LNAMES
3355845Sbostic #define	matcher	lmatcher
3455845Sbostic #define	fast	lfast
3555845Sbostic #define	slow	lslow
3655845Sbostic #define	dissect	ldissect
3755845Sbostic #define	backref	lbackref
3855845Sbostic #define	step	lstep
3955845Sbostic #define	print	lprint
4056355Sbostic #define	at	lat
4155845Sbostic #define	match	lmat
4255845Sbostic #endif
4355845Sbostic 
4455845Sbostic /* another structure passed up and down to avoid zillions of parameters */
4555845Sbostic struct match {
4655845Sbostic 	struct re_guts *g;
4755845Sbostic 	int eflags;
4855845Sbostic 	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
4960201Sbostic 	char *offp;		/* offsets work from here */
5060201Sbostic 	char *beginp;		/* start of string -- virtual NUL precedes */
5160201Sbostic 	char *endp;		/* end of string -- virtual NUL here */
5260201Sbostic 	char *coldp;		/* can be no match starting before here */
5360201Sbostic 	char **lastpos;		/* [nplus+1] */
5455845Sbostic 	STATEVARS;
5555845Sbostic 	states st;		/* current states */
5655845Sbostic 	states fresh;		/* states for a fresh start */
5755845Sbostic 	states tmp;		/* temporary */
5855845Sbostic 	states empty;		/* empty set of states */
5955845Sbostic };
6055845Sbostic 
6160201Sbostic static int matcher(/*register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags*/);
6260201Sbostic static char *dissect(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/);
6360201Sbostic static char *backref(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev*/);
6460201Sbostic static char *fast(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/);
6560201Sbostic static char *slow(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/);
6660201Sbostic static states step(/*register struct re_guts *g, int start, int stop, register states bef, int ch, register states aft*/);
6760201Sbostic #define	BOL	(OUT+1)
6860201Sbostic #define	EOL	(BOL+1)
6960201Sbostic #define	BOLEOL	(BOL+2)
7060201Sbostic #define	NOTHING	(BOL+3)
7160201Sbostic #define	BOW	(BOL+4)
7260201Sbostic #define	EOW	(BOL+5)
7360201Sbostic #define	CODEMAX	(BOL+5)		/* highest code used */
7460201Sbostic #define	NONCHAR(c)	((c) > CHAR_MAX)
7560201Sbostic #define	NNONCHAR	(CODEMAX-CHAR_MAX)
7656355Sbostic #ifdef REDEBUG
7760201Sbostic static void print(/*struct match *m, char *caption, states st, int ch, FILE *d*/);
7860201Sbostic #endif
7960201Sbostic #ifdef REDEBUG
8060201Sbostic static void at(/*struct match *m, char *title, char *start, char *stop, sopno startst, stopno stopst*/);
8160201Sbostic #endif
8260201Sbostic #ifdef REDEBUG
8360201Sbostic static char *pchar(/*int ch*/);
8460201Sbostic #endif
8560201Sbostic 
8660201Sbostic #ifdef REDEBUG
8756355Sbostic #define	SP(t, s, c)	print(m, t, s, c, stdout)
8856355Sbostic #define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
8956355Sbostic #define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
9055845Sbostic #else
9155845Sbostic #define	SP(t, s, c)	/* nothing */
9256355Sbostic #define	AT(t, p1, p2, s1, s2)	/* nothing */
9356355Sbostic #define	NOTE(s)	/* nothing */
9455845Sbostic #endif
9555845Sbostic 
9655845Sbostic /*
9755845Sbostic  - matcher - the actual matching engine
9860201Sbostic  == static int matcher(register struct re_guts *g, char *string, \
9960201Sbostic  ==	size_t nmatch, regmatch_t pmatch[], int eflags);
10055845Sbostic  */
10155845Sbostic static int			/* 0 success, REG_NOMATCH failure */
10255845Sbostic matcher(g, string, nmatch, pmatch, eflags)
10355845Sbostic register struct re_guts *g;
10460201Sbostic char *string;
10555845Sbostic size_t nmatch;
10655845Sbostic regmatch_t pmatch[];
10755845Sbostic int eflags;
10855845Sbostic {
10960201Sbostic 	register char *endp;
11055845Sbostic 	register int i;
11155845Sbostic 	struct match mv;
11255845Sbostic 	register struct match *m = &mv;
11360201Sbostic 	register char *dp;
11455845Sbostic 	const register sopno gf = g->firststate+1;	/* +1 for OEND */
11555845Sbostic 	const register sopno gl = g->laststate;
11660201Sbostic 	char *start;
11760201Sbostic 	char *stop;
11855845Sbostic 
11956355Sbostic 	/* simplify the situation where possible */
12055845Sbostic 	if (g->cflags&REG_NOSUB)
12156355Sbostic 		nmatch = 0;
12255845Sbostic 	if (eflags&REG_STARTEND) {
12355845Sbostic 		start = string + pmatch[0].rm_so;
12455845Sbostic 		stop = string + pmatch[0].rm_eo;
12555845Sbostic 	} else {
12655845Sbostic 		start = string;
12760201Sbostic 		stop = start + strlen(start);
12855845Sbostic 	}
12960201Sbostic 	if (stop < start)
13060201Sbostic 		return(REG_INVARG);
13155845Sbostic 
13255882Sbostic 	/* prescreening; this does wonders for this rather slow code */
13355882Sbostic 	if (g->must != NULL) {
13455882Sbostic 		for (dp = start; dp < stop; dp++)
13560201Sbostic 			if (*dp == g->must[0] && stop - dp >= g->mlen &&
13660201Sbostic 				memcmp(dp, g->must, (size_t)g->mlen) == 0)
13755882Sbostic 				break;
13855882Sbostic 		if (dp == stop)		/* we didn't find g->must */
13955882Sbostic 			return(REG_NOMATCH);
14055882Sbostic 	}
14155882Sbostic 
14255845Sbostic 	/* match struct setup */
14355845Sbostic 	m->g = g;
14455845Sbostic 	m->eflags = eflags;
14555845Sbostic 	m->pmatch = NULL;
14655845Sbostic 	m->lastpos = NULL;
14755845Sbostic 	m->offp = string;
14855845Sbostic 	m->beginp = start;
14955845Sbostic 	m->endp = stop;
15055845Sbostic 	STATESETUP(m, 4);
15155845Sbostic 	SETUP(m->st);
15255845Sbostic 	SETUP(m->fresh);
15355845Sbostic 	SETUP(m->tmp);
15455845Sbostic 	SETUP(m->empty);
15555845Sbostic 	CLEAR(m->empty);
15655845Sbostic 
15755845Sbostic 	/* this loop does only one repetition except for backrefs */
15855845Sbostic 	for (;;) {
15955845Sbostic 		endp = fast(m, start, stop, gf, gl);
16055845Sbostic 		if (endp == NULL) {		/* a miss */
16155845Sbostic 			STATETEARDOWN(m);
16255845Sbostic 			return(REG_NOMATCH);
16355845Sbostic 		}
16455845Sbostic 		if (nmatch == 0 && !g->backrefs)
16555845Sbostic 			break;		/* no further info needed */
16655845Sbostic 
16755845Sbostic 		/* where? */
16855845Sbostic 		assert(m->coldp != NULL);
16955845Sbostic 		for (;;) {
17056355Sbostic 			NOTE("finding start");
17155845Sbostic 			endp = slow(m, m->coldp, stop, gf, gl);
17255845Sbostic 			if (endp != NULL)
17355845Sbostic 				break;
17456355Sbostic 			assert(m->coldp < m->endp);
17555845Sbostic 			m->coldp++;
17655845Sbostic 		}
17755845Sbostic 		if (nmatch == 1 && !g->backrefs)
17855845Sbostic 			break;		/* no further info needed */
17955845Sbostic 
18055845Sbostic 		/* oh my, he wants the subexpressions... */
18155845Sbostic 		if (m->pmatch == NULL)
18255845Sbostic 			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
18355845Sbostic 							sizeof(regmatch_t));
18455845Sbostic 		if (m->pmatch == NULL) {
18555845Sbostic 			STATETEARDOWN(m);
18655845Sbostic 			return(REG_ESPACE);
18755845Sbostic 		}
18856355Sbostic 		for (i = 1; i <= m->g->nsub; i++)
18956355Sbostic 			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
19056355Sbostic 		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
19156355Sbostic 			NOTE("dissecting");
19255845Sbostic 			dp = dissect(m, m->coldp, endp, gf, gl);
19356355Sbostic 		} else {
19455845Sbostic 			if (g->nplus > 0 && m->lastpos == NULL)
19560201Sbostic 				m->lastpos = (char **)malloc((g->nplus+1) *
19660201Sbostic 							sizeof(char *));
19755845Sbostic 			if (g->nplus > 0 && m->lastpos == NULL) {
19855845Sbostic 				free(m->pmatch);
19955845Sbostic 				STATETEARDOWN(m);
20055845Sbostic 				return(REG_ESPACE);
20155845Sbostic 			}
20256355Sbostic 			NOTE("backref dissect");
20355845Sbostic 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
20455845Sbostic 		}
20555845Sbostic 		if (dp != NULL)
20655845Sbostic 			break;
20755845Sbostic 
20855845Sbostic 		/* uh-oh... we couldn't find a subexpression-level match */
20955845Sbostic 		assert(g->backrefs);	/* must be back references doing it */
21055845Sbostic 		assert(g->nplus == 0 || m->lastpos != NULL);
21156355Sbostic 		for (;;) {
21256355Sbostic 			if (dp != NULL || endp <= m->coldp)
21356355Sbostic 				break;		/* defeat */
21456355Sbostic 			NOTE("backoff");
21556355Sbostic 			endp = slow(m, m->coldp, endp-1, gf, gl);
21656355Sbostic 			if (endp == NULL)
21756355Sbostic 				break;		/* defeat */
21855845Sbostic 			/* try it on a shorter possibility */
21956355Sbostic #ifndef NDEBUG
22055845Sbostic 			for (i = 1; i <= m->g->nsub; i++) {
22156355Sbostic 				assert(m->pmatch[i].rm_so == -1);
22256355Sbostic 				assert(m->pmatch[i].rm_eo == -1);
22355845Sbostic 			}
22456355Sbostic #endif
22556355Sbostic 			NOTE("backoff dissect");
22655845Sbostic 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
22755845Sbostic 		}
22855845Sbostic 		assert(dp == NULL || dp == endp);
22955845Sbostic 		if (dp != NULL)		/* found a shorter one */
23055845Sbostic 			break;
23155845Sbostic 
23255845Sbostic 		/* despite initial appearances, there is no match here */
23356355Sbostic 		NOTE("false alarm");
23455845Sbostic 		start = m->coldp + 1;	/* recycle starting later */
23555845Sbostic 		assert(start <= stop);
23655845Sbostic 	}
23755845Sbostic 
23855845Sbostic 	/* fill in the details if requested */
23955845Sbostic 	if (nmatch > 0) {
24055845Sbostic 		pmatch[0].rm_so = m->coldp - m->offp;
24155845Sbostic 		pmatch[0].rm_eo = endp - m->offp;
24255845Sbostic 	}
24355845Sbostic 	if (nmatch > 1) {
24455845Sbostic 		assert(m->pmatch != NULL);
24555845Sbostic 		for (i = 1; i < nmatch; i++)
24655845Sbostic 			if (i <= m->g->nsub)
24755845Sbostic 				pmatch[i] = m->pmatch[i];
24855845Sbostic 			else {
24955845Sbostic 				pmatch[i].rm_so = -1;
25055845Sbostic 				pmatch[i].rm_eo = -1;
25155845Sbostic 			}
25255845Sbostic 	}
25355845Sbostic 
25455845Sbostic 	if (m->pmatch != NULL)
25555845Sbostic 		free((char *)m->pmatch);
25655845Sbostic 	if (m->lastpos != NULL)
25755845Sbostic 		free((char *)m->lastpos);
25855845Sbostic 	STATETEARDOWN(m);
25955845Sbostic 	return(0);
26055845Sbostic }
26155845Sbostic 
26255845Sbostic /*
26355845Sbostic  - dissect - figure out what matched what, no back references
26460201Sbostic  == static char *dissect(register struct match *m, char *start, \
26560201Sbostic  ==	char *stop, sopno startst, sopno stopst);
26655845Sbostic  */
26760201Sbostic static char *			/* == stop (success) always */
26855845Sbostic dissect(m, start, stop, startst, stopst)
26955845Sbostic register struct match *m;
27060201Sbostic char *start;
27160201Sbostic char *stop;
27255845Sbostic sopno startst;
27355845Sbostic sopno stopst;
27455845Sbostic {
27555845Sbostic 	register int i;
27655845Sbostic 	register sopno ss;	/* start sop of current subRE */
27755845Sbostic 	register sopno es;	/* end sop of current subRE */
27860201Sbostic 	register char *sp;	/* start of string matched by it */
27960201Sbostic 	register char *stp;	/* string matched by it cannot pass here */
28060201Sbostic 	register char *rest;	/* start of rest of string */
28160201Sbostic 	register char *tail;	/* string unmatched by rest of RE */
28255845Sbostic 	register sopno ssub;	/* start sop of subsubRE */
28355845Sbostic 	register sopno esub;	/* end sop of subsubRE */
28460201Sbostic 	register char *ssp;	/* start of string matched by subsubRE */
28560201Sbostic 	register char *sep;	/* end of string matched by subsubRE */
28660201Sbostic 	register char *oldssp;	/* previous ssp */
28760201Sbostic 	register char *dp;
28855845Sbostic 
28956355Sbostic 	AT("diss", start, stop, startst, stopst);
29055845Sbostic 	sp = start;
29155845Sbostic 	for (ss = startst; ss < stopst; ss = es) {
29255845Sbostic 		/* identify end of subRE */
29355845Sbostic 		es = ss;
29455845Sbostic 		switch (OP(m->g->strip[es])) {
29555845Sbostic 		case OPLUS_:
29655845Sbostic 		case OQUEST_:
29755845Sbostic 			es += OPND(m->g->strip[es]);
29855845Sbostic 			break;
29955845Sbostic 		case OCH_:
30055845Sbostic 			while (OP(m->g->strip[es]) != O_CH)
30155845Sbostic 				es += OPND(m->g->strip[es]);
30255845Sbostic 			break;
30355845Sbostic 		}
30455845Sbostic 		es++;
30555845Sbostic 
30655845Sbostic 		/* figure out what it matched */
30755845Sbostic 		switch (OP(m->g->strip[ss])) {
30855845Sbostic 		case OEND:
30960201Sbostic 			assert(nope);
31055845Sbostic 			break;
31155845Sbostic 		case OCHAR:
31255845Sbostic 			sp++;
31355845Sbostic 			break;
31455845Sbostic 		case OBOL:
31555845Sbostic 		case OEOL:
31660201Sbostic 		case OBOW:
31760201Sbostic 		case OEOW:
31855845Sbostic 			break;
31955845Sbostic 		case OANY:
32055845Sbostic 		case OANYOF:
32155845Sbostic 			sp++;
32255845Sbostic 			break;
32355845Sbostic 		case OBACK_:
32455845Sbostic 		case O_BACK:
32560201Sbostic 			assert(nope);
32655845Sbostic 			break;
32755845Sbostic 		/* cases where length of match is hard to find */
32855845Sbostic 		case OQUEST_:
32955845Sbostic 			stp = stop;
33055845Sbostic 			for (;;) {
33155845Sbostic 				/* how long could this one be? */
33255845Sbostic 				rest = slow(m, sp, stp, ss, es);
33355845Sbostic 				assert(rest != NULL);	/* it did match */
33455845Sbostic 				/* could the rest match the rest? */
33555845Sbostic 				tail = slow(m, rest, stop, es, stopst);
33655845Sbostic 				if (tail == stop)
33755845Sbostic 					break;		/* yes! */
33855845Sbostic 				/* no -- try a shorter match for this one */
33955845Sbostic 				stp = rest - 1;
34055845Sbostic 				assert(stp >= sp);	/* it did work */
34155845Sbostic 			}
34255845Sbostic 			ssub = ss + 1;
34355845Sbostic 			esub = es - 1;
34455845Sbostic 			/* did innards match? */
34555845Sbostic 			if (slow(m, sp, rest, ssub, esub) != NULL) {
34655845Sbostic 				dp = dissect(m, sp, rest, ssub, esub);
34755845Sbostic 				assert(dp == rest);
34855845Sbostic 			} else		/* no */
34955845Sbostic 				assert(sp == rest);
35055845Sbostic 			sp = rest;
35155845Sbostic 			break;
35255845Sbostic 		case OPLUS_:
35355845Sbostic 			stp = stop;
35455845Sbostic 			for (;;) {
35555845Sbostic 				/* how long could this one be? */
35655845Sbostic 				rest = slow(m, sp, stp, ss, es);
35755845Sbostic 				assert(rest != NULL);	/* it did match */
35855845Sbostic 				/* could the rest match the rest? */
35955845Sbostic 				tail = slow(m, rest, stop, es, stopst);
36055845Sbostic 				if (tail == stop)
36155845Sbostic 					break;		/* yes! */
36255845Sbostic 				/* no -- try a shorter match for this one */
36355845Sbostic 				stp = rest - 1;
36455845Sbostic 				assert(stp >= sp);	/* it did work */
36555845Sbostic 			}
36655845Sbostic 			ssub = ss + 1;
36755845Sbostic 			esub = es - 1;
36855845Sbostic 			ssp = sp;
36955845Sbostic 			oldssp = ssp;
37055845Sbostic 			for (;;) {	/* find last match of innards */
37155845Sbostic 				sep = slow(m, ssp, rest, ssub, esub);
37255845Sbostic 				if (sep == NULL || sep == ssp)
37355845Sbostic 					break;	/* failed or matched null */
37455845Sbostic 				oldssp = ssp;	/* on to next try */
37555845Sbostic 				ssp = sep;
37655845Sbostic 			}
37755845Sbostic 			if (sep == NULL) {
37855845Sbostic 				/* last successful match */
37955845Sbostic 				sep = ssp;
38055845Sbostic 				ssp = oldssp;
38155845Sbostic 			}
38255845Sbostic 			assert(sep == rest);	/* must exhaust substring */
38355845Sbostic 			assert(slow(m, ssp, sep, ssub, esub) == rest);
38455845Sbostic 			dp = dissect(m, ssp, sep, ssub, esub);
38555845Sbostic 			assert(dp == sep);
38655845Sbostic 			sp = rest;
38755845Sbostic 			break;
38855845Sbostic 		case OCH_:
38955845Sbostic 			stp = stop;
39055845Sbostic 			for (;;) {
39155845Sbostic 				/* how long could this one be? */
39255845Sbostic 				rest = slow(m, sp, stp, ss, es);
39355845Sbostic 				assert(rest != NULL);	/* it did match */
39455845Sbostic 				/* could the rest match the rest? */
39555845Sbostic 				tail = slow(m, rest, stop, es, stopst);
39655845Sbostic 				if (tail == stop)
39755845Sbostic 					break;		/* yes! */
39855845Sbostic 				/* no -- try a shorter match for this one */
39955845Sbostic 				stp = rest - 1;
40055845Sbostic 				assert(stp >= sp);	/* it did work */
40155845Sbostic 			}
40255845Sbostic 			ssub = ss + 1;
40355845Sbostic 			esub = ss + OPND(m->g->strip[ss]) - 1;
40455845Sbostic 			assert(OP(m->g->strip[esub]) == OOR1);
40555845Sbostic 			for (;;) {	/* find first matching branch */
40655845Sbostic 				if (slow(m, sp, rest, ssub, esub) == rest)
40755845Sbostic 					break;	/* it matched all of it */
40855845Sbostic 				/* that one missed, try next one */
40955845Sbostic 				assert(OP(m->g->strip[esub]) == OOR1);
41055845Sbostic 				esub++;
41155845Sbostic 				assert(OP(m->g->strip[esub]) == OOR2);
41255845Sbostic 				ssub = esub + 1;
41355845Sbostic 				esub += OPND(m->g->strip[esub]);
41455845Sbostic 				if (OP(m->g->strip[esub]) == OOR2)
41555845Sbostic 					esub--;
41655845Sbostic 				else
41755845Sbostic 					assert(OP(m->g->strip[esub]) == O_CH);
41855845Sbostic 			}
41955845Sbostic 			dp = dissect(m, sp, rest, ssub, esub);
42055845Sbostic 			assert(dp == rest);
42155845Sbostic 			sp = rest;
42255845Sbostic 			break;
42355845Sbostic 		case O_PLUS:
42455845Sbostic 		case O_QUEST:
42555845Sbostic 		case OOR1:
42655845Sbostic 		case OOR2:
42755845Sbostic 		case O_CH:
42860201Sbostic 			assert(nope);
42955845Sbostic 			break;
43055845Sbostic 		case OLPAREN:
43155845Sbostic 			i = OPND(m->g->strip[ss]);
43255845Sbostic 			m->pmatch[i].rm_so = sp - m->offp;
43355845Sbostic 			break;
43455845Sbostic 		case ORPAREN:
43555845Sbostic 			i = OPND(m->g->strip[ss]);
43655845Sbostic 			m->pmatch[i].rm_eo = sp - m->offp;
43755845Sbostic 			break;
43855845Sbostic 		default:		/* uh oh */
43960201Sbostic 			assert(nope);
44055845Sbostic 			break;
44155845Sbostic 		}
44255845Sbostic 	}
44355845Sbostic 
44455845Sbostic 	assert(sp == stop);
44555845Sbostic 	return(sp);
44655845Sbostic }
44755845Sbostic 
44855845Sbostic /*
44955845Sbostic  - backref - figure out what matched what, figuring in back references
45060201Sbostic  == static char *backref(register struct match *m, char *start, \
45160201Sbostic  ==	char *stop, sopno startst, sopno stopst, sopno lev);
45255845Sbostic  */
45360201Sbostic static char *			/* == stop (success) or NULL (failure) */
45455845Sbostic backref(m, start, stop, startst, stopst, lev)
45555845Sbostic register struct match *m;
45660201Sbostic char *start;
45760201Sbostic char *stop;
45855845Sbostic sopno startst;
45955845Sbostic sopno stopst;
46055845Sbostic sopno lev;			/* PLUS nesting level */
46155845Sbostic {
46255845Sbostic 	register int i;
46355845Sbostic 	register sopno ss;	/* start sop of current subRE */
46460201Sbostic 	register char *sp;	/* start of string matched by it */
46555845Sbostic 	register sopno ssub;	/* start sop of subsubRE */
46655845Sbostic 	register sopno esub;	/* end sop of subsubRE */
46760201Sbostic 	register char *ssp;	/* start of string matched by subsubRE */
46860201Sbostic 	register char *dp;
46955845Sbostic 	register size_t len;
47055845Sbostic 	register int hard;
47155845Sbostic 	register sop s;
47255845Sbostic 	register regoff_t offsave;
47355845Sbostic 	register cset *cs;
47455845Sbostic 
47556355Sbostic 	AT("back", start, stop, startst, stopst);
47655845Sbostic 	sp = start;
47755845Sbostic 
47855845Sbostic 	/* get as far as we can with easy stuff */
47955845Sbostic 	hard = 0;
48055845Sbostic 	for (ss = startst; !hard && ss < stopst; ss++)
48155845Sbostic 		switch (OP(s = m->g->strip[ss])) {
48255845Sbostic 		case OCHAR:
48360201Sbostic 			if (sp == stop || *sp++ != (char)OPND(s))
48455845Sbostic 				return(NULL);
48555845Sbostic 			break;
48655845Sbostic 		case OANY:
48755845Sbostic 			if (sp == stop)
48855845Sbostic 				return(NULL);
48955845Sbostic 			sp++;
49055845Sbostic 			break;
49155845Sbostic 		case OANYOF:
49255845Sbostic 			cs = &m->g->sets[OPND(s)];
49355845Sbostic 			if (sp == stop || !CHIN(cs, *sp++))
49455845Sbostic 				return(NULL);
49555845Sbostic 			break;
49655845Sbostic 		case OBOL:
49755845Sbostic 			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
49855845Sbostic 					(sp < m->endp && *(sp-1) == '\n' &&
49955845Sbostic 						(m->g->cflags&REG_NEWLINE)) )
50055845Sbostic 				{ /* yes */ }
50155845Sbostic 			else
50255845Sbostic 				return(NULL);
50355845Sbostic 			break;
50455845Sbostic 		case OEOL:
50555845Sbostic 			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
50655845Sbostic 					(sp < m->endp && *sp == '\n' &&
50755845Sbostic 						(m->g->cflags&REG_NEWLINE)) )
50855845Sbostic 				{ /* yes */ }
50955845Sbostic 			else
51055845Sbostic 				return(NULL);
51155845Sbostic 			break;
51260201Sbostic 		case OBOW:
51360201Sbostic 			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
51460201Sbostic 					(sp < m->endp && *(sp-1) == '\n' &&
51560201Sbostic 						(m->g->cflags&REG_NEWLINE)) ||
51660201Sbostic 					(sp > m->beginp &&
517*65332Sbostic 							!ISWORD(*(sp-1))) ) &&
518*65332Sbostic 					(sp < m->endp && ISWORD(*sp)) )
51960201Sbostic 				{ /* yes */ }
52060201Sbostic 			else
52160201Sbostic 				return(NULL);
52260201Sbostic 			break;
52360201Sbostic 		case OEOW:
52460201Sbostic 			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
52560201Sbostic 					(sp < m->endp && *sp == '\n' &&
52660201Sbostic 						(m->g->cflags&REG_NEWLINE)) ||
527*65332Sbostic 					(sp < m->endp && !ISWORD(*sp)) ) &&
528*65332Sbostic 					(sp > m->beginp && ISWORD(*(sp-1))) )
52960201Sbostic 				{ /* yes */ }
53060201Sbostic 			else
53160201Sbostic 				return(NULL);
53260201Sbostic 			break;
53355845Sbostic 		case O_QUEST:
53455845Sbostic 			break;
53555845Sbostic 		case OOR1:	/* matches null but needs to skip */
53655845Sbostic 			ss++;
53755845Sbostic 			s = m->g->strip[ss];
53855845Sbostic 			do {
53955845Sbostic 				assert(OP(s) == OOR2);
54055845Sbostic 				ss += OPND(s);
54155845Sbostic 			} while (OP(s = m->g->strip[ss]) != O_CH);
54255845Sbostic 			/* note that the ss++ gets us past the O_CH */
54355845Sbostic 			break;
54455845Sbostic 		default:	/* have to make a choice */
54555845Sbostic 			hard = 1;
54655845Sbostic 			break;
54755845Sbostic 		}
54855845Sbostic 	if (!hard) {		/* that was it! */
54955845Sbostic 		if (sp != stop)
55055845Sbostic 			return(NULL);
55155845Sbostic 		return(sp);
55255845Sbostic 	}
55355845Sbostic 	ss--;			/* adjust for the for's final increment */
55455845Sbostic 
55555845Sbostic 	/* the hard stuff */
55656355Sbostic 	AT("hard", sp, stop, ss, stopst);
55755845Sbostic 	s = m->g->strip[ss];
55855845Sbostic 	switch (OP(s)) {
55955845Sbostic 	case OBACK_:		/* the vilest depths */
56055845Sbostic 		i = OPND(s);
56155845Sbostic 		if (m->pmatch[i].rm_eo == -1)
56255845Sbostic 			return(NULL);
56355845Sbostic 		assert(m->pmatch[i].rm_so != -1);
56455845Sbostic 		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
56555845Sbostic 		assert(stop - m->beginp >= len);
56655845Sbostic 		if (sp > stop - len)
56755845Sbostic 			return(NULL);	/* not enough left to match */
56855845Sbostic 		ssp = m->offp + m->pmatch[i].rm_so;
56960201Sbostic 		if (memcmp(sp, ssp, len) != 0)
57055845Sbostic 			return(NULL);
57155845Sbostic 		while (m->g->strip[ss] != SOP(O_BACK, i))
57255845Sbostic 			ss++;
57355845Sbostic 		return(backref(m, sp+len, stop, ss+1, stopst, lev));
57455845Sbostic 		break;
57555845Sbostic 	case OQUEST_:		/* to null or not */
57655845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
57755845Sbostic 		if (dp != NULL)
57855845Sbostic 			return(dp);	/* not */
57955845Sbostic 		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
58055845Sbostic 		break;
58155845Sbostic 	case OPLUS_:
58255845Sbostic 		assert(m->lastpos != NULL);
58355845Sbostic 		assert(lev+1 <= m->g->nplus);
58455845Sbostic 		m->lastpos[lev+1] = sp;
58555845Sbostic 		return(backref(m, sp, stop, ss+1, stopst, lev+1));
58655845Sbostic 		break;
58755845Sbostic 	case O_PLUS:
58855845Sbostic 		if (sp == m->lastpos[lev])	/* last pass matched null */
58955845Sbostic 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
59055845Sbostic 		/* try another pass */
59155845Sbostic 		m->lastpos[lev] = sp;
59255845Sbostic 		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
59355845Sbostic 		if (dp == NULL)
59455845Sbostic 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
59555845Sbostic 		else
59655845Sbostic 			return(dp);
59755845Sbostic 		break;
59855845Sbostic 	case OCH_:		/* find the right one, if any */
59955845Sbostic 		ssub = ss + 1;
60055845Sbostic 		esub = ss + OPND(s) - 1;
60155845Sbostic 		assert(OP(m->g->strip[esub]) == OOR1);
60255845Sbostic 		for (;;) {	/* find first matching branch */
60355845Sbostic 			dp = backref(m, sp, stop, ssub, esub, lev);
60455845Sbostic 			if (dp != NULL)
60555845Sbostic 				return(dp);
60655845Sbostic 			/* that one missed, try next one */
60755845Sbostic 			if (OP(m->g->strip[esub]) == O_CH)
60855845Sbostic 				return(NULL);	/* there is none */
60955845Sbostic 			esub++;
61055845Sbostic 			assert(OP(m->g->strip[esub]) == OOR2);
61155845Sbostic 			ssub = esub + 1;
61255845Sbostic 			esub += OPND(m->g->strip[esub]);
61355845Sbostic 			if (OP(m->g->strip[esub]) == OOR2)
61455845Sbostic 				esub--;
61555845Sbostic 			else
61655845Sbostic 				assert(OP(m->g->strip[esub]) == O_CH);
61755845Sbostic 		}
61855845Sbostic 		break;
61955845Sbostic 	case OLPAREN:		/* must undo assignment if rest fails */
62055845Sbostic 		i = OPND(s);
62155845Sbostic 		offsave = m->pmatch[i].rm_so;
62255845Sbostic 		m->pmatch[i].rm_so = sp - m->offp;
62355845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
62455845Sbostic 		if (dp != NULL)
62555845Sbostic 			return(dp);
62655845Sbostic 		m->pmatch[i].rm_so = offsave;
62755845Sbostic 		return(NULL);
62855845Sbostic 		break;
62955845Sbostic 	case ORPAREN:		/* must undo assignment if rest fails */
63055845Sbostic 		i = OPND(s);
63155845Sbostic 		offsave = m->pmatch[i].rm_eo;
63255845Sbostic 		m->pmatch[i].rm_eo = sp - m->offp;
63355845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
63455845Sbostic 		if (dp != NULL)
63555845Sbostic 			return(dp);
63655845Sbostic 		m->pmatch[i].rm_eo = offsave;
63755845Sbostic 		return(NULL);
63855845Sbostic 		break;
63955845Sbostic 	default:		/* uh oh */
64060201Sbostic 		assert(nope);
64155845Sbostic 		break;
64255845Sbostic 	}
64355845Sbostic 
64455845Sbostic 	/* "can't happen" */
64560201Sbostic 	assert(nope);
64655845Sbostic 	/* NOTREACHED */
64755845Sbostic }
64855845Sbostic 
64955845Sbostic /*
65055845Sbostic  - fast - step through the string at top speed
65160201Sbostic  == static char *fast(register struct match *m, char *start, \
65260201Sbostic  ==	char *stop, sopno startst, sopno stopst);
65355845Sbostic  */
65460201Sbostic static char *			/* where tentative match ended, or NULL */
65555845Sbostic fast(m, start, stop, startst, stopst)
65655845Sbostic register struct match *m;
65760201Sbostic char *start;
65860201Sbostic char *stop;
65955845Sbostic sopno startst;
66055845Sbostic sopno stopst;
66155845Sbostic {
66255845Sbostic 	register states st = m->st;
66355845Sbostic 	register states fresh = m->fresh;
66455845Sbostic 	register states tmp = m->tmp;
66560201Sbostic 	register char *p = start;
66660201Sbostic 	register int c = (start == m->beginp) ? OUT : *(start-1);
66760201Sbostic 	register int lastc;	/* previous c */
66860201Sbostic 	register int flagch;
66960201Sbostic 	register int i;
67060201Sbostic 	register char *coldp;	/* last p after which no match was underway */
67155845Sbostic 
67255845Sbostic 	CLEAR(st);
67355845Sbostic 	SET1(st, startst);
67460201Sbostic 	st = step(m->g, startst, stopst, st, NOTHING, st);
67555845Sbostic 	ASSIGN(fresh, st);
67655845Sbostic 	SP("start", st, *p);
67755845Sbostic 	coldp = NULL;
67855845Sbostic 	for (;;) {
67955845Sbostic 		/* next character */
68055845Sbostic 		lastc = c;
68160201Sbostic 		c = (p == m->endp) ? OUT : *p;
68255845Sbostic 		if (EQ(st, fresh))
68355845Sbostic 			coldp = p;
68455845Sbostic 
68555845Sbostic 		/* is there an EOL and/or BOL between lastc and c? */
68660201Sbostic 		flagch = '\0';
68760201Sbostic 		i = 0;
68860201Sbostic 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
68960201Sbostic 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
69060201Sbostic 			flagch = BOL;
69160201Sbostic 			i = m->g->nbol;
69255845Sbostic 		}
69360201Sbostic 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
69460201Sbostic 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
69560201Sbostic 			flagch = (flagch == BOL) ? BOLEOL : EOL;
69660201Sbostic 			i += m->g->neol;
69760201Sbostic 		}
69860201Sbostic 		if (i != 0) {
69960201Sbostic 			for (; i > 0; i--)
70060201Sbostic 				st = step(m->g, startst, stopst, st, flagch, st);
70160201Sbostic 			SP("boleol", st, c);
70260201Sbostic 		}
70355845Sbostic 
70460201Sbostic 		/* how about a word boundary? */
705*65332Sbostic 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
706*65332Sbostic 					(c != OUT && ISWORD(c)) ) {
70760201Sbostic 			flagch = BOW;
70860201Sbostic 		}
709*65332Sbostic 		if ( (lastc != OUT && ISWORD(lastc)) &&
710*65332Sbostic 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
71160201Sbostic 			flagch = EOW;
71260201Sbostic 		}
71360201Sbostic 		if (flagch == BOW || flagch == EOW) {
71460201Sbostic 			st = step(m->g, startst, stopst, st, flagch, st);
71560201Sbostic 			SP("boweow", st, c);
71660201Sbostic 		}
71760201Sbostic 
71855845Sbostic 		/* are we done? */
71955845Sbostic 		if (ISSET(st, stopst) || p == stop)
72055845Sbostic 			break;		/* NOTE BREAK OUT */
72155845Sbostic 
72255845Sbostic 		/* no, we must deal with this character */
72355845Sbostic 		ASSIGN(tmp, st);
72455845Sbostic 		ASSIGN(st, fresh);
72560201Sbostic 		assert(c != OUT);
72655845Sbostic 		st = step(m->g, startst, stopst, tmp, c, st);
72755845Sbostic 		SP("aft", st, c);
72860201Sbostic 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
72955845Sbostic 		p++;
73055845Sbostic 	}
73155845Sbostic 
73255845Sbostic 	assert(coldp != NULL);
73355845Sbostic 	m->coldp = coldp;
73455845Sbostic 	if (ISSET(st, stopst))
73555845Sbostic 		return(p+1);
73655845Sbostic 	else
73755845Sbostic 		return(NULL);
73855845Sbostic }
73955845Sbostic 
74055845Sbostic /*
74155845Sbostic  - slow - step through the string more deliberately
74260201Sbostic  == static char *slow(register struct match *m, char *start, \
74360201Sbostic  ==	char *stop, sopno startst, sopno stopst);
74455845Sbostic  */
74560201Sbostic static char *			/* where it ended */
74655845Sbostic slow(m, start, stop, startst, stopst)
74755845Sbostic register struct match *m;
74860201Sbostic char *start;
74960201Sbostic char *stop;
75055845Sbostic sopno startst;
75155845Sbostic sopno stopst;
75255845Sbostic {
75355845Sbostic 	register states st = m->st;
75455845Sbostic 	register states empty = m->empty;
75555845Sbostic 	register states tmp = m->tmp;
75660201Sbostic 	register char *p = start;
75760201Sbostic 	register int c = (start == m->beginp) ? OUT : *(start-1);
75860201Sbostic 	register int lastc;	/* previous c */
75960201Sbostic 	register int flagch;
76060201Sbostic 	register int i;
76160201Sbostic 	register char *matchp;	/* last p at which a match ended */
76255845Sbostic 
76356355Sbostic 	AT("slow", start, stop, startst, stopst);
76455845Sbostic 	CLEAR(st);
76555845Sbostic 	SET1(st, startst);
76655845Sbostic 	SP("sstart", st, *p);
76760201Sbostic 	st = step(m->g, startst, stopst, st, NOTHING, st);
76855845Sbostic 	matchp = NULL;
76955845Sbostic 	for (;;) {
77055845Sbostic 		/* next character */
77155845Sbostic 		lastc = c;
77260201Sbostic 		c = (p == m->endp) ? OUT : *p;
77355845Sbostic 
77455845Sbostic 		/* is there an EOL and/or BOL between lastc and c? */
77560201Sbostic 		flagch = '\0';
77660201Sbostic 		i = 0;
77760201Sbostic 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
77860201Sbostic 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
77960201Sbostic 			flagch = BOL;
78060201Sbostic 			i = m->g->nbol;
78160201Sbostic 		}
78260201Sbostic 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
78360201Sbostic 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
78460201Sbostic 			flagch = (flagch == BOL) ? BOLEOL : EOL;
78560201Sbostic 			i += m->g->neol;
78660201Sbostic 		}
78760201Sbostic 		if (i != 0) {
78860201Sbostic 			for (; i > 0; i--)
78960201Sbostic 				st = step(m->g, startst, stopst, st, flagch, st);
79060201Sbostic 			SP("sboleol", st, c);
79160201Sbostic 		}
79255845Sbostic 
79360201Sbostic 		/* how about a word boundary? */
794*65332Sbostic 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
795*65332Sbostic 					(c != OUT && ISWORD(c)) ) {
79660201Sbostic 			flagch = BOW;
79755845Sbostic 		}
798*65332Sbostic 		if ( (lastc != OUT && ISWORD(lastc)) &&
799*65332Sbostic 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
80060201Sbostic 			flagch = EOW;
80160201Sbostic 		}
80260201Sbostic 		if (flagch == BOW || flagch == EOW) {
80360201Sbostic 			st = step(m->g, startst, stopst, st, flagch, st);
80460201Sbostic 			SP("sboweow", st, c);
80560201Sbostic 		}
80655845Sbostic 
80755845Sbostic 		/* are we done? */
80855845Sbostic 		if (ISSET(st, stopst))
80955845Sbostic 			matchp = p;
81055845Sbostic 		if (EQ(st, empty) || p == stop)
81155845Sbostic 			break;		/* NOTE BREAK OUT */
81255845Sbostic 
81355845Sbostic 		/* no, we must deal with this character */
81455845Sbostic 		ASSIGN(tmp, st);
81555845Sbostic 		ASSIGN(st, empty);
81660201Sbostic 		assert(c != OUT);
81755845Sbostic 		st = step(m->g, startst, stopst, tmp, c, st);
81855845Sbostic 		SP("saft", st, c);
81960201Sbostic 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
82055845Sbostic 		p++;
82155845Sbostic 	}
82255845Sbostic 
82355845Sbostic 	return(matchp);
82455845Sbostic }
82555845Sbostic 
82655845Sbostic 
82755845Sbostic /*
82855845Sbostic  - step - map set of states reachable before char to set reachable after
82960201Sbostic  == static states step(register struct re_guts *g, int start, int stop, \
83060201Sbostic  ==	register states bef, int ch, register states aft);
83160201Sbostic  == #define	BOL	(OUT+1)
83260201Sbostic  == #define	EOL	(BOL+1)
83360201Sbostic  == #define	BOLEOL	(BOL+2)
83460201Sbostic  == #define	NOTHING	(BOL+3)
83560201Sbostic  == #define	BOW	(BOL+4)
83660201Sbostic  == #define	EOW	(BOL+5)
83760201Sbostic  == #define	CODEMAX	(BOL+5)		// highest code used
83860201Sbostic  == #define	NONCHAR(c)	((c) > CHAR_MAX)
83960201Sbostic  == #define	NNONCHAR	(CODEMAX-CHAR_MAX)
84055845Sbostic  */
84155845Sbostic static states
84255845Sbostic step(g, start, stop, bef, ch, aft)
84355845Sbostic register struct re_guts *g;
84455845Sbostic int start;			/* start state within strip */
84555845Sbostic int stop;			/* state after stop state within strip */
84655845Sbostic register states bef;		/* states reachable before */
84760201Sbostic int ch;				/* character or NONCHAR code */
84855845Sbostic register states aft;		/* states already known reachable after */
84955845Sbostic {
85055845Sbostic 	register cset *cs;
85155845Sbostic 	register sop s;
85255845Sbostic 	register sopno pc;
85355845Sbostic 	register onestate here;		/* note, macros know this name */
85455845Sbostic 	register sopno look;
85555845Sbostic 	register int i;
85655845Sbostic 
85755845Sbostic 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
85855845Sbostic 		s = g->strip[pc];
85955845Sbostic 		switch (OP(s)) {
86055845Sbostic 		case OEND:
86155845Sbostic 			assert(pc == stop-1);
86255845Sbostic 			break;
86355845Sbostic 		case OCHAR:
86460201Sbostic 			/* only characters can match */
86560201Sbostic 			assert(!NONCHAR(ch) || ch != (char)OPND(s));
86660201Sbostic 			if (ch == (char)OPND(s))
86755845Sbostic 				FWD(aft, bef, 1);
86855845Sbostic 			break;
86960201Sbostic 		case OBOL:
87060201Sbostic 			if (ch == BOL || ch == BOLEOL)
87160201Sbostic 				FWD(aft, bef, 1);
87260201Sbostic 			break;
87355845Sbostic 		case OEOL:
87460201Sbostic 			if (ch == EOL || ch == BOLEOL)
87560201Sbostic 				FWD(aft, bef, 1);
87655845Sbostic 			break;
87760201Sbostic 		case OBOW:
87860201Sbostic 			if (ch == BOW)
87960201Sbostic 				FWD(aft, bef, 1);
88060201Sbostic 			break;
88160201Sbostic 		case OEOW:
88260201Sbostic 			if (ch == EOW)
88360201Sbostic 				FWD(aft, bef, 1);
88460201Sbostic 			break;
88555845Sbostic 		case OANY:
88660201Sbostic 			if (!NONCHAR(ch))
88760201Sbostic 				FWD(aft, bef, 1);
88855845Sbostic 			break;
88955845Sbostic 		case OANYOF:
89055845Sbostic 			cs = &g->sets[OPND(s)];
89160201Sbostic 			if (!NONCHAR(ch) && CHIN(cs, ch))
89255845Sbostic 				FWD(aft, bef, 1);
89355845Sbostic 			break;
89455845Sbostic 		case OBACK_:		/* ignored here */
89555845Sbostic 		case O_BACK:
89655845Sbostic 			FWD(aft, aft, 1);
89755845Sbostic 			break;
89855845Sbostic 		case OPLUS_:		/* forward, this is just an empty */
89955845Sbostic 			FWD(aft, aft, 1);
90055845Sbostic 			break;
90155845Sbostic 		case O_PLUS:		/* both forward and back */
90255845Sbostic 			FWD(aft, aft, 1);
90355845Sbostic 			i = ISSETBACK(aft, OPND(s));
90455845Sbostic 			BACK(aft, aft, OPND(s));
90555845Sbostic 			if (!i && ISSETBACK(aft, OPND(s))) {
90655845Sbostic 				/* oho, must reconsider loop body */
90755845Sbostic 				pc -= OPND(s) + 1;
90855845Sbostic 				INIT(here, pc);
90955845Sbostic 			}
91055845Sbostic 			break;
91155845Sbostic 		case OQUEST_:		/* two branches, both forward */
91255845Sbostic 			FWD(aft, aft, 1);
91355845Sbostic 			FWD(aft, aft, OPND(s));
91455845Sbostic 			break;
91555845Sbostic 		case O_QUEST:		/* just an empty */
91655845Sbostic 			FWD(aft, aft, 1);
91755845Sbostic 			break;
91855845Sbostic 		case OLPAREN:		/* not significant here */
91955845Sbostic 		case ORPAREN:
92055845Sbostic 			FWD(aft, aft, 1);
92155845Sbostic 			break;
92255845Sbostic 		case OCH_:		/* mark the first two branches */
92355845Sbostic 			FWD(aft, aft, 1);
92455845Sbostic 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
92555845Sbostic 			FWD(aft, aft, OPND(s));
92655845Sbostic 			break;
92755845Sbostic 		case OOR1:		/* done a branch, find the O_CH */
92855845Sbostic 			if (ISSTATEIN(aft, here)) {
92955845Sbostic 				for (look = 1;
93055845Sbostic 						OP(s = g->strip[pc+look]) != O_CH;
93155845Sbostic 						look += OPND(s))
93255845Sbostic 					assert(OP(s) == OOR2);
93355845Sbostic 				FWD(aft, aft, look);
93455845Sbostic 			}
93555845Sbostic 			break;
93655845Sbostic 		case OOR2:		/* propagate OCH_'s marking */
93755845Sbostic 			FWD(aft, aft, 1);
93855845Sbostic 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
93955845Sbostic 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
94055845Sbostic 				FWD(aft, aft, OPND(s));
94155845Sbostic 			}
94255845Sbostic 			break;
94355845Sbostic 		case O_CH:		/* just empty */
94455845Sbostic 			FWD(aft, aft, 1);
94555845Sbostic 			break;
94655845Sbostic 		default:		/* ooooops... */
94760201Sbostic 			assert(nope);
94855845Sbostic 			break;
94955845Sbostic 		}
95055845Sbostic 	}
95155845Sbostic 
95255845Sbostic 	return(aft);
95355845Sbostic }
95455845Sbostic 
95556355Sbostic #ifdef REDEBUG
95655845Sbostic /*
95755845Sbostic  - print - print a set of states
95860201Sbostic  == #ifdef REDEBUG
95960201Sbostic  == static void print(struct match *m, char *caption, states st, \
96060201Sbostic  ==	int ch, FILE *d);
96160201Sbostic  == #endif
96255845Sbostic  */
96355845Sbostic static void
96456355Sbostic print(m, caption, st, ch, d)
96556355Sbostic struct match *m;
96655845Sbostic char *caption;
96755845Sbostic states st;
96860201Sbostic int ch;
96955845Sbostic FILE *d;
97055845Sbostic {
97156355Sbostic 	register struct re_guts *g = m->g;
97255845Sbostic 	register int i;
97355845Sbostic 	register int first = 1;
97455845Sbostic 
97556355Sbostic 	if (!(m->eflags&REG_TRACE))
97656355Sbostic 		return;
97756355Sbostic 
97855845Sbostic 	fprintf(d, "%s", caption);
97955845Sbostic 	if (ch != '\0')
98056355Sbostic 		fprintf(d, " %s", pchar(ch));
98155845Sbostic 	for (i = 0; i < g->nstates; i++)
98255845Sbostic 		if (ISSET(st, i)) {
98355845Sbostic 			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
98455845Sbostic 			first = 0;
98555845Sbostic 		}
98655845Sbostic 	fprintf(d, "\n");
98755845Sbostic }
98856355Sbostic 
98956355Sbostic /*
99056355Sbostic  - at - print current situation
99160201Sbostic  == #ifdef REDEBUG
99260201Sbostic  == static void at(struct match *m, char *title, char *start, char *stop, \
99360201Sbostic  ==						sopno startst, stopno stopst);
99460201Sbostic  == #endif
99556355Sbostic  */
99656355Sbostic static void
99756355Sbostic at(m, title, start, stop, startst, stopst)
99856355Sbostic struct match *m;
99956355Sbostic char *title;
100060201Sbostic char *start;
100160201Sbostic char *stop;
100256355Sbostic sopno startst;
100356355Sbostic sopno stopst;
100456355Sbostic {
100556355Sbostic 	if (!(m->eflags&REG_TRACE))
100656355Sbostic 		return;
100756355Sbostic 
100856355Sbostic 	printf("%s %s-", title, pchar(*start));
100956355Sbostic 	printf("%s ", pchar(*stop));
101056355Sbostic 	printf("%ld-%ld\n", (long)startst, (long)stopst);
101156355Sbostic }
101256355Sbostic 
101356355Sbostic #ifndef PCHARDONE
101456355Sbostic #define	PCHARDONE	/* never again */
101556355Sbostic /*
101656355Sbostic  - pchar - make a character printable
101760201Sbostic  == #ifdef REDEBUG
101860201Sbostic  == static char *pchar(int ch);
101960201Sbostic  == #endif
102056355Sbostic  *
102156355Sbostic  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
102256355Sbostic  * duplicate here avoids having a debugging-capable regexec.o tied to
102356355Sbostic  * a matching debug.o, and this is convenient.  It all disappears in
102456355Sbostic  * the non-debug compilation anyway, so it doesn't matter much.
102556355Sbostic  */
102656355Sbostic static char *			/* -> representation */
102756355Sbostic pchar(ch)
102856355Sbostic int ch;
102956355Sbostic {
103056355Sbostic 	static char pbuf[10];
103156355Sbostic 
103256355Sbostic 	if (isprint(ch) || ch == ' ')
103356355Sbostic 		sprintf(pbuf, "%c", ch);
103456355Sbostic 	else
103556355Sbostic 		sprintf(pbuf, "\\%o", ch);
103656355Sbostic 	return(pbuf);
103756355Sbostic }
103855845Sbostic #endif
103956355Sbostic #endif
104055845Sbostic 
104155845Sbostic #undef	matcher
104255845Sbostic #undef	fast
104355845Sbostic #undef	slow
104455845Sbostic #undef	dissect
104555845Sbostic #undef	backref
104655845Sbostic #undef	step
104755845Sbostic #undef	print
104856355Sbostic #undef	at
104955845Sbostic #undef	match
1050