xref: /csrg-svn/lib/libc/regex/engine.c (revision 56355)
155845Sbostic /*-
255845Sbostic  * Copyright (c) 1992 Henry Spencer.
355845Sbostic  * Copyright (c) 1992 The Regents of the University of California.
455845Sbostic  * 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*56355Sbostic  *	@(#)engine.c	5.3 (Berkeley) 09/30/92
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	expand	sexpand
2855845Sbostic #define	step	sstep
2955845Sbostic #define	print	sprint
30*56355Sbostic #define	at	sat
3155845Sbostic #define	match	smat
3255845Sbostic #endif
3355845Sbostic #ifdef LNAMES
3455845Sbostic #define	matcher	lmatcher
3555845Sbostic #define	fast	lfast
3655845Sbostic #define	slow	lslow
3755845Sbostic #define	dissect	ldissect
3855845Sbostic #define	backref	lbackref
3955845Sbostic #define	expand	lexpand
4055845Sbostic #define	step	lstep
4155845Sbostic #define	print	lprint
42*56355Sbostic #define	at	lat
4355845Sbostic #define	match	lmat
4455845Sbostic #endif
4555845Sbostic 
4655845Sbostic /* another structure passed up and down to avoid zillions of parameters */
4755845Sbostic struct match {
4855845Sbostic 	struct re_guts *g;
4955845Sbostic 	int eflags;
5055845Sbostic 	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
5155845Sbostic 	uchar *offp;		/* offsets work from here */
5255845Sbostic 	uchar *beginp;		/* start of string -- virtual NUL precedes */
5355845Sbostic 	uchar *endp;		/* end of string -- virtual NUL here */
5455845Sbostic 	uchar *coldp;		/* can be no match starting before here */
5555845Sbostic 	uchar **lastpos;	/* [nplus+1] */
5655845Sbostic 	STATEVARS;
5755845Sbostic 	states st;		/* current states */
5855845Sbostic 	states fresh;		/* states for a fresh start */
5955845Sbostic 	states tmp;		/* temporary */
6055845Sbostic 	states empty;		/* empty set of states */
6155845Sbostic };
6255845Sbostic 
63*56355Sbostic #include "engine.ih"
64*56355Sbostic 
65*56355Sbostic #ifdef REDEBUG
66*56355Sbostic #define	SP(t, s, c)	print(m, t, s, c, stdout)
67*56355Sbostic #define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
68*56355Sbostic #define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
6955845Sbostic #else
7055845Sbostic #define	SP(t, s, c)	/* nothing */
71*56355Sbostic #define	AT(t, p1, p2, s1, s2)	/* nothing */
72*56355Sbostic #define	NOTE(s)	/* nothing */
7355845Sbostic #endif
7455845Sbostic 
7555845Sbostic /*
7655845Sbostic  - matcher - the actual matching engine
77*56355Sbostic  == static int matcher(register struct re_guts *g, uchar *string, \
78*56355Sbostic  ==	size_t nmatch, regmatch_t pmatch[], int eflags);
7955845Sbostic  */
8055845Sbostic static int			/* 0 success, REG_NOMATCH failure */
8155845Sbostic matcher(g, string, nmatch, pmatch, eflags)
8255845Sbostic register struct re_guts *g;
8355845Sbostic uchar *string;
8455845Sbostic size_t nmatch;
8555845Sbostic regmatch_t pmatch[];
8655845Sbostic int eflags;
8755845Sbostic {
8855845Sbostic 	register uchar *endp;
8955845Sbostic 	register int i;
9055845Sbostic 	struct match mv;
9155845Sbostic 	register struct match *m = &mv;
9255845Sbostic 	register uchar *dp;
9355845Sbostic 	const register sopno gf = g->firststate+1;	/* +1 for OEND */
9455845Sbostic 	const register sopno gl = g->laststate;
9555845Sbostic 	uchar *start;
9655845Sbostic 	uchar *stop;
9755845Sbostic 
98*56355Sbostic 	/* simplify the situation where possible */
9955845Sbostic 	if (g->cflags&REG_NOSUB)
100*56355Sbostic 		nmatch = 0;
10155845Sbostic 	if (eflags&REG_STARTEND) {
10255845Sbostic 		start = string + pmatch[0].rm_so;
10355845Sbostic 		stop = string + pmatch[0].rm_eo;
10455845Sbostic 	} else {
10555845Sbostic 		start = string;
10655845Sbostic 		stop = start + strlen((char *)start);
10755845Sbostic 	}
10855845Sbostic 
10955882Sbostic 	/* prescreening; this does wonders for this rather slow code */
11055882Sbostic 	if (g->must != NULL) {
11155882Sbostic 		for (dp = start; dp < stop; dp++)
11255882Sbostic 			if (*dp == (uchar)g->must[0] && stop - dp >= g->mlen &&
11355882Sbostic 			strncmp((char *)dp, g->must, (size_t)g->mlen) == 0)
11455882Sbostic 				break;
11555882Sbostic 		if (dp == stop)		/* we didn't find g->must */
11655882Sbostic 			return(REG_NOMATCH);
11755882Sbostic 	}
11855882Sbostic 
11955845Sbostic 	/* match struct setup */
12055845Sbostic 	m->g = g;
12155845Sbostic 	m->eflags = eflags;
12255845Sbostic 	m->pmatch = NULL;
12355845Sbostic 	m->lastpos = NULL;
12455845Sbostic 	m->offp = string;
12555845Sbostic 	m->beginp = start;
12655845Sbostic 	m->endp = stop;
12755845Sbostic 	STATESETUP(m, 4);
12855845Sbostic 	SETUP(m->st);
12955845Sbostic 	SETUP(m->fresh);
13055845Sbostic 	SETUP(m->tmp);
13155845Sbostic 	SETUP(m->empty);
13255845Sbostic 	CLEAR(m->empty);
13355845Sbostic 
13455845Sbostic 	/* this loop does only one repetition except for backrefs */
13555845Sbostic 	for (;;) {
13655845Sbostic 		endp = fast(m, start, stop, gf, gl);
13755845Sbostic 		if (endp == NULL) {		/* a miss */
13855845Sbostic 			STATETEARDOWN(m);
13955845Sbostic 			return(REG_NOMATCH);
14055845Sbostic 		}
14155845Sbostic 		if (nmatch == 0 && !g->backrefs)
14255845Sbostic 			break;		/* no further info needed */
14355845Sbostic 
14455845Sbostic 		/* where? */
14555845Sbostic 		assert(m->coldp != NULL);
14655845Sbostic 		for (;;) {
147*56355Sbostic 			NOTE("finding start");
14855845Sbostic 			endp = slow(m, m->coldp, stop, gf, gl);
14955845Sbostic 			if (endp != NULL)
15055845Sbostic 				break;
151*56355Sbostic 			assert(m->coldp < m->endp);
15255845Sbostic 			m->coldp++;
15355845Sbostic 		}
15455845Sbostic 		if (nmatch == 1 && !g->backrefs)
15555845Sbostic 			break;		/* no further info needed */
15655845Sbostic 
15755845Sbostic 		/* oh my, he wants the subexpressions... */
15855845Sbostic 		if (m->pmatch == NULL)
15955845Sbostic 			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
16055845Sbostic 							sizeof(regmatch_t));
16155845Sbostic 		if (m->pmatch == NULL) {
16255845Sbostic 			STATETEARDOWN(m);
16355845Sbostic 			return(REG_ESPACE);
16455845Sbostic 		}
165*56355Sbostic 		for (i = 1; i <= m->g->nsub; i++)
166*56355Sbostic 			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
167*56355Sbostic 		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
168*56355Sbostic 			NOTE("dissecting");
16955845Sbostic 			dp = dissect(m, m->coldp, endp, gf, gl);
170*56355Sbostic 		} else {
17155845Sbostic 			if (g->nplus > 0 && m->lastpos == NULL)
17255845Sbostic 				m->lastpos = (uchar **)malloc((g->nplus+1) *
17355845Sbostic 							sizeof(uchar *));
17455845Sbostic 			if (g->nplus > 0 && m->lastpos == NULL) {
17555845Sbostic 				free(m->pmatch);
17655845Sbostic 				STATETEARDOWN(m);
17755845Sbostic 				return(REG_ESPACE);
17855845Sbostic 			}
179*56355Sbostic 			NOTE("backref dissect");
18055845Sbostic 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
18155845Sbostic 		}
18255845Sbostic 		if (dp != NULL)
18355845Sbostic 			break;
18455845Sbostic 
18555845Sbostic 		/* uh-oh... we couldn't find a subexpression-level match */
18655845Sbostic 		assert(g->backrefs);	/* must be back references doing it */
18755845Sbostic 		assert(g->nplus == 0 || m->lastpos != NULL);
188*56355Sbostic 		for (;;) {
189*56355Sbostic 			if (dp != NULL || endp <= m->coldp)
190*56355Sbostic 				break;		/* defeat */
191*56355Sbostic 			NOTE("backoff");
192*56355Sbostic 			endp = slow(m, m->coldp, endp-1, gf, gl);
193*56355Sbostic 			if (endp == NULL)
194*56355Sbostic 				break;		/* defeat */
19555845Sbostic 			/* try it on a shorter possibility */
196*56355Sbostic #ifndef NDEBUG
19755845Sbostic 			for (i = 1; i <= m->g->nsub; i++) {
198*56355Sbostic 				assert(m->pmatch[i].rm_so == -1);
199*56355Sbostic 				assert(m->pmatch[i].rm_eo == -1);
20055845Sbostic 			}
201*56355Sbostic #endif
202*56355Sbostic 			NOTE("backoff dissect");
20355845Sbostic 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
20455845Sbostic 		}
20555845Sbostic 		assert(dp == NULL || dp == endp);
20655845Sbostic 		if (dp != NULL)		/* found a shorter one */
20755845Sbostic 			break;
20855845Sbostic 
20955845Sbostic 		/* despite initial appearances, there is no match here */
210*56355Sbostic 		NOTE("false alarm");
21155845Sbostic 		start = m->coldp + 1;	/* recycle starting later */
21255845Sbostic 		assert(start <= stop);
21355845Sbostic 	}
21455845Sbostic 
21555845Sbostic 	/* fill in the details if requested */
21655845Sbostic 	if (nmatch > 0) {
21755845Sbostic 		pmatch[0].rm_so = m->coldp - m->offp;
21855845Sbostic 		pmatch[0].rm_eo = endp - m->offp;
21955845Sbostic 	}
22055845Sbostic 	if (nmatch > 1) {
22155845Sbostic 		assert(m->pmatch != NULL);
22255845Sbostic 		for (i = 1; i < nmatch; i++)
22355845Sbostic 			if (i <= m->g->nsub)
22455845Sbostic 				pmatch[i] = m->pmatch[i];
22555845Sbostic 			else {
22655845Sbostic 				pmatch[i].rm_so = -1;
22755845Sbostic 				pmatch[i].rm_eo = -1;
22855845Sbostic 			}
22955845Sbostic 	}
23055845Sbostic 
23155845Sbostic 	if (m->pmatch != NULL)
23255845Sbostic 		free((char *)m->pmatch);
23355845Sbostic 	if (m->lastpos != NULL)
23455845Sbostic 		free((char *)m->lastpos);
23555845Sbostic 	STATETEARDOWN(m);
23655845Sbostic 	return(0);
23755845Sbostic }
23855845Sbostic 
23955845Sbostic /*
24055845Sbostic  - dissect - figure out what matched what, no back references
241*56355Sbostic  == static uchar *dissect(register struct match *m, uchar *start, \
242*56355Sbostic  ==	uchar *stop, sopno startst, sopno stopst);
24355845Sbostic  */
24455845Sbostic static uchar *			/* == stop (success) always */
24555845Sbostic dissect(m, start, stop, startst, stopst)
24655845Sbostic register struct match *m;
24755845Sbostic uchar *start;
24855845Sbostic uchar *stop;
24955845Sbostic sopno startst;
25055845Sbostic sopno stopst;
25155845Sbostic {
25255845Sbostic 	register int i;
25355845Sbostic 	register sopno ss;	/* start sop of current subRE */
25455845Sbostic 	register sopno es;	/* end sop of current subRE */
25555845Sbostic 	register uchar *sp;	/* start of string matched by it */
25655845Sbostic 	register uchar *stp;	/* string matched by it cannot pass here */
25755845Sbostic 	register uchar *rest;	/* start of rest of string */
25855845Sbostic 	register uchar *tail;	/* string unmatched by rest of RE */
25955845Sbostic 	register sopno ssub;	/* start sop of subsubRE */
26055845Sbostic 	register sopno esub;	/* end sop of subsubRE */
26155845Sbostic 	register uchar *ssp;	/* start of string matched by subsubRE */
26255845Sbostic 	register uchar *sep;	/* end of string matched by subsubRE */
26355845Sbostic 	register uchar *oldssp;	/* previous ssp */
26455845Sbostic 	register uchar *dp;
26555845Sbostic 
266*56355Sbostic 	AT("diss", start, stop, startst, stopst);
26755845Sbostic 	sp = start;
26855845Sbostic 	for (ss = startst; ss < stopst; ss = es) {
26955845Sbostic 		/* identify end of subRE */
27055845Sbostic 		es = ss;
27155845Sbostic 		switch (OP(m->g->strip[es])) {
27255845Sbostic 		case OPLUS_:
27355845Sbostic 		case OQUEST_:
27455845Sbostic 			es += OPND(m->g->strip[es]);
27555845Sbostic 			break;
27655845Sbostic 		case OCH_:
27755845Sbostic 			while (OP(m->g->strip[es]) != O_CH)
27855845Sbostic 				es += OPND(m->g->strip[es]);
27955845Sbostic 			break;
28055845Sbostic 		}
28155845Sbostic 		es++;
28255845Sbostic 
28355845Sbostic 		/* figure out what it matched */
28455845Sbostic 		switch (OP(m->g->strip[ss])) {
28555845Sbostic 		case OEND:
28655845Sbostic 			assert(0);
28755845Sbostic 			break;
28855845Sbostic 		case OCHAR:
28955845Sbostic 			sp++;
29055845Sbostic 			break;
29155845Sbostic 		case OBOL:
29255845Sbostic 		case OEOL:
29355845Sbostic 			break;
29455845Sbostic 		case OANY:
29555845Sbostic 		case OANYOF:
29655845Sbostic 			sp++;
29755845Sbostic 			break;
29855845Sbostic 		case OBACK_:
29955845Sbostic 		case O_BACK:
30055845Sbostic 			assert(0);
30155845Sbostic 			break;
30255845Sbostic 		/* cases where length of match is hard to find */
30355845Sbostic 		case OQUEST_:
30455845Sbostic 			stp = stop;
30555845Sbostic 			for (;;) {
30655845Sbostic 				/* how long could this one be? */
30755845Sbostic 				rest = slow(m, sp, stp, ss, es);
30855845Sbostic 				assert(rest != NULL);	/* it did match */
30955845Sbostic 				/* could the rest match the rest? */
31055845Sbostic 				tail = slow(m, rest, stop, es, stopst);
31155845Sbostic 				if (tail == stop)
31255845Sbostic 					break;		/* yes! */
31355845Sbostic 				/* no -- try a shorter match for this one */
31455845Sbostic 				stp = rest - 1;
31555845Sbostic 				assert(stp >= sp);	/* it did work */
31655845Sbostic 			}
31755845Sbostic 			ssub = ss + 1;
31855845Sbostic 			esub = es - 1;
31955845Sbostic 			/* did innards match? */
32055845Sbostic 			if (slow(m, sp, rest, ssub, esub) != NULL) {
32155845Sbostic 				dp = dissect(m, sp, rest, ssub, esub);
32255845Sbostic 				assert(dp == rest);
32355845Sbostic 			} else		/* no */
32455845Sbostic 				assert(sp == rest);
32555845Sbostic 			sp = rest;
32655845Sbostic 			break;
32755845Sbostic 		case OPLUS_:
32855845Sbostic 			stp = stop;
32955845Sbostic 			for (;;) {
33055845Sbostic 				/* how long could this one be? */
33155845Sbostic 				rest = slow(m, sp, stp, ss, es);
33255845Sbostic 				assert(rest != NULL);	/* it did match */
33355845Sbostic 				/* could the rest match the rest? */
33455845Sbostic 				tail = slow(m, rest, stop, es, stopst);
33555845Sbostic 				if (tail == stop)
33655845Sbostic 					break;		/* yes! */
33755845Sbostic 				/* no -- try a shorter match for this one */
33855845Sbostic 				stp = rest - 1;
33955845Sbostic 				assert(stp >= sp);	/* it did work */
34055845Sbostic 			}
34155845Sbostic 			ssub = ss + 1;
34255845Sbostic 			esub = es - 1;
34355845Sbostic 			ssp = sp;
34455845Sbostic 			oldssp = ssp;
34555845Sbostic 			for (;;) {	/* find last match of innards */
34655845Sbostic 				sep = slow(m, ssp, rest, ssub, esub);
34755845Sbostic 				if (sep == NULL || sep == ssp)
34855845Sbostic 					break;	/* failed or matched null */
34955845Sbostic 				oldssp = ssp;	/* on to next try */
35055845Sbostic 				ssp = sep;
35155845Sbostic 			}
35255845Sbostic 			if (sep == NULL) {
35355845Sbostic 				/* last successful match */
35455845Sbostic 				sep = ssp;
35555845Sbostic 				ssp = oldssp;
35655845Sbostic 			}
35755845Sbostic 			assert(sep == rest);	/* must exhaust substring */
35855845Sbostic 			assert(slow(m, ssp, sep, ssub, esub) == rest);
35955845Sbostic 			dp = dissect(m, ssp, sep, ssub, esub);
36055845Sbostic 			assert(dp == sep);
36155845Sbostic 			sp = rest;
36255845Sbostic 			break;
36355845Sbostic 		case OCH_:
36455845Sbostic 			stp = stop;
36555845Sbostic 			for (;;) {
36655845Sbostic 				/* how long could this one be? */
36755845Sbostic 				rest = slow(m, sp, stp, ss, es);
36855845Sbostic 				assert(rest != NULL);	/* it did match */
36955845Sbostic 				/* could the rest match the rest? */
37055845Sbostic 				tail = slow(m, rest, stop, es, stopst);
37155845Sbostic 				if (tail == stop)
37255845Sbostic 					break;		/* yes! */
37355845Sbostic 				/* no -- try a shorter match for this one */
37455845Sbostic 				stp = rest - 1;
37555845Sbostic 				assert(stp >= sp);	/* it did work */
37655845Sbostic 			}
37755845Sbostic 			ssub = ss + 1;
37855845Sbostic 			esub = ss + OPND(m->g->strip[ss]) - 1;
37955845Sbostic 			assert(OP(m->g->strip[esub]) == OOR1);
38055845Sbostic 			for (;;) {	/* find first matching branch */
38155845Sbostic 				if (slow(m, sp, rest, ssub, esub) == rest)
38255845Sbostic 					break;	/* it matched all of it */
38355845Sbostic 				/* that one missed, try next one */
38455845Sbostic 				assert(OP(m->g->strip[esub]) == OOR1);
38555845Sbostic 				esub++;
38655845Sbostic 				assert(OP(m->g->strip[esub]) == OOR2);
38755845Sbostic 				ssub = esub + 1;
38855845Sbostic 				esub += OPND(m->g->strip[esub]);
38955845Sbostic 				if (OP(m->g->strip[esub]) == OOR2)
39055845Sbostic 					esub--;
39155845Sbostic 				else
39255845Sbostic 					assert(OP(m->g->strip[esub]) == O_CH);
39355845Sbostic 			}
39455845Sbostic 			dp = dissect(m, sp, rest, ssub, esub);
39555845Sbostic 			assert(dp == rest);
39655845Sbostic 			sp = rest;
39755845Sbostic 			break;
39855845Sbostic 		case O_PLUS:
39955845Sbostic 		case O_QUEST:
40055845Sbostic 		case OOR1:
40155845Sbostic 		case OOR2:
40255845Sbostic 		case O_CH:
40355845Sbostic 			assert(0);
40455845Sbostic 			break;
40555845Sbostic 		case OLPAREN:
40655845Sbostic 			i = OPND(m->g->strip[ss]);
40755845Sbostic 			m->pmatch[i].rm_so = sp - m->offp;
40855845Sbostic 			break;
40955845Sbostic 		case ORPAREN:
41055845Sbostic 			i = OPND(m->g->strip[ss]);
41155845Sbostic 			m->pmatch[i].rm_eo = sp - m->offp;
41255845Sbostic 			break;
41355845Sbostic 		default:		/* uh oh */
41455845Sbostic 			assert(0);
41555845Sbostic 			break;
41655845Sbostic 		}
41755845Sbostic 	}
41855845Sbostic 
41955845Sbostic 	assert(sp == stop);
42055845Sbostic 	return(sp);
42155845Sbostic }
42255845Sbostic 
42355845Sbostic /*
42455845Sbostic  - backref - figure out what matched what, figuring in back references
425*56355Sbostic  == static uchar *backref(register struct match *m, uchar *start, \
426*56355Sbostic  ==	uchar *stop, sopno startst, sopno stopst, sopno lev);
42755845Sbostic  */
42855845Sbostic static uchar *			/* == stop (success) or NULL (failure) */
42955845Sbostic backref(m, start, stop, startst, stopst, lev)
43055845Sbostic register struct match *m;
43155845Sbostic uchar *start;
43255845Sbostic uchar *stop;
43355845Sbostic sopno startst;
43455845Sbostic sopno stopst;
43555845Sbostic sopno lev;			/* PLUS nesting level */
43655845Sbostic {
43755845Sbostic 	register int i;
43855845Sbostic 	register sopno ss;	/* start sop of current subRE */
43955845Sbostic 	register uchar *sp;	/* start of string matched by it */
44055845Sbostic 	register sopno ssub;	/* start sop of subsubRE */
44155845Sbostic 	register sopno esub;	/* end sop of subsubRE */
44255845Sbostic 	register uchar *ssp;	/* start of string matched by subsubRE */
44355845Sbostic 	register uchar *dp;
44455845Sbostic 	register size_t len;
44555845Sbostic 	register int hard;
44655845Sbostic 	register sop s;
44755845Sbostic 	register regoff_t offsave;
44855845Sbostic 	register cset *cs;
44955845Sbostic 
450*56355Sbostic 	AT("back", start, stop, startst, stopst);
45155845Sbostic 	sp = start;
45255845Sbostic 
45355845Sbostic 	/* get as far as we can with easy stuff */
45455845Sbostic 	hard = 0;
45555845Sbostic 	for (ss = startst; !hard && ss < stopst; ss++)
45655845Sbostic 		switch (OP(s = m->g->strip[ss])) {
45755845Sbostic 		case OCHAR:
45855845Sbostic 			if (sp == stop || *sp++ != OPND(s))
45955845Sbostic 				return(NULL);
46055845Sbostic 			break;
46155845Sbostic 		case OANY:
46255845Sbostic 			if (sp == stop)
46355845Sbostic 				return(NULL);
46455845Sbostic 			sp++;
46555845Sbostic 			break;
46655845Sbostic 		case OANYOF:
46755845Sbostic 			cs = &m->g->sets[OPND(s)];
46855845Sbostic 			if (sp == stop || !CHIN(cs, *sp++))
46955845Sbostic 				return(NULL);
47055845Sbostic 			break;
47155845Sbostic 		case OBOL:
47255845Sbostic 			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
47355845Sbostic 					(sp < m->endp && *(sp-1) == '\n' &&
47455845Sbostic 						(m->g->cflags&REG_NEWLINE)) )
47555845Sbostic 				{ /* yes */ }
47655845Sbostic 			else
47755845Sbostic 				return(NULL);
47855845Sbostic 			break;
47955845Sbostic 		case OEOL:
48055845Sbostic 			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
48155845Sbostic 					(sp < m->endp && *sp == '\n' &&
48255845Sbostic 						(m->g->cflags&REG_NEWLINE)) )
48355845Sbostic 				{ /* yes */ }
48455845Sbostic 			else
48555845Sbostic 				return(NULL);
48655845Sbostic 			break;
48755845Sbostic 		case O_QUEST:
48855845Sbostic 			break;
48955845Sbostic 		case OOR1:	/* matches null but needs to skip */
49055845Sbostic 			ss++;
49155845Sbostic 			s = m->g->strip[ss];
49255845Sbostic 			do {
49355845Sbostic 				assert(OP(s) == OOR2);
49455845Sbostic 				ss += OPND(s);
49555845Sbostic 			} while (OP(s = m->g->strip[ss]) != O_CH);
49655845Sbostic 			/* note that the ss++ gets us past the O_CH */
49755845Sbostic 			break;
49855845Sbostic 		default:	/* have to make a choice */
49955845Sbostic 			hard = 1;
50055845Sbostic 			break;
50155845Sbostic 		}
50255845Sbostic 	if (!hard) {		/* that was it! */
50355845Sbostic 		if (sp != stop)
50455845Sbostic 			return(NULL);
50555845Sbostic 		return(sp);
50655845Sbostic 	}
50755845Sbostic 	ss--;			/* adjust for the for's final increment */
50855845Sbostic 
50955845Sbostic 	/* the hard stuff */
510*56355Sbostic 	AT("hard", sp, stop, ss, stopst);
51155845Sbostic 	s = m->g->strip[ss];
51255845Sbostic 	switch (OP(s)) {
51355845Sbostic 	case OBACK_:		/* the vilest depths */
51455845Sbostic 		i = OPND(s);
51555845Sbostic 		if (m->pmatch[i].rm_eo == -1)
51655845Sbostic 			return(NULL);
51755845Sbostic 		assert(m->pmatch[i].rm_so != -1);
51855845Sbostic 		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
51955845Sbostic 		assert(stop - m->beginp >= len);
52055845Sbostic 		if (sp > stop - len)
52155845Sbostic 			return(NULL);	/* not enough left to match */
52255845Sbostic 		ssp = m->offp + m->pmatch[i].rm_so;
52355845Sbostic 		if (strncmp((char *)sp, (char *)ssp, len) != 0)
52455845Sbostic 			return(NULL);
52555845Sbostic 		while (m->g->strip[ss] != SOP(O_BACK, i))
52655845Sbostic 			ss++;
52755845Sbostic 		return(backref(m, sp+len, stop, ss+1, stopst, lev));
52855845Sbostic 		break;
52955845Sbostic 	case OQUEST_:		/* to null or not */
53055845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
53155845Sbostic 		if (dp != NULL)
53255845Sbostic 			return(dp);	/* not */
53355845Sbostic 		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
53455845Sbostic 		break;
53555845Sbostic 	case OPLUS_:
53655845Sbostic 		assert(m->lastpos != NULL);
53755845Sbostic 		assert(lev+1 <= m->g->nplus);
53855845Sbostic 		m->lastpos[lev+1] = sp;
53955845Sbostic 		return(backref(m, sp, stop, ss+1, stopst, lev+1));
54055845Sbostic 		break;
54155845Sbostic 	case O_PLUS:
54255845Sbostic 		if (sp == m->lastpos[lev])	/* last pass matched null */
54355845Sbostic 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
54455845Sbostic 		/* try another pass */
54555845Sbostic 		m->lastpos[lev] = sp;
54655845Sbostic 		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
54755845Sbostic 		if (dp == NULL)
54855845Sbostic 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
54955845Sbostic 		else
55055845Sbostic 			return(dp);
55155845Sbostic 		break;
55255845Sbostic 	case OCH_:		/* find the right one, if any */
55355845Sbostic 		ssub = ss + 1;
55455845Sbostic 		esub = ss + OPND(s) - 1;
55555845Sbostic 		assert(OP(m->g->strip[esub]) == OOR1);
55655845Sbostic 		for (;;) {	/* find first matching branch */
55755845Sbostic 			dp = backref(m, sp, stop, ssub, esub, lev);
55855845Sbostic 			if (dp != NULL)
55955845Sbostic 				return(dp);
56055845Sbostic 			/* that one missed, try next one */
56155845Sbostic 			if (OP(m->g->strip[esub]) == O_CH)
56255845Sbostic 				return(NULL);	/* there is none */
56355845Sbostic 			esub++;
56455845Sbostic 			assert(OP(m->g->strip[esub]) == OOR2);
56555845Sbostic 			ssub = esub + 1;
56655845Sbostic 			esub += OPND(m->g->strip[esub]);
56755845Sbostic 			if (OP(m->g->strip[esub]) == OOR2)
56855845Sbostic 				esub--;
56955845Sbostic 			else
57055845Sbostic 				assert(OP(m->g->strip[esub]) == O_CH);
57155845Sbostic 		}
57255845Sbostic 		break;
57355845Sbostic 	case OLPAREN:		/* must undo assignment if rest fails */
57455845Sbostic 		i = OPND(s);
57555845Sbostic 		offsave = m->pmatch[i].rm_so;
57655845Sbostic 		m->pmatch[i].rm_so = sp - m->offp;
57755845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
57855845Sbostic 		if (dp != NULL)
57955845Sbostic 			return(dp);
58055845Sbostic 		m->pmatch[i].rm_so = offsave;
58155845Sbostic 		return(NULL);
58255845Sbostic 		break;
58355845Sbostic 	case ORPAREN:		/* must undo assignment if rest fails */
58455845Sbostic 		i = OPND(s);
58555845Sbostic 		offsave = m->pmatch[i].rm_eo;
58655845Sbostic 		m->pmatch[i].rm_eo = sp - m->offp;
58755845Sbostic 		dp = backref(m, sp, stop, ss+1, stopst, lev);
58855845Sbostic 		if (dp != NULL)
58955845Sbostic 			return(dp);
59055845Sbostic 		m->pmatch[i].rm_eo = offsave;
59155845Sbostic 		return(NULL);
59255845Sbostic 		break;
59355845Sbostic 	default:		/* uh oh */
59455845Sbostic 		assert(0);
59555845Sbostic 		break;
59655845Sbostic 	}
59755845Sbostic 
59855845Sbostic 	/* "can't happen" */
59955845Sbostic 	assert(0);
60055845Sbostic 	/* NOTREACHED */
60155845Sbostic }
60255845Sbostic 
60355845Sbostic /*
60455845Sbostic  - fast - step through the string at top speed
605*56355Sbostic  == static uchar *fast(register struct match *m, uchar *start, \
606*56355Sbostic  ==	uchar *stop, sopno startst, sopno stopst);
60755845Sbostic  */
60855845Sbostic static uchar *			/* where tentative match ended, or NULL */
60955845Sbostic fast(m, start, stop, startst, stopst)
61055845Sbostic register struct match *m;
61155845Sbostic uchar *start;
61255845Sbostic uchar *stop;
61355845Sbostic sopno startst;
61455845Sbostic sopno stopst;
61555845Sbostic {
61655845Sbostic 	register states st = m->st;
61755845Sbostic 	register states fresh = m->fresh;
61855845Sbostic 	register states tmp = m->tmp;
61955845Sbostic 	register uchar *p = start;
620*56355Sbostic 	register uchar c = (start == m->beginp) ? '\0' : *(start-1);
62155845Sbostic 	register uchar lastc;	/* previous c */
62255845Sbostic 	register int atbol;
62355845Sbostic 	register int ateol;
62455845Sbostic 	register uchar *coldp;	/* last p after which no match was underway */
62555845Sbostic 
62655845Sbostic 	CLEAR(st);
62755845Sbostic 	SET1(st, startst);
62855845Sbostic 	st = expand(m->g, startst, stopst, st, 0, 0);
62955845Sbostic 	ASSIGN(fresh, st);
63055845Sbostic 	SP("start", st, *p);
63155845Sbostic 	coldp = NULL;
63255845Sbostic 	for (;;) {
63355845Sbostic 		/* next character */
63455845Sbostic 		lastc = c;
63555845Sbostic 		c = (p == m->endp) ? '\0' : *p;
63655845Sbostic 		if (EQ(st, fresh))
63755845Sbostic 			coldp = p;
63855845Sbostic 
63955845Sbostic 		/* is there an EOL and/or BOL between lastc and c? */
64055845Sbostic 		atbol = ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
64155845Sbostic 				(lastc == '\0' && !(m->eflags&REG_NOTBOL)) );
64255845Sbostic 		ateol = ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
64355845Sbostic 				(c == '\0' && !(m->eflags&REG_NOTEOL)) );
64455845Sbostic 		if (atbol || ateol) {
64555845Sbostic 			st = expand(m->g, startst, stopst, st, atbol, ateol);
64655845Sbostic 			SP("bef", st, c);
64755845Sbostic 		}
64855845Sbostic 
64955845Sbostic 		/* are we done? */
65055845Sbostic 		if (ISSET(st, stopst) || p == stop)
65155845Sbostic 			break;		/* NOTE BREAK OUT */
65255845Sbostic 
65355845Sbostic 		/* no, we must deal with this character */
65455845Sbostic 		ASSIGN(tmp, st);
65555845Sbostic 		ASSIGN(st, fresh);
65655845Sbostic 		st = step(m->g, startst, stopst, tmp, c, st);
65755845Sbostic 		SP("aft", st, c);
65855845Sbostic 		assert(EQ(expand(m->g, startst, stopst, st, 0, 0), st));
65955845Sbostic 		p++;
66055845Sbostic 	}
66155845Sbostic 
66255845Sbostic 	assert(coldp != NULL);
66355845Sbostic 	m->coldp = coldp;
66455845Sbostic 	if (ISSET(st, stopst))
66555845Sbostic 		return(p+1);
66655845Sbostic 	else
66755845Sbostic 		return(NULL);
66855845Sbostic }
66955845Sbostic 
67055845Sbostic /*
67155845Sbostic  - slow - step through the string more deliberately
672*56355Sbostic  == static uchar *slow(register struct match *m, uchar *start, \
673*56355Sbostic  ==	uchar *stop, sopno startst, sopno stopst);
67455845Sbostic  */
67555845Sbostic static uchar *			/* where it ended */
67655845Sbostic slow(m, start, stop, startst, stopst)
67755845Sbostic register struct match *m;
67855845Sbostic uchar *start;
67955845Sbostic uchar *stop;
68055845Sbostic sopno startst;
68155845Sbostic sopno stopst;
68255845Sbostic {
68355845Sbostic 	register states st = m->st;
68455845Sbostic 	register states empty = m->empty;
68555845Sbostic 	register states tmp = m->tmp;
68655845Sbostic 	register uchar *p = start;
68755845Sbostic 	register uchar c = (start == m->beginp) ? '\0' : *(start-1);
68855845Sbostic 	register uchar lastc;	/* previous c */
68955845Sbostic 	register int atbol;
69055845Sbostic 	register int ateol;
69155845Sbostic 	register uchar *matchp;	/* last p at which a match ended */
69255845Sbostic 
693*56355Sbostic 	AT("slow", start, stop, startst, stopst);
69455845Sbostic 	CLEAR(st);
69555845Sbostic 	SET1(st, startst);
69655845Sbostic 	SP("sstart", st, *p);
69755845Sbostic 	matchp = NULL;
69855845Sbostic 	for (;;) {
69955845Sbostic 		/* next character */
70055845Sbostic 		lastc = c;
70155845Sbostic 		c = (p == m->endp) ? '\0' : *p;
70255845Sbostic 
70355845Sbostic 		/* is there an EOL and/or BOL between lastc and c? */
70455845Sbostic 		atbol = ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
70555845Sbostic 				(lastc == '\0' && !(m->eflags&REG_NOTBOL)) );
70655845Sbostic 		ateol = ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
70755845Sbostic 				(c == '\0' && !(m->eflags&REG_NOTEOL)) );
70855845Sbostic 
70955845Sbostic 		/* do we need an expansion before looking at the char? */
71055845Sbostic 		if (p == start || atbol || ateol) {
71155845Sbostic 			st = expand(m->g, startst, stopst, st, atbol, ateol);
71255845Sbostic 			SP("sbef", st, c);
71355845Sbostic 		}
71455845Sbostic 
71555845Sbostic 		/* are we done? */
71655845Sbostic 		if (ISSET(st, stopst))
71755845Sbostic 			matchp = p;
71855845Sbostic 		if (EQ(st, empty) || p == stop)
71955845Sbostic 			break;		/* NOTE BREAK OUT */
72055845Sbostic 
72155845Sbostic 		/* no, we must deal with this character */
72255845Sbostic 		ASSIGN(tmp, st);
72355845Sbostic 		ASSIGN(st, empty);
72455845Sbostic 		st = step(m->g, startst, stopst, tmp, c, st);
72555845Sbostic 		SP("saft", st, c);
72655845Sbostic 		assert(EQ(expand(m->g, startst, stopst, st, 0, 0), st));
72755845Sbostic 		p++;
72855845Sbostic 	}
72955845Sbostic 
73055845Sbostic 	return(matchp);
73155845Sbostic }
73255845Sbostic 
73355845Sbostic 
73455845Sbostic /*
73555845Sbostic  - expand - return set of states reachable from an initial set
736*56355Sbostic  == static states expand(register struct re_guts *g, int start, \
737*56355Sbostic  ==	int stop, register states st, int atbol, int ateol);
73855845Sbostic  */
73955845Sbostic static states
74055845Sbostic expand(g, start, stop, st, atbol, ateol)
74155845Sbostic register struct re_guts *g;
74255845Sbostic int start;			/* start state within strip */
74355845Sbostic int stop;			/* state after stop state within strip */
74455845Sbostic register states st;
74555845Sbostic int atbol;			/* at start or just after \n? (for BOL) */
74655845Sbostic int ateol;			/* just before \n or \0? (for EOL) */
74755845Sbostic {
74855845Sbostic 	register sop s;
74955845Sbostic 	register sopno pc;
75055845Sbostic 	register onestate here;		/* note, macros know this name */
75155845Sbostic 	register sopno look;
75255845Sbostic 	register int i;
75355845Sbostic 
75455845Sbostic 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
75555845Sbostic 		s = g->strip[pc];
75655845Sbostic 		switch (OP(s)) {
75755845Sbostic 		case OEND:
75855845Sbostic 			assert(pc == stop-1);
75955845Sbostic 			break;
76055845Sbostic 		case OCHAR:		/* can't get past this */
76155845Sbostic 			break;
76255845Sbostic 		case OBOL:
76355845Sbostic 			if (atbol)
76455845Sbostic 				FWD(st, st, 1);
76555845Sbostic 			break;
76655845Sbostic 		case OEOL:
76755845Sbostic 			if (ateol)
76855845Sbostic 				FWD(st, st, 1);
76955845Sbostic 			break;
77055845Sbostic 		case OANY:		/* can't get past this either */
77155845Sbostic 			break;
77255845Sbostic 		case OANYOF:		/* or this */
77355845Sbostic 			break;
77455845Sbostic 		case OBACK_:		/* not significant here */
77555845Sbostic 		case O_BACK:
77655845Sbostic 			FWD(st, st, 1);
77755845Sbostic 			break;
77855845Sbostic 		case OPLUS_:		/* forward, this is just an empty */
77955845Sbostic 			FWD(st, st, 1);
78055845Sbostic 			break;
78155845Sbostic 		case O_PLUS:		/* both forward and back */
78255845Sbostic 			FWD(st, st, 1);
78355845Sbostic 			i = ISSETBACK(st, OPND(s));
78455845Sbostic 			BACK(st, st, OPND(s));
78555845Sbostic 			if (!i && ISSETBACK(st, OPND(s))) {
78655845Sbostic 				/* oho, must reconsider loop body */
78755845Sbostic 				pc -= OPND(s) + 1;
78855845Sbostic 				INIT(here, pc);
78955845Sbostic 			}
79055845Sbostic 			break;
79155845Sbostic 		case OQUEST_:		/* two branches, both forward */
79255845Sbostic 			FWD(st, st, 1);
79355845Sbostic 			FWD(st, st, OPND(s));
79455845Sbostic 			break;
79555845Sbostic 		case O_QUEST:		/* just an empty */
79655845Sbostic 			FWD(st, st, 1);
79755845Sbostic 			break;
79855845Sbostic 		case OLPAREN:		/* not significant here */
79955845Sbostic 		case ORPAREN:
80055845Sbostic 			FWD(st, st, 1);
80155845Sbostic 			break;
80255845Sbostic 		case OCH_:		/* mark the first two branches */
80355845Sbostic 			FWD(st, st, 1);
80455845Sbostic 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
80555845Sbostic 			FWD(st, st, OPND(s));
80655845Sbostic 			break;
80755845Sbostic 		case OOR1:		/* done a branch, find the O_CH */
80855845Sbostic 			if (ISSTATEIN(st, here)) {
80955845Sbostic 				for (look = 1;
81055845Sbostic 						OP(s = g->strip[pc+look]) != O_CH;
81155845Sbostic 						look += OPND(s))
81255845Sbostic 					assert(OP(s) == OOR2);
81355845Sbostic 				FWD(st, st, look);
81455845Sbostic 			}
81555845Sbostic 			break;
81655845Sbostic 		case OOR2:		/* propagate OCH_'s marking onward */
81755845Sbostic 			FWD(st, st, 1);
81855845Sbostic 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
81955845Sbostic 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
82055845Sbostic 				FWD(st, st, OPND(s));
82155845Sbostic 			}
82255845Sbostic 			break;
82355845Sbostic 		case O_CH:		/* just an empty */
82455845Sbostic 			FWD(st, st, 1);
82555845Sbostic 			break;
82655845Sbostic 		default:		/* ooooops... */
82755845Sbostic 			assert(0);
82855845Sbostic 			break;
82955845Sbostic 		}
83055845Sbostic 	}
83155845Sbostic 
83255845Sbostic 	return(st);
83355845Sbostic }
83455845Sbostic 
83555845Sbostic /*
83655845Sbostic  - step - map set of states reachable before char to set reachable after
837*56355Sbostic  == static states step(register struct re_guts *g, int start, int stop, \
838*56355Sbostic  ==	register states bef, uchar ch, register states aft);
83955845Sbostic  */
84055845Sbostic static states
84155845Sbostic step(g, start, stop, bef, ch, aft)
84255845Sbostic register struct re_guts *g;
84355845Sbostic int start;			/* start state within strip */
84455845Sbostic int stop;			/* state after stop state within strip */
84555845Sbostic register states bef;		/* states reachable before */
84655845Sbostic uchar ch;
84755845Sbostic register states aft;		/* states already known reachable after */
84855845Sbostic {
84955845Sbostic 	register cset *cs;
85055845Sbostic 	register sop s;
85155845Sbostic 	register sopno pc;
85255845Sbostic 	register onestate here;		/* note, macros know this name */
85355845Sbostic 	register sopno look;
85455845Sbostic 	register int i;
85555845Sbostic 
85655845Sbostic 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
85755845Sbostic 		s = g->strip[pc];
85855845Sbostic 		switch (OP(s)) {
85955845Sbostic 		case OEND:
86055845Sbostic 			assert(pc == stop-1);
86155845Sbostic 			break;
86255845Sbostic 		case OCHAR:
86355845Sbostic 			if (ch == OPND(s))
86455845Sbostic 				FWD(aft, bef, 1);
86555845Sbostic 			break;
86655845Sbostic 		case OBOL:	/* these are looked after by expand() */
86755845Sbostic 		case OEOL:
86855845Sbostic 			break;
86955845Sbostic 		case OANY:
87055845Sbostic 			FWD(aft, bef, 1);
87155845Sbostic 			break;
87255845Sbostic 		case OANYOF:
87355845Sbostic 			cs = &g->sets[OPND(s)];
87455845Sbostic 			if (CHIN(cs, ch))
87555845Sbostic 				FWD(aft, bef, 1);
87655845Sbostic 			break;
87755845Sbostic 		case OBACK_:		/* ignored here */
87855845Sbostic 		case O_BACK:
87955845Sbostic 			FWD(aft, aft, 1);
88055845Sbostic 			break;
88155845Sbostic 		case OPLUS_:		/* forward, this is just an empty */
88255845Sbostic 			FWD(aft, aft, 1);
88355845Sbostic 			break;
88455845Sbostic 		case O_PLUS:		/* both forward and back */
88555845Sbostic 			FWD(aft, aft, 1);
88655845Sbostic 			i = ISSETBACK(aft, OPND(s));
88755845Sbostic 			BACK(aft, aft, OPND(s));
88855845Sbostic 			if (!i && ISSETBACK(aft, OPND(s))) {
88955845Sbostic 				/* oho, must reconsider loop body */
89055845Sbostic 				pc -= OPND(s) + 1;
89155845Sbostic 				INIT(here, pc);
89255845Sbostic 			}
89355845Sbostic 			break;
89455845Sbostic 		case OQUEST_:		/* two branches, both forward */
89555845Sbostic 			FWD(aft, aft, 1);
89655845Sbostic 			FWD(aft, aft, OPND(s));
89755845Sbostic 			break;
89855845Sbostic 		case O_QUEST:		/* just an empty */
89955845Sbostic 			FWD(aft, aft, 1);
90055845Sbostic 			break;
90155845Sbostic 		case OLPAREN:		/* not significant here */
90255845Sbostic 		case ORPAREN:
90355845Sbostic 			FWD(aft, aft, 1);
90455845Sbostic 			break;
90555845Sbostic 		case OCH_:		/* mark the first two branches */
90655845Sbostic 			FWD(aft, aft, 1);
90755845Sbostic 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
90855845Sbostic 			FWD(aft, aft, OPND(s));
90955845Sbostic 			break;
91055845Sbostic 		case OOR1:		/* done a branch, find the O_CH */
91155845Sbostic 			if (ISSTATEIN(aft, here)) {
91255845Sbostic 				for (look = 1;
91355845Sbostic 						OP(s = g->strip[pc+look]) != O_CH;
91455845Sbostic 						look += OPND(s))
91555845Sbostic 					assert(OP(s) == OOR2);
91655845Sbostic 				FWD(aft, aft, look);
91755845Sbostic 			}
91855845Sbostic 			break;
91955845Sbostic 		case OOR2:		/* propagate OCH_'s marking */
92055845Sbostic 			FWD(aft, aft, 1);
92155845Sbostic 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
92255845Sbostic 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
92355845Sbostic 				FWD(aft, aft, OPND(s));
92455845Sbostic 			}
92555845Sbostic 			break;
92655845Sbostic 		case O_CH:		/* just empty */
92755845Sbostic 			FWD(aft, aft, 1);
92855845Sbostic 			break;
92955845Sbostic 		default:		/* ooooops... */
93055845Sbostic 			assert(0);
93155845Sbostic 			break;
93255845Sbostic 		}
93355845Sbostic 	}
93455845Sbostic 
93555845Sbostic 	return(aft);
93655845Sbostic }
93755845Sbostic 
938*56355Sbostic #ifdef REDEBUG
93955845Sbostic /*
94055845Sbostic  - print - print a set of states
941*56355Sbostic  == #ifdef REDEBUG
942*56355Sbostic  == static void print(struct match *m, char *caption, states st, \
943*56355Sbostic  ==	uchar ch, FILE *d);
944*56355Sbostic  == #endif
94555845Sbostic  */
94655845Sbostic static void
947*56355Sbostic print(m, caption, st, ch, d)
948*56355Sbostic struct match *m;
94955845Sbostic char *caption;
95055845Sbostic states st;
95155845Sbostic uchar ch;
95255845Sbostic FILE *d;
95355845Sbostic {
954*56355Sbostic 	register struct re_guts *g = m->g;
95555845Sbostic 	register int i;
95655845Sbostic 	register int first = 1;
95755845Sbostic 
958*56355Sbostic 	if (!(m->eflags&REG_TRACE))
959*56355Sbostic 		return;
960*56355Sbostic 
96155845Sbostic 	fprintf(d, "%s", caption);
96255845Sbostic 	if (ch != '\0')
963*56355Sbostic 		fprintf(d, " %s", pchar(ch));
96455845Sbostic 	for (i = 0; i < g->nstates; i++)
96555845Sbostic 		if (ISSET(st, i)) {
96655845Sbostic 			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
96755845Sbostic 			first = 0;
96855845Sbostic 		}
96955845Sbostic 	fprintf(d, "\n");
97055845Sbostic }
971*56355Sbostic 
972*56355Sbostic /*
973*56355Sbostic  - at - print current situation
974*56355Sbostic  == #ifdef REDEBUG
975*56355Sbostic  == static void at(struct match *m, char *title, uchar *start, uchar *stop, \
976*56355Sbostic  ==						sopno startst, stopno stopst);
977*56355Sbostic  == #endif
978*56355Sbostic  */
979*56355Sbostic static void
980*56355Sbostic at(m, title, start, stop, startst, stopst)
981*56355Sbostic struct match *m;
982*56355Sbostic char *title;
983*56355Sbostic uchar *start;
984*56355Sbostic uchar *stop;
985*56355Sbostic sopno startst;
986*56355Sbostic sopno stopst;
987*56355Sbostic {
988*56355Sbostic 	if (!(m->eflags&REG_TRACE))
989*56355Sbostic 		return;
990*56355Sbostic 
991*56355Sbostic 	printf("%s %s-", title, pchar(*start));
992*56355Sbostic 	printf("%s ", pchar(*stop));
993*56355Sbostic 	printf("%ld-%ld\n", (long)startst, (long)stopst);
994*56355Sbostic }
995*56355Sbostic 
996*56355Sbostic #ifndef PCHARDONE
997*56355Sbostic #define	PCHARDONE	/* never again */
998*56355Sbostic /*
999*56355Sbostic  - pchar - make a character printable
1000*56355Sbostic  == #ifdef REDEBUG
1001*56355Sbostic  == static char *pchar(int ch);
1002*56355Sbostic  == #endif
1003*56355Sbostic  *
1004*56355Sbostic  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
1005*56355Sbostic  * duplicate here avoids having a debugging-capable regexec.o tied to
1006*56355Sbostic  * a matching debug.o, and this is convenient.  It all disappears in
1007*56355Sbostic  * the non-debug compilation anyway, so it doesn't matter much.
1008*56355Sbostic  */
1009*56355Sbostic static char *			/* -> representation */
1010*56355Sbostic pchar(ch)
1011*56355Sbostic int ch;
1012*56355Sbostic {
1013*56355Sbostic 	static char pbuf[10];
1014*56355Sbostic 
1015*56355Sbostic 	if (isprint(ch) || ch == ' ')
1016*56355Sbostic 		sprintf(pbuf, "%c", ch);
1017*56355Sbostic 	else
1018*56355Sbostic 		sprintf(pbuf, "\\%o", ch);
1019*56355Sbostic 	return(pbuf);
1020*56355Sbostic }
102155845Sbostic #endif
1022*56355Sbostic #endif
102355845Sbostic 
102455845Sbostic #undef	matcher
102555845Sbostic #undef	fast
102655845Sbostic #undef	slow
102755845Sbostic #undef	dissect
102855845Sbostic #undef	backref
102955845Sbostic #undef	expand
103055845Sbostic #undef	step
103155845Sbostic #undef	print
1032*56355Sbostic #undef	at
103355845Sbostic #undef	match
1034