xref: /freebsd/lib/libc/regex/engine.c (revision eab20bcecaf2f9d29bd1d279c474ec554ab6fd66)
158f0484fSRodney W. Grimes /*-
258f0484fSRodney W. Grimes  * Copyright (c) 1992, 1993, 1994 Henry Spencer.
358f0484fSRodney W. Grimes  * Copyright (c) 1992, 1993, 1994
458f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
558f0484fSRodney W. Grimes  *
658f0484fSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
758f0484fSRodney W. Grimes  * Henry Spencer.
858f0484fSRodney W. Grimes  *
958f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
1058f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
1158f0484fSRodney W. Grimes  * are met:
1258f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1358f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1458f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1558f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1658f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1758f0484fSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
1858f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
1958f0484fSRodney W. Grimes  *    without specific prior written permission.
2058f0484fSRodney W. Grimes  *
2158f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2258f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2358f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2458f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2558f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2658f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2758f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2858f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2958f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3058f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3158f0484fSRodney W. Grimes  * SUCH DAMAGE.
3258f0484fSRodney W. Grimes  *
3358f0484fSRodney W. Grimes  *	@(#)engine.c	8.5 (Berkeley) 3/20/94
3458f0484fSRodney W. Grimes  */
3558f0484fSRodney W. Grimes 
36333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
37333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
38333fc21eSDavid E. O'Brien 
3958f0484fSRodney W. Grimes /*
4058f0484fSRodney W. Grimes  * The matching engine and friends.  This file is #included by regexec.c
4158f0484fSRodney W. Grimes  * after suitable #defines of a variety of macros used herein, so that
4258f0484fSRodney W. Grimes  * different state representations can be used without duplicating masses
4358f0484fSRodney W. Grimes  * of code.
4458f0484fSRodney W. Grimes  */
4558f0484fSRodney W. Grimes 
4658f0484fSRodney W. Grimes #ifdef SNAMES
4758f0484fSRodney W. Grimes #define	matcher	smatcher
4858f0484fSRodney W. Grimes #define	fast	sfast
4958f0484fSRodney W. Grimes #define	slow	sslow
5058f0484fSRodney W. Grimes #define	dissect	sdissect
5158f0484fSRodney W. Grimes #define	backref	sbackref
5258f0484fSRodney W. Grimes #define	step	sstep
5358f0484fSRodney W. Grimes #define	print	sprint
5458f0484fSRodney W. Grimes #define	at	sat
5558f0484fSRodney W. Grimes #define	match	smat
5658f0484fSRodney W. Grimes #endif
5758f0484fSRodney W. Grimes #ifdef LNAMES
5858f0484fSRodney W. Grimes #define	matcher	lmatcher
5958f0484fSRodney W. Grimes #define	fast	lfast
6058f0484fSRodney W. Grimes #define	slow	lslow
6158f0484fSRodney W. Grimes #define	dissect	ldissect
6258f0484fSRodney W. Grimes #define	backref	lbackref
6358f0484fSRodney W. Grimes #define	step	lstep
6458f0484fSRodney W. Grimes #define	print	lprint
6558f0484fSRodney W. Grimes #define	at	lat
6658f0484fSRodney W. Grimes #define	match	lmat
6758f0484fSRodney W. Grimes #endif
68e5996857STim J. Robbins #ifdef MNAMES
69e5996857STim J. Robbins #define	matcher	mmatcher
70e5996857STim J. Robbins #define	fast	mfast
71e5996857STim J. Robbins #define	slow	mslow
72e5996857STim J. Robbins #define	dissect	mdissect
73e5996857STim J. Robbins #define	backref	mbackref
74e5996857STim J. Robbins #define	step	mstep
75e5996857STim J. Robbins #define	print	mprint
76e5996857STim J. Robbins #define	at	mat
77e5996857STim J. Robbins #define	match	mmat
78e5996857STim J. Robbins #endif
7958f0484fSRodney W. Grimes 
8058f0484fSRodney W. Grimes /* another structure passed up and down to avoid zillions of parameters */
8158f0484fSRodney W. Grimes struct match {
8258f0484fSRodney W. Grimes 	struct re_guts *g;
8358f0484fSRodney W. Grimes 	int eflags;
8458f0484fSRodney W. Grimes 	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
85eb2b3d10SXin LI 	const char *offp;	/* offsets work from here */
86eb2b3d10SXin LI 	const char *beginp;	/* start of string -- virtual NUL precedes */
87eb2b3d10SXin LI 	const char *endp;	/* end of string -- virtual NUL here */
88eb2b3d10SXin LI 	const char *coldp;	/* can be no match starting before here */
89eb2b3d10SXin LI 	const char **lastpos;	/* [nplus+1] */
9058f0484fSRodney W. Grimes 	STATEVARS;
9158f0484fSRodney W. Grimes 	states st;		/* current states */
9258f0484fSRodney W. Grimes 	states fresh;		/* states for a fresh start */
9358f0484fSRodney W. Grimes 	states tmp;		/* temporary */
9458f0484fSRodney W. Grimes 	states empty;		/* empty set of states */
95e5996857STim J. Robbins 	mbstate_t mbs;		/* multibyte conversion state */
9658f0484fSRodney W. Grimes };
9758f0484fSRodney W. Grimes 
9858f0484fSRodney W. Grimes /* ========= begin header generated by ./mkh ========= */
9958f0484fSRodney W. Grimes #ifdef __cplusplus
10058f0484fSRodney W. Grimes extern "C" {
10158f0484fSRodney W. Grimes #endif
10258f0484fSRodney W. Grimes 
10358f0484fSRodney W. Grimes /* === engine.c === */
104eb2b3d10SXin LI static int matcher(struct re_guts *g, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
105eb2b3d10SXin LI static const char *dissect(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
106eb2b3d10SXin LI static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev, int);
107eb2b3d10SXin LI static const char *fast(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
108eb2b3d10SXin LI static const char *slow(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
109e5996857STim J. Robbins static states step(struct re_guts *g, sopno start, sopno stop, states bef, wint_t ch, states aft);
110082063a0SXin LI #define MAX_RECURSION	100
111e5996857STim J. Robbins #define	BOL	(OUT-1)
112e5996857STim J. Robbins #define	EOL	(BOL-1)
113e5996857STim J. Robbins #define	BOLEOL	(BOL-2)
114e5996857STim J. Robbins #define	NOTHING	(BOL-3)
115e5996857STim J. Robbins #define	BOW	(BOL-4)
116e5996857STim J. Robbins #define	EOW	(BOL-5)
117e5996857STim J. Robbins #define	BADCHAR	(BOL-6)
118e5996857STim J. Robbins #define	NONCHAR(c)	((c) <= OUT)
11958f0484fSRodney W. Grimes #ifdef REDEBUG
120eb2b3d10SXin LI static void print(struct match *m, const char *caption, states st, int ch, FILE *d);
12158f0484fSRodney W. Grimes #endif
12258f0484fSRodney W. Grimes #ifdef REDEBUG
123eb2b3d10SXin LI static void at(struct match *m, const char *title, const char *start, const char *stop, sopno startst, sopno stopst);
12458f0484fSRodney W. Grimes #endif
12558f0484fSRodney W. Grimes #ifdef REDEBUG
126eb2b3d10SXin LI static const char *pchar(int ch);
12758f0484fSRodney W. Grimes #endif
12858f0484fSRodney W. Grimes 
12958f0484fSRodney W. Grimes #ifdef __cplusplus
13058f0484fSRodney W. Grimes }
13158f0484fSRodney W. Grimes #endif
13258f0484fSRodney W. Grimes /* ========= end header generated by ./mkh ========= */
13358f0484fSRodney W. Grimes 
13458f0484fSRodney W. Grimes #ifdef REDEBUG
13558f0484fSRodney W. Grimes #define	SP(t, s, c)	print(m, t, s, c, stdout)
13658f0484fSRodney W. Grimes #define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
13758f0484fSRodney W. Grimes #define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
13858f0484fSRodney W. Grimes #else
13958f0484fSRodney W. Grimes #define	SP(t, s, c)	/* nothing */
14058f0484fSRodney W. Grimes #define	AT(t, p1, p2, s1, s2)	/* nothing */
14158f0484fSRodney W. Grimes #define	NOTE(s)	/* nothing */
14258f0484fSRodney W. Grimes #endif
14358f0484fSRodney W. Grimes 
14458f0484fSRodney W. Grimes /*
14558f0484fSRodney W. Grimes  - matcher - the actual matching engine
146eb2b3d10SXin LI  == static int matcher(struct re_guts *g, const char *string, \
14758f0484fSRodney W. Grimes  ==	size_t nmatch, regmatch_t pmatch[], int eflags);
14858f0484fSRodney W. Grimes  */
14958f0484fSRodney W. Grimes static int			/* 0 success, REG_NOMATCH failure */
150eb2b3d10SXin LI matcher(struct re_guts *g,
151eb2b3d10SXin LI 	const char *string,
152eb2b3d10SXin LI 	size_t nmatch,
153eb2b3d10SXin LI 	regmatch_t pmatch[],
154eb2b3d10SXin LI 	int eflags)
15558f0484fSRodney W. Grimes {
156eb2b3d10SXin LI 	const char *endp;
1578fb3f3f6SDavid E. O'Brien 	int i;
15858f0484fSRodney W. Grimes 	struct match mv;
1598fb3f3f6SDavid E. O'Brien 	struct match *m = &mv;
160eb2b3d10SXin LI 	const char *dp;
1618fb3f3f6SDavid E. O'Brien 	const sopno gf = g->firststate+1;	/* +1 for OEND */
1628fb3f3f6SDavid E. O'Brien 	const sopno gl = g->laststate;
163eb2b3d10SXin LI 	const char *start;
164eb2b3d10SXin LI 	const char *stop;
1656049d9f0SDaniel C. Sobral 	/* Boyer-Moore algorithms variables */
166eb2b3d10SXin LI 	const char *pp;
1676049d9f0SDaniel C. Sobral 	int cj, mj;
168eb2b3d10SXin LI 	const char *mustfirst;
169eb2b3d10SXin LI 	const char *mustlast;
1708fb3f3f6SDavid E. O'Brien 	int *matchjump;
1718fb3f3f6SDavid E. O'Brien 	int *charjump;
17258f0484fSRodney W. Grimes 
17358f0484fSRodney W. Grimes 	/* simplify the situation where possible */
17458f0484fSRodney W. Grimes 	if (g->cflags&REG_NOSUB)
17558f0484fSRodney W. Grimes 		nmatch = 0;
17658f0484fSRodney W. Grimes 	if (eflags&REG_STARTEND) {
17758f0484fSRodney W. Grimes 		start = string + pmatch[0].rm_so;
17858f0484fSRodney W. Grimes 		stop = string + pmatch[0].rm_eo;
17958f0484fSRodney W. Grimes 	} else {
18058f0484fSRodney W. Grimes 		start = string;
18158f0484fSRodney W. Grimes 		stop = start + strlen(start);
18258f0484fSRodney W. Grimes 	}
18358f0484fSRodney W. Grimes 	if (stop < start)
18458f0484fSRodney W. Grimes 		return(REG_INVARG);
18558f0484fSRodney W. Grimes 
18658f0484fSRodney W. Grimes 	/* prescreening; this does wonders for this rather slow code */
18758f0484fSRodney W. Grimes 	if (g->must != NULL) {
1886049d9f0SDaniel C. Sobral 		if (g->charjump != NULL && g->matchjump != NULL) {
1896049d9f0SDaniel C. Sobral 			mustfirst = g->must;
1906049d9f0SDaniel C. Sobral 			mustlast = g->must + g->mlen - 1;
1916049d9f0SDaniel C. Sobral 			charjump = g->charjump;
1926049d9f0SDaniel C. Sobral 			matchjump = g->matchjump;
1936049d9f0SDaniel C. Sobral 			pp = mustlast;
194c5e125bbSDaniel C. Sobral 			for (dp = start+g->mlen-1; dp < stop;) {
1956049d9f0SDaniel C. Sobral 				/* Fast skip non-matches */
196e0554a53SJacques Vidrine 				while (dp < stop && charjump[(int)*dp])
197e0554a53SJacques Vidrine 					dp += charjump[(int)*dp];
1986049d9f0SDaniel C. Sobral 
199c5e125bbSDaniel C. Sobral 				if (dp >= stop)
2006049d9f0SDaniel C. Sobral 					break;
2016049d9f0SDaniel C. Sobral 
2026049d9f0SDaniel C. Sobral 				/* Greedy matcher */
2036049d9f0SDaniel C. Sobral 				/* We depend on not being used for
2046049d9f0SDaniel C. Sobral 				 * for strings of length 1
2056049d9f0SDaniel C. Sobral 				 */
206c5e125bbSDaniel C. Sobral 				while (*--dp == *--pp && pp != mustfirst);
2076049d9f0SDaniel C. Sobral 
208c5e125bbSDaniel C. Sobral 				if (*dp == *pp)
2096049d9f0SDaniel C. Sobral 					break;
2106049d9f0SDaniel C. Sobral 
2116049d9f0SDaniel C. Sobral 				/* Jump to next possible match */
2126049d9f0SDaniel C. Sobral 				mj = matchjump[pp - mustfirst];
213e0554a53SJacques Vidrine 				cj = charjump[(int)*dp];
214c5e125bbSDaniel C. Sobral 				dp += (cj < mj ? mj : cj);
2156049d9f0SDaniel C. Sobral 				pp = mustlast;
2166049d9f0SDaniel C. Sobral 			}
2176049d9f0SDaniel C. Sobral 			if (pp != mustfirst)
2186049d9f0SDaniel C. Sobral 				return(REG_NOMATCH);
2196049d9f0SDaniel C. Sobral 		} else {
22058f0484fSRodney W. Grimes 			for (dp = start; dp < stop; dp++)
2216049d9f0SDaniel C. Sobral 				if (*dp == g->must[0] &&
2226049d9f0SDaniel C. Sobral 				    stop - dp >= g->mlen &&
22358f0484fSRodney W. Grimes 				    memcmp(dp, g->must, (size_t)g->mlen) == 0)
22458f0484fSRodney W. Grimes 					break;
22558f0484fSRodney W. Grimes 			if (dp == stop)		/* we didn't find g->must */
22658f0484fSRodney W. Grimes 				return(REG_NOMATCH);
22758f0484fSRodney W. Grimes 		}
2286049d9f0SDaniel C. Sobral 	}
22958f0484fSRodney W. Grimes 
23058f0484fSRodney W. Grimes 	/* match struct setup */
23158f0484fSRodney W. Grimes 	m->g = g;
23258f0484fSRodney W. Grimes 	m->eflags = eflags;
23358f0484fSRodney W. Grimes 	m->pmatch = NULL;
23458f0484fSRodney W. Grimes 	m->lastpos = NULL;
23558f0484fSRodney W. Grimes 	m->offp = string;
23658f0484fSRodney W. Grimes 	m->beginp = start;
23758f0484fSRodney W. Grimes 	m->endp = stop;
23858f0484fSRodney W. Grimes 	STATESETUP(m, 4);
23958f0484fSRodney W. Grimes 	SETUP(m->st);
24058f0484fSRodney W. Grimes 	SETUP(m->fresh);
24158f0484fSRodney W. Grimes 	SETUP(m->tmp);
24258f0484fSRodney W. Grimes 	SETUP(m->empty);
24358f0484fSRodney W. Grimes 	CLEAR(m->empty);
244e5996857STim J. Robbins 	ZAPSTATE(&m->mbs);
24558f0484fSRodney W. Grimes 
246e6a886d8SDaniel C. Sobral 	/* Adjust start according to moffset, to speed things up */
247e6a886d8SDaniel C. Sobral 	if (g->moffset > -1)
248b6c1a561SDaniel C. Sobral 		start = ((dp - g->moffset) < start) ? start : dp - g->moffset;
249e6a886d8SDaniel C. Sobral 
250bca3476aSDiomidis Spinellis 	SP("mloop", m->st, *start);
251bca3476aSDiomidis Spinellis 
25258f0484fSRodney W. Grimes 	/* this loop does only one repetition except for backrefs */
25358f0484fSRodney W. Grimes 	for (;;) {
25458f0484fSRodney W. Grimes 		endp = fast(m, start, stop, gf, gl);
25558f0484fSRodney W. Grimes 		if (endp == NULL) {		/* a miss */
256c7ce9e21SDiomidis Spinellis 			if (m->pmatch != NULL)
257c7ce9e21SDiomidis Spinellis 				free((char *)m->pmatch);
258c7ce9e21SDiomidis Spinellis 			if (m->lastpos != NULL)
259c7ce9e21SDiomidis Spinellis 				free((char *)m->lastpos);
26058f0484fSRodney W. Grimes 			STATETEARDOWN(m);
26158f0484fSRodney W. Grimes 			return(REG_NOMATCH);
26258f0484fSRodney W. Grimes 		}
26358f0484fSRodney W. Grimes 		if (nmatch == 0 && !g->backrefs)
26458f0484fSRodney W. Grimes 			break;		/* no further info needed */
26558f0484fSRodney W. Grimes 
26658f0484fSRodney W. Grimes 		/* where? */
26758f0484fSRodney W. Grimes 		assert(m->coldp != NULL);
26858f0484fSRodney W. Grimes 		for (;;) {
26958f0484fSRodney W. Grimes 			NOTE("finding start");
27058f0484fSRodney W. Grimes 			endp = slow(m, m->coldp, stop, gf, gl);
27158f0484fSRodney W. Grimes 			if (endp != NULL)
27258f0484fSRodney W. Grimes 				break;
27358f0484fSRodney W. Grimes 			assert(m->coldp < m->endp);
274e5996857STim J. Robbins 			m->coldp += XMBRTOWC(NULL, m->coldp,
275e5996857STim J. Robbins 			    m->endp - m->coldp, &m->mbs, 0);
27658f0484fSRodney W. Grimes 		}
27758f0484fSRodney W. Grimes 		if (nmatch == 1 && !g->backrefs)
27858f0484fSRodney W. Grimes 			break;		/* no further info needed */
27958f0484fSRodney W. Grimes 
28058f0484fSRodney W. Grimes 		/* oh my, he wants the subexpressions... */
28158f0484fSRodney W. Grimes 		if (m->pmatch == NULL)
28258f0484fSRodney W. Grimes 			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
28358f0484fSRodney W. Grimes 							sizeof(regmatch_t));
28458f0484fSRodney W. Grimes 		if (m->pmatch == NULL) {
28558f0484fSRodney W. Grimes 			STATETEARDOWN(m);
28658f0484fSRodney W. Grimes 			return(REG_ESPACE);
28758f0484fSRodney W. Grimes 		}
28858f0484fSRodney W. Grimes 		for (i = 1; i <= m->g->nsub; i++)
28958f0484fSRodney W. Grimes 			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
29058f0484fSRodney W. Grimes 		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
29158f0484fSRodney W. Grimes 			NOTE("dissecting");
29258f0484fSRodney W. Grimes 			dp = dissect(m, m->coldp, endp, gf, gl);
29358f0484fSRodney W. Grimes 		} else {
29458f0484fSRodney W. Grimes 			if (g->nplus > 0 && m->lastpos == NULL)
295eb2b3d10SXin LI 				m->lastpos = malloc((g->nplus+1) *
296eb2b3d10SXin LI 						sizeof(const char *));
29758f0484fSRodney W. Grimes 			if (g->nplus > 0 && m->lastpos == NULL) {
29858f0484fSRodney W. Grimes 				free(m->pmatch);
29958f0484fSRodney W. Grimes 				STATETEARDOWN(m);
30058f0484fSRodney W. Grimes 				return(REG_ESPACE);
30158f0484fSRodney W. Grimes 			}
30258f0484fSRodney W. Grimes 			NOTE("backref dissect");
303082063a0SXin LI 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
30458f0484fSRodney W. Grimes 		}
30558f0484fSRodney W. Grimes 		if (dp != NULL)
30658f0484fSRodney W. Grimes 			break;
30758f0484fSRodney W. Grimes 
30858f0484fSRodney W. Grimes 		/* uh-oh... we couldn't find a subexpression-level match */
30958f0484fSRodney W. Grimes 		assert(g->backrefs);	/* must be back references doing it */
31058f0484fSRodney W. Grimes 		assert(g->nplus == 0 || m->lastpos != NULL);
31158f0484fSRodney W. Grimes 		for (;;) {
31258f0484fSRodney W. Grimes 			if (dp != NULL || endp <= m->coldp)
31358f0484fSRodney W. Grimes 				break;		/* defeat */
31458f0484fSRodney W. Grimes 			NOTE("backoff");
31558f0484fSRodney W. Grimes 			endp = slow(m, m->coldp, endp-1, gf, gl);
31658f0484fSRodney W. Grimes 			if (endp == NULL)
31758f0484fSRodney W. Grimes 				break;		/* defeat */
31858f0484fSRodney W. Grimes 			/* try it on a shorter possibility */
31958f0484fSRodney W. Grimes #ifndef NDEBUG
32058f0484fSRodney W. Grimes 			for (i = 1; i <= m->g->nsub; i++) {
32158f0484fSRodney W. Grimes 				assert(m->pmatch[i].rm_so == -1);
32258f0484fSRodney W. Grimes 				assert(m->pmatch[i].rm_eo == -1);
32358f0484fSRodney W. Grimes 			}
32458f0484fSRodney W. Grimes #endif
32558f0484fSRodney W. Grimes 			NOTE("backoff dissect");
326082063a0SXin LI 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
32758f0484fSRodney W. Grimes 		}
32858f0484fSRodney W. Grimes 		assert(dp == NULL || dp == endp);
32958f0484fSRodney W. Grimes 		if (dp != NULL)		/* found a shorter one */
33058f0484fSRodney W. Grimes 			break;
33158f0484fSRodney W. Grimes 
33258f0484fSRodney W. Grimes 		/* despite initial appearances, there is no match here */
33358f0484fSRodney W. Grimes 		NOTE("false alarm");
334e5996857STim J. Robbins 		/* recycle starting later */
335e5996857STim J. Robbins 		start = m->coldp + XMBRTOWC(NULL, m->coldp,
336bd9643b1STim J. Robbins 		    stop - m->coldp, &m->mbs, 0);
33758f0484fSRodney W. Grimes 		assert(start <= stop);
33858f0484fSRodney W. Grimes 	}
33958f0484fSRodney W. Grimes 
34058f0484fSRodney W. Grimes 	/* fill in the details if requested */
34158f0484fSRodney W. Grimes 	if (nmatch > 0) {
34258f0484fSRodney W. Grimes 		pmatch[0].rm_so = m->coldp - m->offp;
34358f0484fSRodney W. Grimes 		pmatch[0].rm_eo = endp - m->offp;
34458f0484fSRodney W. Grimes 	}
34558f0484fSRodney W. Grimes 	if (nmatch > 1) {
34658f0484fSRodney W. Grimes 		assert(m->pmatch != NULL);
34758f0484fSRodney W. Grimes 		for (i = 1; i < nmatch; i++)
34858f0484fSRodney W. Grimes 			if (i <= m->g->nsub)
34958f0484fSRodney W. Grimes 				pmatch[i] = m->pmatch[i];
35058f0484fSRodney W. Grimes 			else {
35158f0484fSRodney W. Grimes 				pmatch[i].rm_so = -1;
35258f0484fSRodney W. Grimes 				pmatch[i].rm_eo = -1;
35358f0484fSRodney W. Grimes 			}
35458f0484fSRodney W. Grimes 	}
35558f0484fSRodney W. Grimes 
35658f0484fSRodney W. Grimes 	if (m->pmatch != NULL)
35758f0484fSRodney W. Grimes 		free((char *)m->pmatch);
35858f0484fSRodney W. Grimes 	if (m->lastpos != NULL)
35958f0484fSRodney W. Grimes 		free((char *)m->lastpos);
36058f0484fSRodney W. Grimes 	STATETEARDOWN(m);
36158f0484fSRodney W. Grimes 	return(0);
36258f0484fSRodney W. Grimes }
36358f0484fSRodney W. Grimes 
36458f0484fSRodney W. Grimes /*
36558f0484fSRodney W. Grimes  - dissect - figure out what matched what, no back references
366eb2b3d10SXin LI  == static const char *dissect(struct match *m, const char *start, \
367eb2b3d10SXin LI  ==	const char *stop, sopno startst, sopno stopst);
36858f0484fSRodney W. Grimes  */
369eb2b3d10SXin LI static const char *		/* == stop (success) always */
370eb2b3d10SXin LI dissect(struct match *m,
371eb2b3d10SXin LI 	const char *start,
372eb2b3d10SXin LI 	const char *stop,
373eb2b3d10SXin LI 	sopno startst,
374eb2b3d10SXin LI 	sopno stopst)
37558f0484fSRodney W. Grimes {
3768fb3f3f6SDavid E. O'Brien 	int i;
3778fb3f3f6SDavid E. O'Brien 	sopno ss;		/* start sop of current subRE */
3788fb3f3f6SDavid E. O'Brien 	sopno es;		/* end sop of current subRE */
379eb2b3d10SXin LI 	const char *sp;		/* start of string matched by it */
380eb2b3d10SXin LI 	const char *stp;	/* string matched by it cannot pass here */
381eb2b3d10SXin LI 	const char *rest;	/* start of rest of string */
382eb2b3d10SXin LI 	const char *tail;	/* string unmatched by rest of RE */
3838fb3f3f6SDavid E. O'Brien 	sopno ssub;		/* start sop of subsubRE */
3848fb3f3f6SDavid E. O'Brien 	sopno esub;		/* end sop of subsubRE */
385eb2b3d10SXin LI 	const char *ssp;	/* start of string matched by subsubRE */
386eb2b3d10SXin LI 	const char *sep;	/* end of string matched by subsubRE */
387eb2b3d10SXin LI 	const char *oldssp;	/* previous ssp */
388eb2b3d10SXin LI 	const char *dp;
38958f0484fSRodney W. Grimes 
39058f0484fSRodney W. Grimes 	AT("diss", start, stop, startst, stopst);
39158f0484fSRodney W. Grimes 	sp = start;
39258f0484fSRodney W. Grimes 	for (ss = startst; ss < stopst; ss = es) {
39358f0484fSRodney W. Grimes 		/* identify end of subRE */
39458f0484fSRodney W. Grimes 		es = ss;
39558f0484fSRodney W. Grimes 		switch (OP(m->g->strip[es])) {
39658f0484fSRodney W. Grimes 		case OPLUS_:
39758f0484fSRodney W. Grimes 		case OQUEST_:
39858f0484fSRodney W. Grimes 			es += OPND(m->g->strip[es]);
39958f0484fSRodney W. Grimes 			break;
40058f0484fSRodney W. Grimes 		case OCH_:
40158f0484fSRodney W. Grimes 			while (OP(m->g->strip[es]) != O_CH)
40258f0484fSRodney W. Grimes 				es += OPND(m->g->strip[es]);
40358f0484fSRodney W. Grimes 			break;
40458f0484fSRodney W. Grimes 		}
40558f0484fSRodney W. Grimes 		es++;
40658f0484fSRodney W. Grimes 
40758f0484fSRodney W. Grimes 		/* figure out what it matched */
40858f0484fSRodney W. Grimes 		switch (OP(m->g->strip[ss])) {
40958f0484fSRodney W. Grimes 		case OEND:
41058f0484fSRodney W. Grimes 			assert(nope);
41158f0484fSRodney W. Grimes 			break;
41258f0484fSRodney W. Grimes 		case OCHAR:
413e5996857STim J. Robbins 			sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
41458f0484fSRodney W. Grimes 			break;
41558f0484fSRodney W. Grimes 		case OBOL:
41658f0484fSRodney W. Grimes 		case OEOL:
41758f0484fSRodney W. Grimes 		case OBOW:
41858f0484fSRodney W. Grimes 		case OEOW:
41958f0484fSRodney W. Grimes 			break;
42058f0484fSRodney W. Grimes 		case OANY:
42158f0484fSRodney W. Grimes 		case OANYOF:
422e5996857STim J. Robbins 			sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
42358f0484fSRodney W. Grimes 			break;
42458f0484fSRodney W. Grimes 		case OBACK_:
42558f0484fSRodney W. Grimes 		case O_BACK:
42658f0484fSRodney W. Grimes 			assert(nope);
42758f0484fSRodney W. Grimes 			break;
42858f0484fSRodney W. Grimes 		/* cases where length of match is hard to find */
42958f0484fSRodney W. Grimes 		case OQUEST_:
43058f0484fSRodney W. Grimes 			stp = stop;
43158f0484fSRodney W. Grimes 			for (;;) {
43258f0484fSRodney W. Grimes 				/* how long could this one be? */
43358f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
43458f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
43558f0484fSRodney W. Grimes 				/* could the rest match the rest? */
43658f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
43758f0484fSRodney W. Grimes 				if (tail == stop)
43858f0484fSRodney W. Grimes 					break;		/* yes! */
43958f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
44058f0484fSRodney W. Grimes 				stp = rest - 1;
44158f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
44258f0484fSRodney W. Grimes 			}
44358f0484fSRodney W. Grimes 			ssub = ss + 1;
44458f0484fSRodney W. Grimes 			esub = es - 1;
44558f0484fSRodney W. Grimes 			/* did innards match? */
44658f0484fSRodney W. Grimes 			if (slow(m, sp, rest, ssub, esub) != NULL) {
44758f0484fSRodney W. Grimes 				dp = dissect(m, sp, rest, ssub, esub);
44858f0484fSRodney W. Grimes 				assert(dp == rest);
44958f0484fSRodney W. Grimes 			} else		/* no */
45058f0484fSRodney W. Grimes 				assert(sp == rest);
45158f0484fSRodney W. Grimes 			sp = rest;
45258f0484fSRodney W. Grimes 			break;
45358f0484fSRodney W. Grimes 		case OPLUS_:
45458f0484fSRodney W. Grimes 			stp = stop;
45558f0484fSRodney W. Grimes 			for (;;) {
45658f0484fSRodney W. Grimes 				/* how long could this one be? */
45758f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
45858f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
45958f0484fSRodney W. Grimes 				/* could the rest match the rest? */
46058f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
46158f0484fSRodney W. Grimes 				if (tail == stop)
46258f0484fSRodney W. Grimes 					break;		/* yes! */
46358f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
46458f0484fSRodney W. Grimes 				stp = rest - 1;
46558f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
46658f0484fSRodney W. Grimes 			}
46758f0484fSRodney W. Grimes 			ssub = ss + 1;
46858f0484fSRodney W. Grimes 			esub = es - 1;
46958f0484fSRodney W. Grimes 			ssp = sp;
47058f0484fSRodney W. Grimes 			oldssp = ssp;
47158f0484fSRodney W. Grimes 			for (;;) {	/* find last match of innards */
47258f0484fSRodney W. Grimes 				sep = slow(m, ssp, rest, ssub, esub);
47358f0484fSRodney W. Grimes 				if (sep == NULL || sep == ssp)
47458f0484fSRodney W. Grimes 					break;	/* failed or matched null */
47558f0484fSRodney W. Grimes 				oldssp = ssp;	/* on to next try */
47658f0484fSRodney W. Grimes 				ssp = sep;
47758f0484fSRodney W. Grimes 			}
47858f0484fSRodney W. Grimes 			if (sep == NULL) {
47958f0484fSRodney W. Grimes 				/* last successful match */
48058f0484fSRodney W. Grimes 				sep = ssp;
48158f0484fSRodney W. Grimes 				ssp = oldssp;
48258f0484fSRodney W. Grimes 			}
48358f0484fSRodney W. Grimes 			assert(sep == rest);	/* must exhaust substring */
48458f0484fSRodney W. Grimes 			assert(slow(m, ssp, sep, ssub, esub) == rest);
48558f0484fSRodney W. Grimes 			dp = dissect(m, ssp, sep, ssub, esub);
48658f0484fSRodney W. Grimes 			assert(dp == sep);
48758f0484fSRodney W. Grimes 			sp = rest;
48858f0484fSRodney W. Grimes 			break;
48958f0484fSRodney W. Grimes 		case OCH_:
49058f0484fSRodney W. Grimes 			stp = stop;
49158f0484fSRodney W. Grimes 			for (;;) {
49258f0484fSRodney W. Grimes 				/* how long could this one be? */
49358f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
49458f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
49558f0484fSRodney W. Grimes 				/* could the rest match the rest? */
49658f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
49758f0484fSRodney W. Grimes 				if (tail == stop)
49858f0484fSRodney W. Grimes 					break;		/* yes! */
49958f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
50058f0484fSRodney W. Grimes 				stp = rest - 1;
50158f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
50258f0484fSRodney W. Grimes 			}
50358f0484fSRodney W. Grimes 			ssub = ss + 1;
50458f0484fSRodney W. Grimes 			esub = ss + OPND(m->g->strip[ss]) - 1;
50558f0484fSRodney W. Grimes 			assert(OP(m->g->strip[esub]) == OOR1);
50658f0484fSRodney W. Grimes 			for (;;) {	/* find first matching branch */
50758f0484fSRodney W. Grimes 				if (slow(m, sp, rest, ssub, esub) == rest)
50858f0484fSRodney W. Grimes 					break;	/* it matched all of it */
50958f0484fSRodney W. Grimes 				/* that one missed, try next one */
51058f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == OOR1);
51158f0484fSRodney W. Grimes 				esub++;
51258f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == OOR2);
51358f0484fSRodney W. Grimes 				ssub = esub + 1;
51458f0484fSRodney W. Grimes 				esub += OPND(m->g->strip[esub]);
51558f0484fSRodney W. Grimes 				if (OP(m->g->strip[esub]) == OOR2)
51658f0484fSRodney W. Grimes 					esub--;
51758f0484fSRodney W. Grimes 				else
51858f0484fSRodney W. Grimes 					assert(OP(m->g->strip[esub]) == O_CH);
51958f0484fSRodney W. Grimes 			}
52058f0484fSRodney W. Grimes 			dp = dissect(m, sp, rest, ssub, esub);
52158f0484fSRodney W. Grimes 			assert(dp == rest);
52258f0484fSRodney W. Grimes 			sp = rest;
52358f0484fSRodney W. Grimes 			break;
52458f0484fSRodney W. Grimes 		case O_PLUS:
52558f0484fSRodney W. Grimes 		case O_QUEST:
52658f0484fSRodney W. Grimes 		case OOR1:
52758f0484fSRodney W. Grimes 		case OOR2:
52858f0484fSRodney W. Grimes 		case O_CH:
52958f0484fSRodney W. Grimes 			assert(nope);
53058f0484fSRodney W. Grimes 			break;
53158f0484fSRodney W. Grimes 		case OLPAREN:
53258f0484fSRodney W. Grimes 			i = OPND(m->g->strip[ss]);
53358f0484fSRodney W. Grimes 			assert(0 < i && i <= m->g->nsub);
53458f0484fSRodney W. Grimes 			m->pmatch[i].rm_so = sp - m->offp;
53558f0484fSRodney W. Grimes 			break;
53658f0484fSRodney W. Grimes 		case ORPAREN:
53758f0484fSRodney W. Grimes 			i = OPND(m->g->strip[ss]);
53858f0484fSRodney W. Grimes 			assert(0 < i && i <= m->g->nsub);
53958f0484fSRodney W. Grimes 			m->pmatch[i].rm_eo = sp - m->offp;
54058f0484fSRodney W. Grimes 			break;
54158f0484fSRodney W. Grimes 		default:		/* uh oh */
54258f0484fSRodney W. Grimes 			assert(nope);
54358f0484fSRodney W. Grimes 			break;
54458f0484fSRodney W. Grimes 		}
54558f0484fSRodney W. Grimes 	}
54658f0484fSRodney W. Grimes 
54758f0484fSRodney W. Grimes 	assert(sp == stop);
54858f0484fSRodney W. Grimes 	return(sp);
54958f0484fSRodney W. Grimes }
55058f0484fSRodney W. Grimes 
55158f0484fSRodney W. Grimes /*
55258f0484fSRodney W. Grimes  - backref - figure out what matched what, figuring in back references
553eb2b3d10SXin LI  == static const char *backref(struct match *m, const char *start, \
554eb2b3d10SXin LI  ==	const char *stop, sopno startst, sopno stopst, sopno lev);
55558f0484fSRodney W. Grimes  */
556eb2b3d10SXin LI static const char *		/* == stop (success) or NULL (failure) */
557eb2b3d10SXin LI backref(struct match *m,
558eb2b3d10SXin LI 	const char *start,
559eb2b3d10SXin LI 	const char *stop,
560eb2b3d10SXin LI 	sopno startst,
561eb2b3d10SXin LI 	sopno stopst,
562eb2b3d10SXin LI 	sopno lev,		/* PLUS nesting level */
563eb2b3d10SXin LI 	int rec)
56458f0484fSRodney W. Grimes {
5658fb3f3f6SDavid E. O'Brien 	int i;
5668fb3f3f6SDavid E. O'Brien 	sopno ss;		/* start sop of current subRE */
567eb2b3d10SXin LI 	const char *sp;		/* start of string matched by it */
5688fb3f3f6SDavid E. O'Brien 	sopno ssub;		/* start sop of subsubRE */
5698fb3f3f6SDavid E. O'Brien 	sopno esub;		/* end sop of subsubRE */
570eb2b3d10SXin LI 	const char *ssp;	/* start of string matched by subsubRE */
571eb2b3d10SXin LI 	const char *dp;
5728fb3f3f6SDavid E. O'Brien 	size_t len;
5738fb3f3f6SDavid E. O'Brien 	int hard;
5748fb3f3f6SDavid E. O'Brien 	sop s;
5758fb3f3f6SDavid E. O'Brien 	regoff_t offsave;
5768fb3f3f6SDavid E. O'Brien 	cset *cs;
577e5996857STim J. Robbins 	wint_t wc;
57858f0484fSRodney W. Grimes 
57958f0484fSRodney W. Grimes 	AT("back", start, stop, startst, stopst);
58058f0484fSRodney W. Grimes 	sp = start;
58158f0484fSRodney W. Grimes 
58258f0484fSRodney W. Grimes 	/* get as far as we can with easy stuff */
58358f0484fSRodney W. Grimes 	hard = 0;
58458f0484fSRodney W. Grimes 	for (ss = startst; !hard && ss < stopst; ss++)
58558f0484fSRodney W. Grimes 		switch (OP(s = m->g->strip[ss])) {
58658f0484fSRodney W. Grimes 		case OCHAR:
587e5996857STim J. Robbins 			if (sp == stop)
588e5996857STim J. Robbins 				return(NULL);
589e5996857STim J. Robbins 			sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
590e5996857STim J. Robbins 			if (wc != OPND(s))
59158f0484fSRodney W. Grimes 				return(NULL);
59258f0484fSRodney W. Grimes 			break;
59358f0484fSRodney W. Grimes 		case OANY:
59458f0484fSRodney W. Grimes 			if (sp == stop)
59558f0484fSRodney W. Grimes 				return(NULL);
596e5996857STim J. Robbins 			sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
597e5996857STim J. Robbins 			if (wc == BADCHAR)
598e5996857STim J. Robbins 				return (NULL);
59958f0484fSRodney W. Grimes 			break;
60058f0484fSRodney W. Grimes 		case OANYOF:
601e5996857STim J. Robbins 			if (sp == stop)
602e5996857STim J. Robbins 				return (NULL);
60358f0484fSRodney W. Grimes 			cs = &m->g->sets[OPND(s)];
604e5996857STim J. Robbins 			sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
605e5996857STim J. Robbins 			if (wc == BADCHAR || !CHIN(cs, wc))
60658f0484fSRodney W. Grimes 				return(NULL);
60758f0484fSRodney W. Grimes 			break;
60858f0484fSRodney W. Grimes 		case OBOL:
60958f0484fSRodney W. Grimes 			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
61058f0484fSRodney W. Grimes 					(sp < m->endp && *(sp-1) == '\n' &&
61158f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) )
61258f0484fSRodney W. Grimes 				{ /* yes */ }
61358f0484fSRodney W. Grimes 			else
61458f0484fSRodney W. Grimes 				return(NULL);
61558f0484fSRodney W. Grimes 			break;
61658f0484fSRodney W. Grimes 		case OEOL:
61758f0484fSRodney W. Grimes 			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
61858f0484fSRodney W. Grimes 					(sp < m->endp && *sp == '\n' &&
61958f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) )
62058f0484fSRodney W. Grimes 				{ /* yes */ }
62158f0484fSRodney W. Grimes 			else
62258f0484fSRodney W. Grimes 				return(NULL);
62358f0484fSRodney W. Grimes 			break;
62458f0484fSRodney W. Grimes 		case OBOW:
62558f0484fSRodney W. Grimes 			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
62658f0484fSRodney W. Grimes 					(sp < m->endp && *(sp-1) == '\n' &&
62758f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) ||
62858f0484fSRodney W. Grimes 					(sp > m->beginp &&
62958f0484fSRodney W. Grimes 							!ISWORD(*(sp-1))) ) &&
63058f0484fSRodney W. Grimes 					(sp < m->endp && ISWORD(*sp)) )
63158f0484fSRodney W. Grimes 				{ /* yes */ }
63258f0484fSRodney W. Grimes 			else
63358f0484fSRodney W. Grimes 				return(NULL);
63458f0484fSRodney W. Grimes 			break;
63558f0484fSRodney W. Grimes 		case OEOW:
63658f0484fSRodney W. Grimes 			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
63758f0484fSRodney W. Grimes 					(sp < m->endp && *sp == '\n' &&
63858f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) ||
63958f0484fSRodney W. Grimes 					(sp < m->endp && !ISWORD(*sp)) ) &&
64058f0484fSRodney W. Grimes 					(sp > m->beginp && ISWORD(*(sp-1))) )
64158f0484fSRodney W. Grimes 				{ /* yes */ }
64258f0484fSRodney W. Grimes 			else
64358f0484fSRodney W. Grimes 				return(NULL);
64458f0484fSRodney W. Grimes 			break;
64558f0484fSRodney W. Grimes 		case O_QUEST:
64658f0484fSRodney W. Grimes 			break;
64758f0484fSRodney W. Grimes 		case OOR1:	/* matches null but needs to skip */
64858f0484fSRodney W. Grimes 			ss++;
64958f0484fSRodney W. Grimes 			s = m->g->strip[ss];
65058f0484fSRodney W. Grimes 			do {
65158f0484fSRodney W. Grimes 				assert(OP(s) == OOR2);
65258f0484fSRodney W. Grimes 				ss += OPND(s);
65358f0484fSRodney W. Grimes 			} while (OP(s = m->g->strip[ss]) != O_CH);
65458f0484fSRodney W. Grimes 			/* note that the ss++ gets us past the O_CH */
65558f0484fSRodney W. Grimes 			break;
65658f0484fSRodney W. Grimes 		default:	/* have to make a choice */
65758f0484fSRodney W. Grimes 			hard = 1;
65858f0484fSRodney W. Grimes 			break;
65958f0484fSRodney W. Grimes 		}
66058f0484fSRodney W. Grimes 	if (!hard) {		/* that was it! */
66158f0484fSRodney W. Grimes 		if (sp != stop)
66258f0484fSRodney W. Grimes 			return(NULL);
66358f0484fSRodney W. Grimes 		return(sp);
66458f0484fSRodney W. Grimes 	}
66558f0484fSRodney W. Grimes 	ss--;			/* adjust for the for's final increment */
66658f0484fSRodney W. Grimes 
66758f0484fSRodney W. Grimes 	/* the hard stuff */
66858f0484fSRodney W. Grimes 	AT("hard", sp, stop, ss, stopst);
66958f0484fSRodney W. Grimes 	s = m->g->strip[ss];
67058f0484fSRodney W. Grimes 	switch (OP(s)) {
67158f0484fSRodney W. Grimes 	case OBACK_:		/* the vilest depths */
67258f0484fSRodney W. Grimes 		i = OPND(s);
67358f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
67458f0484fSRodney W. Grimes 		if (m->pmatch[i].rm_eo == -1)
67558f0484fSRodney W. Grimes 			return(NULL);
67658f0484fSRodney W. Grimes 		assert(m->pmatch[i].rm_so != -1);
67758f0484fSRodney W. Grimes 		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
678082063a0SXin LI 		if (len == 0 && rec++ > MAX_RECURSION)
6790f4481c5SXin LI 			return(NULL);
68058f0484fSRodney W. Grimes 		assert(stop - m->beginp >= len);
68158f0484fSRodney W. Grimes 		if (sp > stop - len)
68258f0484fSRodney W. Grimes 			return(NULL);	/* not enough left to match */
68358f0484fSRodney W. Grimes 		ssp = m->offp + m->pmatch[i].rm_so;
68458f0484fSRodney W. Grimes 		if (memcmp(sp, ssp, len) != 0)
68558f0484fSRodney W. Grimes 			return(NULL);
68658f0484fSRodney W. Grimes 		while (m->g->strip[ss] != SOP(O_BACK, i))
68758f0484fSRodney W. Grimes 			ss++;
688082063a0SXin LI 		return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
68958f0484fSRodney W. Grimes 	case OQUEST_:		/* to null or not */
690082063a0SXin LI 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
69158f0484fSRodney W. Grimes 		if (dp != NULL)
69258f0484fSRodney W. Grimes 			return(dp);	/* not */
693082063a0SXin LI 		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
69458f0484fSRodney W. Grimes 	case OPLUS_:
69558f0484fSRodney W. Grimes 		assert(m->lastpos != NULL);
69658f0484fSRodney W. Grimes 		assert(lev+1 <= m->g->nplus);
69758f0484fSRodney W. Grimes 		m->lastpos[lev+1] = sp;
698082063a0SXin LI 		return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
69958f0484fSRodney W. Grimes 	case O_PLUS:
70058f0484fSRodney W. Grimes 		if (sp == m->lastpos[lev])	/* last pass matched null */
701082063a0SXin LI 			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
70258f0484fSRodney W. Grimes 		/* try another pass */
70358f0484fSRodney W. Grimes 		m->lastpos[lev] = sp;
704082063a0SXin LI 		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
70558f0484fSRodney W. Grimes 		if (dp == NULL)
706082063a0SXin LI 			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
70758f0484fSRodney W. Grimes 		else
70858f0484fSRodney W. Grimes 			return(dp);
70958f0484fSRodney W. Grimes 	case OCH_:		/* find the right one, if any */
71058f0484fSRodney W. Grimes 		ssub = ss + 1;
71158f0484fSRodney W. Grimes 		esub = ss + OPND(s) - 1;
71258f0484fSRodney W. Grimes 		assert(OP(m->g->strip[esub]) == OOR1);
71358f0484fSRodney W. Grimes 		for (;;) {	/* find first matching branch */
714082063a0SXin LI 			dp = backref(m, sp, stop, ssub, esub, lev, rec);
71558f0484fSRodney W. Grimes 			if (dp != NULL)
71658f0484fSRodney W. Grimes 				return(dp);
71758f0484fSRodney W. Grimes 			/* that one missed, try next one */
71858f0484fSRodney W. Grimes 			if (OP(m->g->strip[esub]) == O_CH)
71958f0484fSRodney W. Grimes 				return(NULL);	/* there is none */
72058f0484fSRodney W. Grimes 			esub++;
72158f0484fSRodney W. Grimes 			assert(OP(m->g->strip[esub]) == OOR2);
72258f0484fSRodney W. Grimes 			ssub = esub + 1;
72358f0484fSRodney W. Grimes 			esub += OPND(m->g->strip[esub]);
72458f0484fSRodney W. Grimes 			if (OP(m->g->strip[esub]) == OOR2)
72558f0484fSRodney W. Grimes 				esub--;
72658f0484fSRodney W. Grimes 			else
72758f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == O_CH);
72858f0484fSRodney W. Grimes 		}
729*eab20bceSPedro F. Giffuni 		/* NOTREACHED */
73058f0484fSRodney W. Grimes 		break;
73158f0484fSRodney W. Grimes 	case OLPAREN:		/* must undo assignment if rest fails */
73258f0484fSRodney W. Grimes 		i = OPND(s);
73358f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
73458f0484fSRodney W. Grimes 		offsave = m->pmatch[i].rm_so;
73558f0484fSRodney W. Grimes 		m->pmatch[i].rm_so = sp - m->offp;
736082063a0SXin LI 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
73758f0484fSRodney W. Grimes 		if (dp != NULL)
73858f0484fSRodney W. Grimes 			return(dp);
73958f0484fSRodney W. Grimes 		m->pmatch[i].rm_so = offsave;
74058f0484fSRodney W. Grimes 		return(NULL);
74158f0484fSRodney W. Grimes 	case ORPAREN:		/* must undo assignment if rest fails */
74258f0484fSRodney W. Grimes 		i = OPND(s);
74358f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
74458f0484fSRodney W. Grimes 		offsave = m->pmatch[i].rm_eo;
74558f0484fSRodney W. Grimes 		m->pmatch[i].rm_eo = sp - m->offp;
746082063a0SXin LI 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
74758f0484fSRodney W. Grimes 		if (dp != NULL)
74858f0484fSRodney W. Grimes 			return(dp);
74958f0484fSRodney W. Grimes 		m->pmatch[i].rm_eo = offsave;
75058f0484fSRodney W. Grimes 		return(NULL);
75158f0484fSRodney W. Grimes 	default:		/* uh oh */
75258f0484fSRodney W. Grimes 		assert(nope);
75358f0484fSRodney W. Grimes 		break;
75458f0484fSRodney W. Grimes 	}
75558f0484fSRodney W. Grimes 
75658f0484fSRodney W. Grimes 	/* "can't happen" */
75758f0484fSRodney W. Grimes 	assert(nope);
75858f0484fSRodney W. Grimes 	/* NOTREACHED */
75916252f11SPoul-Henning Kamp 	return "shut up gcc";
76058f0484fSRodney W. Grimes }
76158f0484fSRodney W. Grimes 
76258f0484fSRodney W. Grimes /*
76358f0484fSRodney W. Grimes  - fast - step through the string at top speed
764eb2b3d10SXin LI  == static const char *fast(struct match *m, const char *start, \
765eb2b3d10SXin LI  ==	const char *stop, sopno startst, sopno stopst);
76658f0484fSRodney W. Grimes  */
767eb2b3d10SXin LI static const char *		/* where tentative match ended, or NULL */
768eb2b3d10SXin LI fast(	struct match *m,
769eb2b3d10SXin LI 	const char *start,
770eb2b3d10SXin LI 	const char *stop,
771eb2b3d10SXin LI 	sopno startst,
772eb2b3d10SXin LI 	sopno stopst)
77358f0484fSRodney W. Grimes {
7748fb3f3f6SDavid E. O'Brien 	states st = m->st;
7758fb3f3f6SDavid E. O'Brien 	states fresh = m->fresh;
7768fb3f3f6SDavid E. O'Brien 	states tmp = m->tmp;
777eb2b3d10SXin LI 	const char *p = start;
778e5996857STim J. Robbins 	wint_t c;
779e5996857STim J. Robbins 	wint_t lastc;		/* previous c */
780e5996857STim J. Robbins 	wint_t flagch;
7818fb3f3f6SDavid E. O'Brien 	int i;
782eb2b3d10SXin LI 	const char *coldp;	/* last p after which no match was underway */
783e5996857STim J. Robbins 	size_t clen;
78458f0484fSRodney W. Grimes 
78558f0484fSRodney W. Grimes 	CLEAR(st);
78658f0484fSRodney W. Grimes 	SET1(st, startst);
787bca3476aSDiomidis Spinellis 	SP("fast", st, *p);
78858f0484fSRodney W. Grimes 	st = step(m->g, startst, stopst, st, NOTHING, st);
78958f0484fSRodney W. Grimes 	ASSIGN(fresh, st);
79058f0484fSRodney W. Grimes 	SP("start", st, *p);
79158f0484fSRodney W. Grimes 	coldp = NULL;
792e5996857STim J. Robbins 	if (start == m->beginp)
793e5996857STim J. Robbins 		c = OUT;
794e5996857STim J. Robbins 	else {
795e5996857STim J. Robbins 		/*
796e5996857STim J. Robbins 		 * XXX Wrong if the previous character was multi-byte.
797e5996857STim J. Robbins 		 * Newline never is (in encodings supported by FreeBSD),
798e5996857STim J. Robbins 		 * so this only breaks the ISWORD tests below.
799e5996857STim J. Robbins 		 */
800e5996857STim J. Robbins 		c = (uch)*(start - 1);
801e5996857STim J. Robbins 	}
80258f0484fSRodney W. Grimes 	for (;;) {
80358f0484fSRodney W. Grimes 		/* next character */
80458f0484fSRodney W. Grimes 		lastc = c;
8051ee0dbeeSTim J. Robbins 		if (p == m->endp) {
8061ee0dbeeSTim J. Robbins 			clen = 0;
807e5996857STim J. Robbins 			c = OUT;
8081ee0dbeeSTim J. Robbins 		} else
8091ee0dbeeSTim J. Robbins 			clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
81058f0484fSRodney W. Grimes 		if (EQ(st, fresh))
81158f0484fSRodney W. Grimes 			coldp = p;
81258f0484fSRodney W. Grimes 
81358f0484fSRodney W. Grimes 		/* is there an EOL and/or BOL between lastc and c? */
81458f0484fSRodney W. Grimes 		flagch = '\0';
81558f0484fSRodney W. Grimes 		i = 0;
81658f0484fSRodney W. Grimes 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
81758f0484fSRodney W. Grimes 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
81858f0484fSRodney W. Grimes 			flagch = BOL;
81958f0484fSRodney W. Grimes 			i = m->g->nbol;
82058f0484fSRodney W. Grimes 		}
82158f0484fSRodney W. Grimes 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
82258f0484fSRodney W. Grimes 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
82358f0484fSRodney W. Grimes 			flagch = (flagch == BOL) ? BOLEOL : EOL;
82458f0484fSRodney W. Grimes 			i += m->g->neol;
82558f0484fSRodney W. Grimes 		}
82658f0484fSRodney W. Grimes 		if (i != 0) {
82758f0484fSRodney W. Grimes 			for (; i > 0; i--)
82858f0484fSRodney W. Grimes 				st = step(m->g, startst, stopst, st, flagch, st);
82958f0484fSRodney W. Grimes 			SP("boleol", st, c);
83058f0484fSRodney W. Grimes 		}
83158f0484fSRodney W. Grimes 
83258f0484fSRodney W. Grimes 		/* how about a word boundary? */
83358f0484fSRodney W. Grimes 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
83458f0484fSRodney W. Grimes 					(c != OUT && ISWORD(c)) ) {
83558f0484fSRodney W. Grimes 			flagch = BOW;
83658f0484fSRodney W. Grimes 		}
83758f0484fSRodney W. Grimes 		if ( (lastc != OUT && ISWORD(lastc)) &&
83858f0484fSRodney W. Grimes 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
83958f0484fSRodney W. Grimes 			flagch = EOW;
84058f0484fSRodney W. Grimes 		}
84158f0484fSRodney W. Grimes 		if (flagch == BOW || flagch == EOW) {
84258f0484fSRodney W. Grimes 			st = step(m->g, startst, stopst, st, flagch, st);
84358f0484fSRodney W. Grimes 			SP("boweow", st, c);
84458f0484fSRodney W. Grimes 		}
84558f0484fSRodney W. Grimes 
84658f0484fSRodney W. Grimes 		/* are we done? */
8471ee0dbeeSTim J. Robbins 		if (ISSET(st, stopst) || p == stop || clen > stop - p)
84858f0484fSRodney W. Grimes 			break;		/* NOTE BREAK OUT */
84958f0484fSRodney W. Grimes 
85058f0484fSRodney W. Grimes 		/* no, we must deal with this character */
85158f0484fSRodney W. Grimes 		ASSIGN(tmp, st);
85258f0484fSRodney W. Grimes 		ASSIGN(st, fresh);
85358f0484fSRodney W. Grimes 		assert(c != OUT);
85458f0484fSRodney W. Grimes 		st = step(m->g, startst, stopst, tmp, c, st);
85558f0484fSRodney W. Grimes 		SP("aft", st, c);
85658f0484fSRodney W. Grimes 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
857e5996857STim J. Robbins 		p += clen;
85858f0484fSRodney W. Grimes 	}
85958f0484fSRodney W. Grimes 
86058f0484fSRodney W. Grimes 	assert(coldp != NULL);
86158f0484fSRodney W. Grimes 	m->coldp = coldp;
86258f0484fSRodney W. Grimes 	if (ISSET(st, stopst))
863bd9643b1STim J. Robbins 		return(p+XMBRTOWC(NULL, p, stop - p, &m->mbs, 0));
86458f0484fSRodney W. Grimes 	else
86558f0484fSRodney W. Grimes 		return(NULL);
86658f0484fSRodney W. Grimes }
86758f0484fSRodney W. Grimes 
86858f0484fSRodney W. Grimes /*
86958f0484fSRodney W. Grimes  - slow - step through the string more deliberately
870eb2b3d10SXin LI  == static const char *slow(struct match *m, const char *start, \
871eb2b3d10SXin LI  ==	const char *stop, sopno startst, sopno stopst);
87258f0484fSRodney W. Grimes  */
873eb2b3d10SXin LI static const char *		/* where it ended */
874eb2b3d10SXin LI slow(	struct match *m,
875eb2b3d10SXin LI 	const char *start,
876eb2b3d10SXin LI 	const char *stop,
877eb2b3d10SXin LI 	sopno startst,
878eb2b3d10SXin LI 	sopno stopst)
87958f0484fSRodney W. Grimes {
8808fb3f3f6SDavid E. O'Brien 	states st = m->st;
8818fb3f3f6SDavid E. O'Brien 	states empty = m->empty;
8828fb3f3f6SDavid E. O'Brien 	states tmp = m->tmp;
883eb2b3d10SXin LI 	const char *p = start;
884e5996857STim J. Robbins 	wint_t c;
885e5996857STim J. Robbins 	wint_t lastc;		/* previous c */
886e5996857STim J. Robbins 	wint_t flagch;
8878fb3f3f6SDavid E. O'Brien 	int i;
888eb2b3d10SXin LI 	const char *matchp;	/* last p at which a match ended */
889e5996857STim J. Robbins 	size_t clen;
89058f0484fSRodney W. Grimes 
89158f0484fSRodney W. Grimes 	AT("slow", start, stop, startst, stopst);
89258f0484fSRodney W. Grimes 	CLEAR(st);
89358f0484fSRodney W. Grimes 	SET1(st, startst);
89458f0484fSRodney W. Grimes 	SP("sstart", st, *p);
89558f0484fSRodney W. Grimes 	st = step(m->g, startst, stopst, st, NOTHING, st);
89658f0484fSRodney W. Grimes 	matchp = NULL;
897e5996857STim J. Robbins 	if (start == m->beginp)
898e5996857STim J. Robbins 		c = OUT;
899e5996857STim J. Robbins 	else {
900e5996857STim J. Robbins 		/*
901e5996857STim J. Robbins 		 * XXX Wrong if the previous character was multi-byte.
902e5996857STim J. Robbins 		 * Newline never is (in encodings supported by FreeBSD),
903e5996857STim J. Robbins 		 * so this only breaks the ISWORD tests below.
904e5996857STim J. Robbins 		 */
905e5996857STim J. Robbins 		c = (uch)*(start - 1);
906e5996857STim J. Robbins 	}
90758f0484fSRodney W. Grimes 	for (;;) {
90858f0484fSRodney W. Grimes 		/* next character */
90958f0484fSRodney W. Grimes 		lastc = c;
910e5996857STim J. Robbins 		if (p == m->endp) {
911e5996857STim J. Robbins 			c = OUT;
912e5996857STim J. Robbins 			clen = 0;
913e5996857STim J. Robbins 		} else
9141ee0dbeeSTim J. Robbins 			clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
91558f0484fSRodney W. Grimes 
91658f0484fSRodney W. Grimes 		/* is there an EOL and/or BOL between lastc and c? */
91758f0484fSRodney W. Grimes 		flagch = '\0';
91858f0484fSRodney W. Grimes 		i = 0;
91958f0484fSRodney W. Grimes 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
92058f0484fSRodney W. Grimes 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
92158f0484fSRodney W. Grimes 			flagch = BOL;
92258f0484fSRodney W. Grimes 			i = m->g->nbol;
92358f0484fSRodney W. Grimes 		}
92458f0484fSRodney W. Grimes 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
92558f0484fSRodney W. Grimes 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
92658f0484fSRodney W. Grimes 			flagch = (flagch == BOL) ? BOLEOL : EOL;
92758f0484fSRodney W. Grimes 			i += m->g->neol;
92858f0484fSRodney W. Grimes 		}
92958f0484fSRodney W. Grimes 		if (i != 0) {
93058f0484fSRodney W. Grimes 			for (; i > 0; i--)
93158f0484fSRodney W. Grimes 				st = step(m->g, startst, stopst, st, flagch, st);
93258f0484fSRodney W. Grimes 			SP("sboleol", st, c);
93358f0484fSRodney W. Grimes 		}
93458f0484fSRodney W. Grimes 
93558f0484fSRodney W. Grimes 		/* how about a word boundary? */
93658f0484fSRodney W. Grimes 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
93758f0484fSRodney W. Grimes 					(c != OUT && ISWORD(c)) ) {
93858f0484fSRodney W. Grimes 			flagch = BOW;
93958f0484fSRodney W. Grimes 		}
94058f0484fSRodney W. Grimes 		if ( (lastc != OUT && ISWORD(lastc)) &&
94158f0484fSRodney W. Grimes 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
94258f0484fSRodney W. Grimes 			flagch = EOW;
94358f0484fSRodney W. Grimes 		}
94458f0484fSRodney W. Grimes 		if (flagch == BOW || flagch == EOW) {
94558f0484fSRodney W. Grimes 			st = step(m->g, startst, stopst, st, flagch, st);
94658f0484fSRodney W. Grimes 			SP("sboweow", st, c);
94758f0484fSRodney W. Grimes 		}
94858f0484fSRodney W. Grimes 
94958f0484fSRodney W. Grimes 		/* are we done? */
95058f0484fSRodney W. Grimes 		if (ISSET(st, stopst))
95158f0484fSRodney W. Grimes 			matchp = p;
9521ee0dbeeSTim J. Robbins 		if (EQ(st, empty) || p == stop || clen > stop - p)
95358f0484fSRodney W. Grimes 			break;		/* NOTE BREAK OUT */
95458f0484fSRodney W. Grimes 
95558f0484fSRodney W. Grimes 		/* no, we must deal with this character */
95658f0484fSRodney W. Grimes 		ASSIGN(tmp, st);
95758f0484fSRodney W. Grimes 		ASSIGN(st, empty);
95858f0484fSRodney W. Grimes 		assert(c != OUT);
95958f0484fSRodney W. Grimes 		st = step(m->g, startst, stopst, tmp, c, st);
96058f0484fSRodney W. Grimes 		SP("saft", st, c);
96158f0484fSRodney W. Grimes 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
962e5996857STim J. Robbins 		p += clen;
96358f0484fSRodney W. Grimes 	}
96458f0484fSRodney W. Grimes 
96558f0484fSRodney W. Grimes 	return(matchp);
96658f0484fSRodney W. Grimes }
96758f0484fSRodney W. Grimes 
96858f0484fSRodney W. Grimes 
96958f0484fSRodney W. Grimes /*
97058f0484fSRodney W. Grimes  - step - map set of states reachable before char to set reachable after
9718fb3f3f6SDavid E. O'Brien  == static states step(struct re_guts *g, sopno start, sopno stop, \
9728fb3f3f6SDavid E. O'Brien  ==	states bef, int ch, states aft);
973e5996857STim J. Robbins  == #define	BOL	(OUT-1)
974e5996857STim J. Robbins  == #define	EOL	(BOL-1)
975e5996857STim J. Robbins  == #define	BOLEOL	(BOL-2)
976e5996857STim J. Robbins  == #define	NOTHING	(BOL-3)
977e5996857STim J. Robbins  == #define	BOW	(BOL-4)
978e5996857STim J. Robbins  == #define	EOW	(BOL-5)
979e5996857STim J. Robbins  == #define	BADCHAR	(BOL-6)
980e5996857STim J. Robbins  == #define	NONCHAR(c)	((c) <= OUT)
98158f0484fSRodney W. Grimes  */
98258f0484fSRodney W. Grimes static states
983eb2b3d10SXin LI step(struct re_guts *g,
984eb2b3d10SXin LI 	sopno start,		/* start state within strip */
985eb2b3d10SXin LI 	sopno stop,		/* state after stop state within strip */
986eb2b3d10SXin LI 	states bef,		/* states reachable before */
987eb2b3d10SXin LI 	wint_t ch,		/* character or NONCHAR code */
988eb2b3d10SXin LI 	states aft)		/* states already known reachable after */
98958f0484fSRodney W. Grimes {
9908fb3f3f6SDavid E. O'Brien 	cset *cs;
9918fb3f3f6SDavid E. O'Brien 	sop s;
9928fb3f3f6SDavid E. O'Brien 	sopno pc;
9938fb3f3f6SDavid E. O'Brien 	onestate here;		/* note, macros know this name */
9948fb3f3f6SDavid E. O'Brien 	sopno look;
9958fb3f3f6SDavid E. O'Brien 	int i;
99658f0484fSRodney W. Grimes 
99758f0484fSRodney W. Grimes 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
99858f0484fSRodney W. Grimes 		s = g->strip[pc];
99958f0484fSRodney W. Grimes 		switch (OP(s)) {
100058f0484fSRodney W. Grimes 		case OEND:
100158f0484fSRodney W. Grimes 			assert(pc == stop-1);
100258f0484fSRodney W. Grimes 			break;
100358f0484fSRodney W. Grimes 		case OCHAR:
100458f0484fSRodney W. Grimes 			/* only characters can match */
1005e5996857STim J. Robbins 			assert(!NONCHAR(ch) || ch != OPND(s));
1006e5996857STim J. Robbins 			if (ch == OPND(s))
100758f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
100858f0484fSRodney W. Grimes 			break;
100958f0484fSRodney W. Grimes 		case OBOL:
101058f0484fSRodney W. Grimes 			if (ch == BOL || ch == BOLEOL)
101158f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
101258f0484fSRodney W. Grimes 			break;
101358f0484fSRodney W. Grimes 		case OEOL:
101458f0484fSRodney W. Grimes 			if (ch == EOL || ch == BOLEOL)
101558f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
101658f0484fSRodney W. Grimes 			break;
101758f0484fSRodney W. Grimes 		case OBOW:
101858f0484fSRodney W. Grimes 			if (ch == BOW)
101958f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
102058f0484fSRodney W. Grimes 			break;
102158f0484fSRodney W. Grimes 		case OEOW:
102258f0484fSRodney W. Grimes 			if (ch == EOW)
102358f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
102458f0484fSRodney W. Grimes 			break;
102558f0484fSRodney W. Grimes 		case OANY:
102658f0484fSRodney W. Grimes 			if (!NONCHAR(ch))
102758f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
102858f0484fSRodney W. Grimes 			break;
102958f0484fSRodney W. Grimes 		case OANYOF:
103058f0484fSRodney W. Grimes 			cs = &g->sets[OPND(s)];
103158f0484fSRodney W. Grimes 			if (!NONCHAR(ch) && CHIN(cs, ch))
103258f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
103358f0484fSRodney W. Grimes 			break;
103458f0484fSRodney W. Grimes 		case OBACK_:		/* ignored here */
103558f0484fSRodney W. Grimes 		case O_BACK:
103658f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
103758f0484fSRodney W. Grimes 			break;
103858f0484fSRodney W. Grimes 		case OPLUS_:		/* forward, this is just an empty */
103958f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
104058f0484fSRodney W. Grimes 			break;
104158f0484fSRodney W. Grimes 		case O_PLUS:		/* both forward and back */
104258f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
104358f0484fSRodney W. Grimes 			i = ISSETBACK(aft, OPND(s));
104458f0484fSRodney W. Grimes 			BACK(aft, aft, OPND(s));
104558f0484fSRodney W. Grimes 			if (!i && ISSETBACK(aft, OPND(s))) {
104658f0484fSRodney W. Grimes 				/* oho, must reconsider loop body */
104758f0484fSRodney W. Grimes 				pc -= OPND(s) + 1;
104858f0484fSRodney W. Grimes 				INIT(here, pc);
104958f0484fSRodney W. Grimes 			}
105058f0484fSRodney W. Grimes 			break;
105158f0484fSRodney W. Grimes 		case OQUEST_:		/* two branches, both forward */
105258f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
105358f0484fSRodney W. Grimes 			FWD(aft, aft, OPND(s));
105458f0484fSRodney W. Grimes 			break;
105558f0484fSRodney W. Grimes 		case O_QUEST:		/* just an empty */
105658f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
105758f0484fSRodney W. Grimes 			break;
105858f0484fSRodney W. Grimes 		case OLPAREN:		/* not significant here */
105958f0484fSRodney W. Grimes 		case ORPAREN:
106058f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
106158f0484fSRodney W. Grimes 			break;
106258f0484fSRodney W. Grimes 		case OCH_:		/* mark the first two branches */
106358f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
106458f0484fSRodney W. Grimes 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
106558f0484fSRodney W. Grimes 			FWD(aft, aft, OPND(s));
106658f0484fSRodney W. Grimes 			break;
106758f0484fSRodney W. Grimes 		case OOR1:		/* done a branch, find the O_CH */
106858f0484fSRodney W. Grimes 			if (ISSTATEIN(aft, here)) {
106958f0484fSRodney W. Grimes 				for (look = 1;
107058f0484fSRodney W. Grimes 						OP(s = g->strip[pc+look]) != O_CH;
107158f0484fSRodney W. Grimes 						look += OPND(s))
107258f0484fSRodney W. Grimes 					assert(OP(s) == OOR2);
1073e7cbc6eeSDiomidis Spinellis 				FWD(aft, aft, look + 1);
107458f0484fSRodney W. Grimes 			}
107558f0484fSRodney W. Grimes 			break;
107658f0484fSRodney W. Grimes 		case OOR2:		/* propagate OCH_'s marking */
107758f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
107858f0484fSRodney W. Grimes 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
107958f0484fSRodney W. Grimes 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
108058f0484fSRodney W. Grimes 				FWD(aft, aft, OPND(s));
108158f0484fSRodney W. Grimes 			}
108258f0484fSRodney W. Grimes 			break;
108358f0484fSRodney W. Grimes 		case O_CH:		/* just empty */
108458f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
108558f0484fSRodney W. Grimes 			break;
108658f0484fSRodney W. Grimes 		default:		/* ooooops... */
108758f0484fSRodney W. Grimes 			assert(nope);
108858f0484fSRodney W. Grimes 			break;
108958f0484fSRodney W. Grimes 		}
109058f0484fSRodney W. Grimes 	}
109158f0484fSRodney W. Grimes 
109258f0484fSRodney W. Grimes 	return(aft);
109358f0484fSRodney W. Grimes }
109458f0484fSRodney W. Grimes 
109558f0484fSRodney W. Grimes #ifdef REDEBUG
109658f0484fSRodney W. Grimes /*
109758f0484fSRodney W. Grimes  - print - print a set of states
109858f0484fSRodney W. Grimes  == #ifdef REDEBUG
1099eb2b3d10SXin LI  == static void print(struct match *m, const char *caption, states st, \
110058f0484fSRodney W. Grimes  ==	int ch, FILE *d);
110158f0484fSRodney W. Grimes  == #endif
110258f0484fSRodney W. Grimes  */
110358f0484fSRodney W. Grimes static void
1104eb2b3d10SXin LI print(struct match *m,
1105eb2b3d10SXin LI 	const char *caption,
1106eb2b3d10SXin LI 	states st,
1107eb2b3d10SXin LI 	int ch,
1108eb2b3d10SXin LI 	FILE *d)
110958f0484fSRodney W. Grimes {
11108fb3f3f6SDavid E. O'Brien 	struct re_guts *g = m->g;
11118fb3f3f6SDavid E. O'Brien 	int i;
11128fb3f3f6SDavid E. O'Brien 	int first = 1;
111358f0484fSRodney W. Grimes 
111458f0484fSRodney W. Grimes 	if (!(m->eflags&REG_TRACE))
111558f0484fSRodney W. Grimes 		return;
111658f0484fSRodney W. Grimes 
111758f0484fSRodney W. Grimes 	fprintf(d, "%s", caption);
111858f0484fSRodney W. Grimes 	if (ch != '\0')
111958f0484fSRodney W. Grimes 		fprintf(d, " %s", pchar(ch));
112058f0484fSRodney W. Grimes 	for (i = 0; i < g->nstates; i++)
112158f0484fSRodney W. Grimes 		if (ISSET(st, i)) {
112258f0484fSRodney W. Grimes 			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
112358f0484fSRodney W. Grimes 			first = 0;
112458f0484fSRodney W. Grimes 		}
112558f0484fSRodney W. Grimes 	fprintf(d, "\n");
112658f0484fSRodney W. Grimes }
112758f0484fSRodney W. Grimes 
112858f0484fSRodney W. Grimes /*
112958f0484fSRodney W. Grimes  - at - print current situation
113058f0484fSRodney W. Grimes  == #ifdef REDEBUG
1131eb2b3d10SXin LI  == static void at(struct match *m, const char *title, const char *start, \
1132eb2b3d10SXin LI  ==			 const char *stop, sopno startst, sopno stopst);
113358f0484fSRodney W. Grimes  == #endif
113458f0484fSRodney W. Grimes  */
113558f0484fSRodney W. Grimes static void
1136eb2b3d10SXin LI at(	struct match *m,
1137eb2b3d10SXin LI 	const char *title,
1138eb2b3d10SXin LI 	const char *start,
1139eb2b3d10SXin LI 	const char *stop,
1140eb2b3d10SXin LI 	sopno startst,
1141eb2b3d10SXin LI 	sopno stopst)
114258f0484fSRodney W. Grimes {
114358f0484fSRodney W. Grimes 	if (!(m->eflags&REG_TRACE))
114458f0484fSRodney W. Grimes 		return;
114558f0484fSRodney W. Grimes 
114658f0484fSRodney W. Grimes 	printf("%s %s-", title, pchar(*start));
114758f0484fSRodney W. Grimes 	printf("%s ", pchar(*stop));
114858f0484fSRodney W. Grimes 	printf("%ld-%ld\n", (long)startst, (long)stopst);
114958f0484fSRodney W. Grimes }
115058f0484fSRodney W. Grimes 
115158f0484fSRodney W. Grimes #ifndef PCHARDONE
115258f0484fSRodney W. Grimes #define	PCHARDONE	/* never again */
115358f0484fSRodney W. Grimes /*
115458f0484fSRodney W. Grimes  - pchar - make a character printable
115558f0484fSRodney W. Grimes  == #ifdef REDEBUG
1156eb2b3d10SXin LI  == static const char *pchar(int ch);
115758f0484fSRodney W. Grimes  == #endif
115858f0484fSRodney W. Grimes  *
115958f0484fSRodney W. Grimes  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
116058f0484fSRodney W. Grimes  * duplicate here avoids having a debugging-capable regexec.o tied to
116158f0484fSRodney W. Grimes  * a matching debug.o, and this is convenient.  It all disappears in
116258f0484fSRodney W. Grimes  * the non-debug compilation anyway, so it doesn't matter much.
116358f0484fSRodney W. Grimes  */
1164eb2b3d10SXin LI static const char *		/* -> representation */
1165eb2b3d10SXin LI pchar(int ch)
116658f0484fSRodney W. Grimes {
116758f0484fSRodney W. Grimes 	static char pbuf[10];
116858f0484fSRodney W. Grimes 
1169b5363c4aSAndrey A. Chernov 	if (isprint((uch)ch) || ch == ' ')
117058f0484fSRodney W. Grimes 		sprintf(pbuf, "%c", ch);
117158f0484fSRodney W. Grimes 	else
117258f0484fSRodney W. Grimes 		sprintf(pbuf, "\\%o", ch);
117358f0484fSRodney W. Grimes 	return(pbuf);
117458f0484fSRodney W. Grimes }
117558f0484fSRodney W. Grimes #endif
117658f0484fSRodney W. Grimes #endif
117758f0484fSRodney W. Grimes 
117858f0484fSRodney W. Grimes #undef	matcher
117958f0484fSRodney W. Grimes #undef	fast
118058f0484fSRodney W. Grimes #undef	slow
118158f0484fSRodney W. Grimes #undef	dissect
118258f0484fSRodney W. Grimes #undef	backref
118358f0484fSRodney W. Grimes #undef	step
118458f0484fSRodney W. Grimes #undef	print
118558f0484fSRodney W. Grimes #undef	at
118658f0484fSRodney W. Grimes #undef	match
1187