xref: /openbsd-src/lib/libc/regex/engine.c (revision b6faad1a1d1550a09bf6ab1f65d45e3ffee10663)
1*b6faad1aSmillert /*	$OpenBSD: engine.c,v 1.26 2020/12/28 21:41:55 millert Exp $	*/
2442a6afdSmillert 
3df930be7Sderaadt /*-
4df930be7Sderaadt  * Copyright (c) 1992, 1993, 1994 Henry Spencer.
5df930be7Sderaadt  * Copyright (c) 1992, 1993, 1994
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Henry Spencer.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
196580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34442a6afdSmillert  *
35442a6afdSmillert  *	@(#)engine.c	8.5 (Berkeley) 3/20/94
36df930be7Sderaadt  */
37df930be7Sderaadt 
38df930be7Sderaadt /*
39df930be7Sderaadt  * The matching engine and friends.  This file is #included by regexec.c
40df930be7Sderaadt  * after suitable #defines of a variety of macros used herein, so that
41df930be7Sderaadt  * different state representations can be used without duplicating masses
42df930be7Sderaadt  * of code.
43df930be7Sderaadt  */
44df930be7Sderaadt 
45df930be7Sderaadt #ifdef SNAMES
46df930be7Sderaadt #define	matcher	smatcher
47df930be7Sderaadt #define	fast	sfast
48df930be7Sderaadt #define	slow	sslow
49df930be7Sderaadt #define	dissect	sdissect
50df930be7Sderaadt #define	backref	sbackref
51df930be7Sderaadt #define	step	sstep
52df930be7Sderaadt #define	print	sprint
53df930be7Sderaadt #define	at	sat
54df930be7Sderaadt #define	match	smat
555b9192c4Smillert #define	nope	snope
56df930be7Sderaadt #endif
57df930be7Sderaadt #ifdef LNAMES
58df930be7Sderaadt #define	matcher	lmatcher
59df930be7Sderaadt #define	fast	lfast
60df930be7Sderaadt #define	slow	lslow
61df930be7Sderaadt #define	dissect	ldissect
62df930be7Sderaadt #define	backref	lbackref
63df930be7Sderaadt #define	step	lstep
64df930be7Sderaadt #define	print	lprint
65df930be7Sderaadt #define	at	lat
66df930be7Sderaadt #define	match	lmat
675b9192c4Smillert #define	nope	lnope
68df930be7Sderaadt #endif
69df930be7Sderaadt 
70df930be7Sderaadt /* another structure passed up and down to avoid zillions of parameters */
71df930be7Sderaadt struct match {
72df930be7Sderaadt 	struct re_guts *g;
73df930be7Sderaadt 	int eflags;
74df930be7Sderaadt 	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
75d1a1db7fSmartijn 	const char *offp;	/* offsets work from here */
76d1a1db7fSmartijn 	const char *beginp;	/* start of string -- virtual NUL precedes */
77d1a1db7fSmartijn 	const char *endp;	/* end of string -- virtual NUL here */
78d1a1db7fSmartijn 	const char *coldp;	/* can be no match starting before here */
79d1a1db7fSmartijn 	const char **lastpos;	/* [nplus+1] */
80df930be7Sderaadt 	STATEVARS;
81df930be7Sderaadt 	states st;		/* current states */
82df930be7Sderaadt 	states fresh;		/* states for a fresh start */
83df930be7Sderaadt 	states tmp;		/* temporary */
84df930be7Sderaadt 	states empty;		/* empty set of states */
85df930be7Sderaadt };
86df930be7Sderaadt 
87d1a1db7fSmartijn static int matcher(struct re_guts *, const char *, size_t, regmatch_t[], int);
88d1a1db7fSmartijn static const char *dissect(struct match *, const char *, const char *, sopno,
89d1a1db7fSmartijn     sopno);
90d1a1db7fSmartijn static const char *backref(struct match *, const char *, const char *, sopno,
91d1a1db7fSmartijn     sopno, sopno, int);
92d1a1db7fSmartijn static const char *fast(struct match *, const char *, const char *, sopno,
93d1a1db7fSmartijn     sopno);
94d1a1db7fSmartijn static const char *slow(struct match *, const char *, const char *, sopno,
95d1a1db7fSmartijn     sopno);
96a1a76537Sotto static states step(struct re_guts *, sopno, sopno, states, int, states);
97991d2fffSotto #define MAX_RECURSION	100
98df930be7Sderaadt #define	BOL	(OUT+1)
99df930be7Sderaadt #define	EOL	(BOL+1)
100df930be7Sderaadt #define	BOLEOL	(BOL+2)
101df930be7Sderaadt #define	NOTHING	(BOL+3)
102df930be7Sderaadt #define	BOW	(BOL+4)
103df930be7Sderaadt #define	EOW	(BOL+5)
1040595d4dbSguenther /* update nonchars[] array below when adding fake chars here */
105df930be7Sderaadt #define	CODEMAX	(BOL+5)		/* highest code used */
106df930be7Sderaadt #define	NONCHAR(c)	((c) > CHAR_MAX)
107df930be7Sderaadt #define	NNONCHAR	(CODEMAX-CHAR_MAX)
108df930be7Sderaadt #ifdef REDEBUG
109d1a1db7fSmartijn static void print(struct match *, const char *, states, int, FILE *);
110df930be7Sderaadt #endif
111df930be7Sderaadt #ifdef REDEBUG
112d1a1db7fSmartijn static void at(struct match *, const char *, const char *, const char *,
113d1a1db7fSmartijn     sopno, sopno);
114df930be7Sderaadt #endif
115df930be7Sderaadt #ifdef REDEBUG
1160595d4dbSguenther static const char *pchar(int);
117df930be7Sderaadt #endif
118df930be7Sderaadt 
119df930be7Sderaadt #ifdef REDEBUG
120df930be7Sderaadt #define	SP(t, s, c)	print(m, t, s, c, stdout)
121df930be7Sderaadt #define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
122442a6afdSmillert #define	NOTE(str)	{ if (m->eflags&REG_TRACE) (void)printf("=%s\n", (str)); }
1235b9192c4Smillert static int nope = 0;
124df930be7Sderaadt #else
125df930be7Sderaadt #define	SP(t, s, c)	/* nothing */
126df930be7Sderaadt #define	AT(t, p1, p2, s1, s2)	/* nothing */
127df930be7Sderaadt #define	NOTE(s)	/* nothing */
128df930be7Sderaadt #endif
129df930be7Sderaadt 
130df930be7Sderaadt /*
131df930be7Sderaadt  - matcher - the actual matching engine
132df930be7Sderaadt  */
133df930be7Sderaadt static int			/* 0 success, REG_NOMATCH failure */
matcher(struct re_guts * g,const char * string,size_t nmatch,regmatch_t pmatch[],int eflags)134d1a1db7fSmartijn matcher(struct re_guts *g, const char *string, size_t nmatch,
135d1a1db7fSmartijn     regmatch_t pmatch[], int eflags)
136df930be7Sderaadt {
137d1a1db7fSmartijn 	const char *endp;
1383d7c72a1Sotto 	int i;
139df930be7Sderaadt 	struct match mv;
1403d7c72a1Sotto 	struct match *m = &mv;
141d1a1db7fSmartijn 	const char *dp;
1423d7c72a1Sotto 	const sopno gf = g->firststate+1;	/* +1 for OEND */
1433d7c72a1Sotto 	const sopno gl = g->laststate;
144d1a1db7fSmartijn 	const char *start;
145d1a1db7fSmartijn 	const char *stop;
146df930be7Sderaadt 
147df930be7Sderaadt 	/* simplify the situation where possible */
148df930be7Sderaadt 	if (g->cflags&REG_NOSUB)
149df930be7Sderaadt 		nmatch = 0;
150df930be7Sderaadt 	if (eflags&REG_STARTEND) {
151df930be7Sderaadt 		start = string + pmatch[0].rm_so;
152df930be7Sderaadt 		stop = string + pmatch[0].rm_eo;
153df930be7Sderaadt 	} else {
154df930be7Sderaadt 		start = string;
155df930be7Sderaadt 		stop = start + strlen(start);
156df930be7Sderaadt 	}
157df930be7Sderaadt 	if (stop < start)
158df930be7Sderaadt 		return(REG_INVARG);
159df930be7Sderaadt 
160df930be7Sderaadt 	/* prescreening; this does wonders for this rather slow code */
161df930be7Sderaadt 	if (g->must != NULL) {
162df930be7Sderaadt 		for (dp = start; dp < stop; dp++)
163df930be7Sderaadt 			if (*dp == g->must[0] && stop - dp >= g->mlen &&
1643240e6a8Sguenther 			    memcmp(dp, g->must, g->mlen) == 0)
165df930be7Sderaadt 				break;
166df930be7Sderaadt 		if (dp == stop)		/* we didn't find g->must */
167df930be7Sderaadt 			return(REG_NOMATCH);
168df930be7Sderaadt 	}
169df930be7Sderaadt 
170df930be7Sderaadt 	/* match struct setup */
171df930be7Sderaadt 	m->g = g;
172df930be7Sderaadt 	m->eflags = eflags;
173df930be7Sderaadt 	m->pmatch = NULL;
174df930be7Sderaadt 	m->lastpos = NULL;
175df930be7Sderaadt 	m->offp = string;
176df930be7Sderaadt 	m->beginp = start;
177df930be7Sderaadt 	m->endp = stop;
178df930be7Sderaadt 	STATESETUP(m, 4);
179df930be7Sderaadt 	SETUP(m->st);
180df930be7Sderaadt 	SETUP(m->fresh);
181df930be7Sderaadt 	SETUP(m->tmp);
182df930be7Sderaadt 	SETUP(m->empty);
183df930be7Sderaadt 	CLEAR(m->empty);
184df930be7Sderaadt 
185df930be7Sderaadt 	/* this loop does only one repetition except for backrefs */
186df930be7Sderaadt 	for (;;) {
187df930be7Sderaadt 		endp = fast(m, start, stop, gf, gl);
188df930be7Sderaadt 		if (endp == NULL) {		/* a miss */
189efc4ecacSotto 			free(m->pmatch);
190efc4ecacSotto 			free(m->lastpos);
191df930be7Sderaadt 			STATETEARDOWN(m);
192df930be7Sderaadt 			return(REG_NOMATCH);
193df930be7Sderaadt 		}
194df930be7Sderaadt 		if (nmatch == 0 && !g->backrefs)
195df930be7Sderaadt 			break;		/* no further info needed */
196df930be7Sderaadt 
197df930be7Sderaadt 		/* where? */
198df930be7Sderaadt 		assert(m->coldp != NULL);
199df930be7Sderaadt 		for (;;) {
200df930be7Sderaadt 			NOTE("finding start");
201df930be7Sderaadt 			endp = slow(m, m->coldp, stop, gf, gl);
202df930be7Sderaadt 			if (endp != NULL)
203df930be7Sderaadt 				break;
204df930be7Sderaadt 			assert(m->coldp < m->endp);
205df930be7Sderaadt 			m->coldp++;
206df930be7Sderaadt 		}
207df930be7Sderaadt 		if (nmatch == 1 && !g->backrefs)
208df930be7Sderaadt 			break;		/* no further info needed */
209df930be7Sderaadt 
210df930be7Sderaadt 		/* oh my, he wants the subexpressions... */
211df930be7Sderaadt 		if (m->pmatch == NULL)
212373c8319Sderaadt 			m->pmatch = reallocarray(NULL, m->g->nsub + 1,
213df930be7Sderaadt 			    sizeof(regmatch_t));
214df930be7Sderaadt 		if (m->pmatch == NULL) {
215df930be7Sderaadt 			STATETEARDOWN(m);
216df930be7Sderaadt 			return(REG_ESPACE);
217df930be7Sderaadt 		}
218df930be7Sderaadt 		for (i = 1; i <= m->g->nsub; i++)
219df930be7Sderaadt 			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
220df930be7Sderaadt 		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
221df930be7Sderaadt 			NOTE("dissecting");
222df930be7Sderaadt 			dp = dissect(m, m->coldp, endp, gf, gl);
223df930be7Sderaadt 		} else {
224df930be7Sderaadt 			if (g->nplus > 0 && m->lastpos == NULL)
225373c8319Sderaadt 				m->lastpos = reallocarray(NULL,
226373c8319Sderaadt 				    g->nplus+1, sizeof(char *));
227df930be7Sderaadt 			if (g->nplus > 0 && m->lastpos == NULL) {
228df930be7Sderaadt 				free(m->pmatch);
229df930be7Sderaadt 				STATETEARDOWN(m);
230df930be7Sderaadt 				return(REG_ESPACE);
231df930be7Sderaadt 			}
232df930be7Sderaadt 			NOTE("backref dissect");
233991d2fffSotto 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
234df930be7Sderaadt 		}
235df930be7Sderaadt 		if (dp != NULL)
236df930be7Sderaadt 			break;
237df930be7Sderaadt 
238df930be7Sderaadt 		/* uh-oh... we couldn't find a subexpression-level match */
239df930be7Sderaadt 		assert(g->backrefs);	/* must be back references doing it */
240df930be7Sderaadt 		assert(g->nplus == 0 || m->lastpos != NULL);
241df930be7Sderaadt 		for (;;) {
242df930be7Sderaadt 			if (dp != NULL || endp <= m->coldp)
243df930be7Sderaadt 				break;		/* defeat */
244df930be7Sderaadt 			NOTE("backoff");
245df930be7Sderaadt 			endp = slow(m, m->coldp, endp-1, gf, gl);
246df930be7Sderaadt 			if (endp == NULL)
247df930be7Sderaadt 				break;		/* defeat */
248df930be7Sderaadt 			/* try it on a shorter possibility */
249df930be7Sderaadt #ifndef NDEBUG
250df930be7Sderaadt 			for (i = 1; i <= m->g->nsub; i++) {
251df930be7Sderaadt 				assert(m->pmatch[i].rm_so == -1);
252df930be7Sderaadt 				assert(m->pmatch[i].rm_eo == -1);
253df930be7Sderaadt 			}
254df930be7Sderaadt #endif
255df930be7Sderaadt 			NOTE("backoff dissect");
256991d2fffSotto 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
257df930be7Sderaadt 		}
258df930be7Sderaadt 		assert(dp == NULL || dp == endp);
259df930be7Sderaadt 		if (dp != NULL)		/* found a shorter one */
260df930be7Sderaadt 			break;
261df930be7Sderaadt 
262df930be7Sderaadt 		/* despite initial appearances, there is no match here */
263df930be7Sderaadt 		NOTE("false alarm");
264cb95f7c6Smillert 		if (m->coldp == stop)
265cb95f7c6Smillert 			break;
266df930be7Sderaadt 		start = m->coldp + 1;	/* recycle starting later */
267df930be7Sderaadt 	}
268df930be7Sderaadt 
269df930be7Sderaadt 	/* fill in the details if requested */
270df930be7Sderaadt 	if (nmatch > 0) {
271df930be7Sderaadt 		pmatch[0].rm_so = m->coldp - m->offp;
272df930be7Sderaadt 		pmatch[0].rm_eo = endp - m->offp;
273df930be7Sderaadt 	}
274df930be7Sderaadt 	if (nmatch > 1) {
275df930be7Sderaadt 		assert(m->pmatch != NULL);
276df930be7Sderaadt 		for (i = 1; i < nmatch; i++)
277df930be7Sderaadt 			if (i <= m->g->nsub)
278df930be7Sderaadt 				pmatch[i] = m->pmatch[i];
279df930be7Sderaadt 			else {
280df930be7Sderaadt 				pmatch[i].rm_so = -1;
281df930be7Sderaadt 				pmatch[i].rm_eo = -1;
282df930be7Sderaadt 			}
283df930be7Sderaadt 	}
284df930be7Sderaadt 
285101bb365Smmcc 	free(m->pmatch);
286101bb365Smmcc 	free(m->lastpos);
287df930be7Sderaadt 	STATETEARDOWN(m);
288df930be7Sderaadt 	return(0);
289df930be7Sderaadt }
290df930be7Sderaadt 
291df930be7Sderaadt /*
292df930be7Sderaadt  - dissect - figure out what matched what, no back references
293df930be7Sderaadt  */
294d1a1db7fSmartijn static const char *		/* == stop (success) always */
dissect(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst)295d1a1db7fSmartijn dissect(struct match *m, const char *start, const char *stop, sopno startst,
296d1a1db7fSmartijn     sopno stopst)
297df930be7Sderaadt {
2983d7c72a1Sotto 	int i;
2993d7c72a1Sotto 	sopno ss;		/* start sop of current subRE */
3003d7c72a1Sotto 	sopno es;		/* end sop of current subRE */
301d1a1db7fSmartijn 	const char *sp;		/* start of string matched by it */
302d1a1db7fSmartijn 	const char *stp;	/* string matched by it cannot pass here */
303d1a1db7fSmartijn 	const char *rest;	/* start of rest of string */
304d1a1db7fSmartijn 	const char *tail;	/* string unmatched by rest of RE */
3053d7c72a1Sotto 	sopno ssub;		/* start sop of subsubRE */
3063d7c72a1Sotto 	sopno esub;		/* end sop of subsubRE */
307d1a1db7fSmartijn 	const char *ssp;	/* start of string matched by subsubRE */
308d1a1db7fSmartijn 	const char *sep;	/* end of string matched by subsubRE */
309d1a1db7fSmartijn 	const char *oldssp;	/* previous ssp */
310d1a1db7fSmartijn 	const char *dp;
311df930be7Sderaadt 
312df930be7Sderaadt 	AT("diss", start, stop, startst, stopst);
313df930be7Sderaadt 	sp = start;
314df930be7Sderaadt 	for (ss = startst; ss < stopst; ss = es) {
315df930be7Sderaadt 		/* identify end of subRE */
316df930be7Sderaadt 		es = ss;
317df930be7Sderaadt 		switch (OP(m->g->strip[es])) {
318df930be7Sderaadt 		case OPLUS_:
319df930be7Sderaadt 		case OQUEST_:
320df930be7Sderaadt 			es += OPND(m->g->strip[es]);
321df930be7Sderaadt 			break;
322df930be7Sderaadt 		case OCH_:
323df930be7Sderaadt 			while (OP(m->g->strip[es]) != O_CH)
324df930be7Sderaadt 				es += OPND(m->g->strip[es]);
325df930be7Sderaadt 			break;
326df930be7Sderaadt 		}
327df930be7Sderaadt 		es++;
328df930be7Sderaadt 
329df930be7Sderaadt 		/* figure out what it matched */
330df930be7Sderaadt 		switch (OP(m->g->strip[ss])) {
331df930be7Sderaadt 		case OEND:
332df930be7Sderaadt 			assert(nope);
333df930be7Sderaadt 			break;
334df930be7Sderaadt 		case OCHAR:
335df930be7Sderaadt 			sp++;
336df930be7Sderaadt 			break;
337df930be7Sderaadt 		case OBOL:
338df930be7Sderaadt 		case OEOL:
339df930be7Sderaadt 		case OBOW:
340df930be7Sderaadt 		case OEOW:
341df930be7Sderaadt 			break;
342df930be7Sderaadt 		case OANY:
343df930be7Sderaadt 		case OANYOF:
344df930be7Sderaadt 			sp++;
345df930be7Sderaadt 			break;
346df930be7Sderaadt 		case OBACK_:
347df930be7Sderaadt 		case O_BACK:
348df930be7Sderaadt 			assert(nope);
349df930be7Sderaadt 			break;
350df930be7Sderaadt 		/* cases where length of match is hard to find */
351df930be7Sderaadt 		case OQUEST_:
352df930be7Sderaadt 			stp = stop;
353df930be7Sderaadt 			for (;;) {
354df930be7Sderaadt 				/* how long could this one be? */
355df930be7Sderaadt 				rest = slow(m, sp, stp, ss, es);
356df930be7Sderaadt 				assert(rest != NULL);	/* it did match */
357df930be7Sderaadt 				/* could the rest match the rest? */
358df930be7Sderaadt 				tail = slow(m, rest, stop, es, stopst);
359df930be7Sderaadt 				if (tail == stop)
360df930be7Sderaadt 					break;		/* yes! */
361df930be7Sderaadt 				/* no -- try a shorter match for this one */
362df930be7Sderaadt 				stp = rest - 1;
363df930be7Sderaadt 				assert(stp >= sp);	/* it did work */
364df930be7Sderaadt 			}
365df930be7Sderaadt 			ssub = ss + 1;
366df930be7Sderaadt 			esub = es - 1;
367df930be7Sderaadt 			/* did innards match? */
368df930be7Sderaadt 			if (slow(m, sp, rest, ssub, esub) != NULL) {
369df930be7Sderaadt 				dp = dissect(m, sp, rest, ssub, esub);
370df930be7Sderaadt 				assert(dp == rest);
371df930be7Sderaadt 			} else		/* no */
372df930be7Sderaadt 				assert(sp == rest);
373df930be7Sderaadt 			sp = rest;
374df930be7Sderaadt 			break;
375df930be7Sderaadt 		case OPLUS_:
376df930be7Sderaadt 			stp = stop;
377df930be7Sderaadt 			for (;;) {
378df930be7Sderaadt 				/* how long could this one be? */
379df930be7Sderaadt 				rest = slow(m, sp, stp, ss, es);
380df930be7Sderaadt 				assert(rest != NULL);	/* it did match */
381df930be7Sderaadt 				/* could the rest match the rest? */
382df930be7Sderaadt 				tail = slow(m, rest, stop, es, stopst);
383df930be7Sderaadt 				if (tail == stop)
384df930be7Sderaadt 					break;		/* yes! */
385df930be7Sderaadt 				/* no -- try a shorter match for this one */
386df930be7Sderaadt 				stp = rest - 1;
387df930be7Sderaadt 				assert(stp >= sp);	/* it did work */
388df930be7Sderaadt 			}
389df930be7Sderaadt 			ssub = ss + 1;
390df930be7Sderaadt 			esub = es - 1;
391df930be7Sderaadt 			ssp = sp;
392df930be7Sderaadt 			oldssp = ssp;
393df930be7Sderaadt 			for (;;) {	/* find last match of innards */
394df930be7Sderaadt 				sep = slow(m, ssp, rest, ssub, esub);
395df930be7Sderaadt 				if (sep == NULL || sep == ssp)
396df930be7Sderaadt 					break;	/* failed or matched null */
397df930be7Sderaadt 				oldssp = ssp;	/* on to next try */
398df930be7Sderaadt 				ssp = sep;
399df930be7Sderaadt 			}
400df930be7Sderaadt 			if (sep == NULL) {
401df930be7Sderaadt 				/* last successful match */
402df930be7Sderaadt 				sep = ssp;
403df930be7Sderaadt 				ssp = oldssp;
404df930be7Sderaadt 			}
405df930be7Sderaadt 			assert(sep == rest);	/* must exhaust substring */
406df930be7Sderaadt 			assert(slow(m, ssp, sep, ssub, esub) == rest);
407df930be7Sderaadt 			dp = dissect(m, ssp, sep, ssub, esub);
408df930be7Sderaadt 			assert(dp == sep);
409df930be7Sderaadt 			sp = rest;
410df930be7Sderaadt 			break;
411df930be7Sderaadt 		case OCH_:
412df930be7Sderaadt 			stp = stop;
413df930be7Sderaadt 			for (;;) {
414df930be7Sderaadt 				/* how long could this one be? */
415df930be7Sderaadt 				rest = slow(m, sp, stp, ss, es);
416df930be7Sderaadt 				assert(rest != NULL);	/* it did match */
417df930be7Sderaadt 				/* could the rest match the rest? */
418df930be7Sderaadt 				tail = slow(m, rest, stop, es, stopst);
419df930be7Sderaadt 				if (tail == stop)
420df930be7Sderaadt 					break;		/* yes! */
421df930be7Sderaadt 				/* no -- try a shorter match for this one */
422df930be7Sderaadt 				stp = rest - 1;
423df930be7Sderaadt 				assert(stp >= sp);	/* it did work */
424df930be7Sderaadt 			}
425df930be7Sderaadt 			ssub = ss + 1;
426df930be7Sderaadt 			esub = ss + OPND(m->g->strip[ss]) - 1;
427df930be7Sderaadt 			assert(OP(m->g->strip[esub]) == OOR1);
428df930be7Sderaadt 			for (;;) {	/* find first matching branch */
429df930be7Sderaadt 				if (slow(m, sp, rest, ssub, esub) == rest)
430df930be7Sderaadt 					break;	/* it matched all of it */
431df930be7Sderaadt 				/* that one missed, try next one */
432df930be7Sderaadt 				assert(OP(m->g->strip[esub]) == OOR1);
433df930be7Sderaadt 				esub++;
434df930be7Sderaadt 				assert(OP(m->g->strip[esub]) == OOR2);
435df930be7Sderaadt 				ssub = esub + 1;
436df930be7Sderaadt 				esub += OPND(m->g->strip[esub]);
437df930be7Sderaadt 				if (OP(m->g->strip[esub]) == OOR2)
438df930be7Sderaadt 					esub--;
439df930be7Sderaadt 				else
440df930be7Sderaadt 					assert(OP(m->g->strip[esub]) == O_CH);
441df930be7Sderaadt 			}
442df930be7Sderaadt 			dp = dissect(m, sp, rest, ssub, esub);
443df930be7Sderaadt 			assert(dp == rest);
444df930be7Sderaadt 			sp = rest;
445df930be7Sderaadt 			break;
446df930be7Sderaadt 		case O_PLUS:
447df930be7Sderaadt 		case O_QUEST:
448df930be7Sderaadt 		case OOR1:
449df930be7Sderaadt 		case OOR2:
450df930be7Sderaadt 		case O_CH:
451df930be7Sderaadt 			assert(nope);
452df930be7Sderaadt 			break;
453df930be7Sderaadt 		case OLPAREN:
454df930be7Sderaadt 			i = OPND(m->g->strip[ss]);
455df930be7Sderaadt 			assert(0 < i && i <= m->g->nsub);
456df930be7Sderaadt 			m->pmatch[i].rm_so = sp - m->offp;
457df930be7Sderaadt 			break;
458df930be7Sderaadt 		case ORPAREN:
459df930be7Sderaadt 			i = OPND(m->g->strip[ss]);
460df930be7Sderaadt 			assert(0 < i && i <= m->g->nsub);
461df930be7Sderaadt 			m->pmatch[i].rm_eo = sp - m->offp;
462df930be7Sderaadt 			break;
463df930be7Sderaadt 		default:		/* uh oh */
464df930be7Sderaadt 			assert(nope);
465df930be7Sderaadt 			break;
466df930be7Sderaadt 		}
467df930be7Sderaadt 	}
468df930be7Sderaadt 
469df930be7Sderaadt 	assert(sp == stop);
470df930be7Sderaadt 	return(sp);
471df930be7Sderaadt }
472df930be7Sderaadt 
473df930be7Sderaadt /*
474df930be7Sderaadt  - backref - figure out what matched what, figuring in back references
475df930be7Sderaadt  */
476d1a1db7fSmartijn static const char *		/* == stop (success) or NULL (failure) */
backref(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst,sopno lev,int rec)477d1a1db7fSmartijn backref(struct match *m, const char *start, const char *stop, sopno startst,
478d1a1db7fSmartijn     sopno stopst, sopno lev, int rec)			/* PLUS nesting level */
479df930be7Sderaadt {
4803d7c72a1Sotto 	int i;
4813d7c72a1Sotto 	sopno ss;	/* start sop of current subRE */
482d1a1db7fSmartijn 	const char *sp;	/* start of string matched by it */
4833d7c72a1Sotto 	sopno ssub;	/* start sop of subsubRE */
4843d7c72a1Sotto 	sopno esub;	/* end sop of subsubRE */
485d1a1db7fSmartijn 	const char *ssp;/* start of string matched by subsubRE */
486d1a1db7fSmartijn 	const char *dp;
4873d7c72a1Sotto 	size_t len;
4883d7c72a1Sotto 	int hard;
4893d7c72a1Sotto 	sop s;
4903d7c72a1Sotto 	regoff_t offsave;
4913d7c72a1Sotto 	cset *cs;
492df930be7Sderaadt 
493df930be7Sderaadt 	AT("back", start, stop, startst, stopst);
494df930be7Sderaadt 	sp = start;
495df930be7Sderaadt 
496df930be7Sderaadt 	/* get as far as we can with easy stuff */
497df930be7Sderaadt 	hard = 0;
498df930be7Sderaadt 	for (ss = startst; !hard && ss < stopst; ss++)
499df930be7Sderaadt 		switch (OP(s = m->g->strip[ss])) {
500df930be7Sderaadt 		case OCHAR:
501df930be7Sderaadt 			if (sp == stop || *sp++ != (char)OPND(s))
502df930be7Sderaadt 				return(NULL);
503df930be7Sderaadt 			break;
504df930be7Sderaadt 		case OANY:
505df930be7Sderaadt 			if (sp == stop)
506df930be7Sderaadt 				return(NULL);
507df930be7Sderaadt 			sp++;
508df930be7Sderaadt 			break;
509df930be7Sderaadt 		case OANYOF:
510df930be7Sderaadt 			cs = &m->g->sets[OPND(s)];
511df930be7Sderaadt 			if (sp == stop || !CHIN(cs, *sp++))
512df930be7Sderaadt 				return(NULL);
513df930be7Sderaadt 			break;
514df930be7Sderaadt 		case OBOL:
515df930be7Sderaadt 			if ((sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
5163465aa04Sschwarze 			    (sp > m->offp && sp < m->endp &&
5173465aa04Sschwarze 			     *(sp-1) == '\n' && (m->g->cflags&REG_NEWLINE)))
518df930be7Sderaadt 				{ /* yes */ }
519df930be7Sderaadt 			else
520df930be7Sderaadt 				return(NULL);
521df930be7Sderaadt 			break;
522df930be7Sderaadt 		case OEOL:
523df930be7Sderaadt 			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
524df930be7Sderaadt 					(sp < m->endp && *sp == '\n' &&
525df930be7Sderaadt 						(m->g->cflags&REG_NEWLINE)) )
526df930be7Sderaadt 				{ /* yes */ }
527df930be7Sderaadt 			else
528df930be7Sderaadt 				return(NULL);
529df930be7Sderaadt 			break;
530df930be7Sderaadt 		case OBOW:
5311ca78303Sschwarze 			if (sp < m->endp && ISWORD(*sp) &&
5321ca78303Sschwarze 			    ((sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
5331ca78303Sschwarze 			     (sp > m->offp && !ISWORD(*(sp-1)))))
534df930be7Sderaadt 				{ /* yes */ }
535df930be7Sderaadt 			else
536df930be7Sderaadt 				return(NULL);
537df930be7Sderaadt 			break;
538df930be7Sderaadt 		case OEOW:
539df930be7Sderaadt 			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
540df930be7Sderaadt 					(sp < m->endp && *sp == '\n' &&
541df930be7Sderaadt 						(m->g->cflags&REG_NEWLINE)) ||
542df930be7Sderaadt 					(sp < m->endp && !ISWORD(*sp)) ) &&
543df930be7Sderaadt 					(sp > m->beginp && ISWORD(*(sp-1))) )
544df930be7Sderaadt 				{ /* yes */ }
545df930be7Sderaadt 			else
546df930be7Sderaadt 				return(NULL);
547df930be7Sderaadt 			break;
548df930be7Sderaadt 		case O_QUEST:
549df930be7Sderaadt 			break;
550df930be7Sderaadt 		case OOR1:	/* matches null but needs to skip */
551df930be7Sderaadt 			ss++;
552df930be7Sderaadt 			s = m->g->strip[ss];
553df930be7Sderaadt 			do {
554df930be7Sderaadt 				assert(OP(s) == OOR2);
555df930be7Sderaadt 				ss += OPND(s);
556df930be7Sderaadt 			} while (OP(s = m->g->strip[ss]) != O_CH);
557df930be7Sderaadt 			/* note that the ss++ gets us past the O_CH */
558df930be7Sderaadt 			break;
559df930be7Sderaadt 		default:	/* have to make a choice */
560df930be7Sderaadt 			hard = 1;
561df930be7Sderaadt 			break;
562df930be7Sderaadt 		}
563df930be7Sderaadt 	if (!hard) {		/* that was it! */
564df930be7Sderaadt 		if (sp != stop)
565df930be7Sderaadt 			return(NULL);
566df930be7Sderaadt 		return(sp);
567df930be7Sderaadt 	}
568df930be7Sderaadt 	ss--;			/* adjust for the for's final increment */
569df930be7Sderaadt 
570df930be7Sderaadt 	/* the hard stuff */
571df930be7Sderaadt 	AT("hard", sp, stop, ss, stopst);
572df930be7Sderaadt 	s = m->g->strip[ss];
573df930be7Sderaadt 	switch (OP(s)) {
574df930be7Sderaadt 	case OBACK_:		/* the vilest depths */
575df930be7Sderaadt 		i = OPND(s);
576df930be7Sderaadt 		assert(0 < i && i <= m->g->nsub);
577df930be7Sderaadt 		if (m->pmatch[i].rm_eo == -1)
578df930be7Sderaadt 			return(NULL);
579df930be7Sderaadt 		assert(m->pmatch[i].rm_so != -1);
580df930be7Sderaadt 		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
581991d2fffSotto 		if (len == 0 && rec++ > MAX_RECURSION)
5822617cd22Sotto 			return(NULL);
583df930be7Sderaadt 		assert(stop - m->beginp >= len);
584df930be7Sderaadt 		if (sp > stop - len)
585df930be7Sderaadt 			return(NULL);	/* not enough left to match */
586df930be7Sderaadt 		ssp = m->offp + m->pmatch[i].rm_so;
587df930be7Sderaadt 		if (memcmp(sp, ssp, len) != 0)
588df930be7Sderaadt 			return(NULL);
589df930be7Sderaadt 		while (m->g->strip[ss] != SOP(O_BACK, i))
590df930be7Sderaadt 			ss++;
591991d2fffSotto 		return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
592df930be7Sderaadt 		break;
593df930be7Sderaadt 	case OQUEST_:		/* to null or not */
594991d2fffSotto 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
595df930be7Sderaadt 		if (dp != NULL)
596df930be7Sderaadt 			return(dp);	/* not */
597991d2fffSotto 		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
598df930be7Sderaadt 		break;
599df930be7Sderaadt 	case OPLUS_:
600df930be7Sderaadt 		assert(m->lastpos != NULL);
601df930be7Sderaadt 		assert(lev+1 <= m->g->nplus);
602df930be7Sderaadt 		m->lastpos[lev+1] = sp;
603991d2fffSotto 		return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
604df930be7Sderaadt 		break;
605df930be7Sderaadt 	case O_PLUS:
606df930be7Sderaadt 		if (sp == m->lastpos[lev])	/* last pass matched null */
607991d2fffSotto 			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
608df930be7Sderaadt 		/* try another pass */
609df930be7Sderaadt 		m->lastpos[lev] = sp;
610991d2fffSotto 		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
611df930be7Sderaadt 		if (dp == NULL)
612991d2fffSotto 			return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
613df930be7Sderaadt 		else
614df930be7Sderaadt 			return(dp);
615df930be7Sderaadt 		break;
616df930be7Sderaadt 	case OCH_:		/* find the right one, if any */
617df930be7Sderaadt 		ssub = ss + 1;
618df930be7Sderaadt 		esub = ss + OPND(s) - 1;
619df930be7Sderaadt 		assert(OP(m->g->strip[esub]) == OOR1);
620df930be7Sderaadt 		for (;;) {	/* find first matching branch */
621991d2fffSotto 			dp = backref(m, sp, stop, ssub, esub, lev, rec);
622df930be7Sderaadt 			if (dp != NULL)
623df930be7Sderaadt 				return(dp);
624df930be7Sderaadt 			/* that one missed, try next one */
625df930be7Sderaadt 			if (OP(m->g->strip[esub]) == O_CH)
626df930be7Sderaadt 				return(NULL);	/* there is none */
627df930be7Sderaadt 			esub++;
628df930be7Sderaadt 			assert(OP(m->g->strip[esub]) == OOR2);
629df930be7Sderaadt 			ssub = esub + 1;
630df930be7Sderaadt 			esub += OPND(m->g->strip[esub]);
631df930be7Sderaadt 			if (OP(m->g->strip[esub]) == OOR2)
632df930be7Sderaadt 				esub--;
633df930be7Sderaadt 			else
634df930be7Sderaadt 				assert(OP(m->g->strip[esub]) == O_CH);
635df930be7Sderaadt 		}
636df930be7Sderaadt 		break;
637df930be7Sderaadt 	case OLPAREN:		/* must undo assignment if rest fails */
638df930be7Sderaadt 		i = OPND(s);
639df930be7Sderaadt 		assert(0 < i && i <= m->g->nsub);
640df930be7Sderaadt 		offsave = m->pmatch[i].rm_so;
641df930be7Sderaadt 		m->pmatch[i].rm_so = sp - m->offp;
642991d2fffSotto 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
643df930be7Sderaadt 		if (dp != NULL)
644df930be7Sderaadt 			return(dp);
645df930be7Sderaadt 		m->pmatch[i].rm_so = offsave;
646df930be7Sderaadt 		return(NULL);
647df930be7Sderaadt 		break;
648df930be7Sderaadt 	case ORPAREN:		/* must undo assignment if rest fails */
649df930be7Sderaadt 		i = OPND(s);
650df930be7Sderaadt 		assert(0 < i && i <= m->g->nsub);
651df930be7Sderaadt 		offsave = m->pmatch[i].rm_eo;
652df930be7Sderaadt 		m->pmatch[i].rm_eo = sp - m->offp;
653991d2fffSotto 		dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
654df930be7Sderaadt 		if (dp != NULL)
655df930be7Sderaadt 			return(dp);
656df930be7Sderaadt 		m->pmatch[i].rm_eo = offsave;
657df930be7Sderaadt 		return(NULL);
658df930be7Sderaadt 		break;
659df930be7Sderaadt 	default:		/* uh oh */
660df930be7Sderaadt 		assert(nope);
661df930be7Sderaadt 		break;
662df930be7Sderaadt 	}
663df930be7Sderaadt 
664df930be7Sderaadt 	/* "can't happen" */
665df930be7Sderaadt 	assert(nope);
666df930be7Sderaadt 	/* NOTREACHED */
6672be36617Stedu 	return NULL;
668df930be7Sderaadt }
669df930be7Sderaadt 
670df930be7Sderaadt /*
671df930be7Sderaadt  - fast - step through the string at top speed
672df930be7Sderaadt  */
673d1a1db7fSmartijn static const char *			/* where tentative match ended, or NULL */
fast(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst)674d1a1db7fSmartijn fast(struct match *m, const char *start, const char *stop, sopno startst,
675d1a1db7fSmartijn     sopno stopst)
676df930be7Sderaadt {
6773d7c72a1Sotto 	states st = m->st;
6783d7c72a1Sotto 	states fresh = m->fresh;
6793d7c72a1Sotto 	states tmp = m->tmp;
680d1a1db7fSmartijn 	const char *p = start;
681e315dedfSmartijn 	int c;
6823d7c72a1Sotto 	int lastc;		/* previous c */
6833d7c72a1Sotto 	int flagch;
6843d7c72a1Sotto 	int i;
685d1a1db7fSmartijn 	const char *coldp;	/* last p after which no match was underway */
686df930be7Sderaadt 
687e315dedfSmartijn 	if (start == m->offp || (start == m->beginp && !(m->eflags&REG_NOTBOL)))
688e315dedfSmartijn 		c = OUT;
689e315dedfSmartijn 	else
690e315dedfSmartijn 		c = *(start-1);
691e315dedfSmartijn 
692df930be7Sderaadt 	CLEAR(st);
693df930be7Sderaadt 	SET1(st, startst);
694df930be7Sderaadt 	st = step(m->g, startst, stopst, st, NOTHING, st);
695df930be7Sderaadt 	ASSIGN(fresh, st);
696df930be7Sderaadt 	SP("start", st, *p);
697df930be7Sderaadt 	coldp = NULL;
698df930be7Sderaadt 	for (;;) {
699df930be7Sderaadt 		/* next character */
700df930be7Sderaadt 		lastc = c;
701df930be7Sderaadt 		c = (p == m->endp) ? OUT : *p;
702df930be7Sderaadt 		if (EQ(st, fresh))
703df930be7Sderaadt 			coldp = p;
704df930be7Sderaadt 
705df930be7Sderaadt 		/* is there an EOL and/or BOL between lastc and c? */
706df930be7Sderaadt 		flagch = '\0';
707df930be7Sderaadt 		i = 0;
708df930be7Sderaadt 		if ((lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
709df930be7Sderaadt 		    (lastc == OUT && !(m->eflags&REG_NOTBOL))) {
710df930be7Sderaadt 			flagch = BOL;
711df930be7Sderaadt 			i = m->g->nbol;
712df930be7Sderaadt 		}
713df930be7Sderaadt 		if ((c == '\n' && m->g->cflags&REG_NEWLINE) ||
714df930be7Sderaadt 		    (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
715df930be7Sderaadt 			flagch = (flagch == BOL) ? BOLEOL : EOL;
716df930be7Sderaadt 			i += m->g->neol;
717df930be7Sderaadt 		}
718df930be7Sderaadt 		if (i != 0) {
719df930be7Sderaadt 			for (; i > 0; i--)
720af486f33Sschwarze 				st = step(m->g, startst, stopst,
721af486f33Sschwarze 				    st, flagch, st);
722df930be7Sderaadt 			SP("boleol", st, c);
723df930be7Sderaadt 		}
724df930be7Sderaadt 
725df930be7Sderaadt 		/* how about a word boundary? */
726df930be7Sderaadt 		if ((flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
727af486f33Sschwarze 		    (c != OUT && ISWORD(c)))
728df930be7Sderaadt 			flagch = BOW;
729df930be7Sderaadt 		if ((lastc != OUT && ISWORD(lastc)) &&
730af486f33Sschwarze 		    (flagch == EOL || (c != OUT && !ISWORD(c))))
731df930be7Sderaadt 			flagch = EOW;
732df930be7Sderaadt 		if (flagch == BOW || flagch == EOW) {
733df930be7Sderaadt 			st = step(m->g, startst, stopst, st, flagch, st);
734df930be7Sderaadt 			SP("boweow", st, c);
735df930be7Sderaadt 		}
736df930be7Sderaadt 
737df930be7Sderaadt 		/* are we done? */
738df930be7Sderaadt 		if (ISSET(st, stopst) || p == stop)
739df930be7Sderaadt 			break;		/* NOTE BREAK OUT */
740df930be7Sderaadt 
741df930be7Sderaadt 		/* no, we must deal with this character */
742df930be7Sderaadt 		ASSIGN(tmp, st);
743df930be7Sderaadt 		ASSIGN(st, fresh);
744df930be7Sderaadt 		assert(c != OUT);
745df930be7Sderaadt 		st = step(m->g, startst, stopst, tmp, c, st);
746df930be7Sderaadt 		SP("aft", st, c);
747df930be7Sderaadt 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
748df930be7Sderaadt 		p++;
749df930be7Sderaadt 	}
750df930be7Sderaadt 
751df930be7Sderaadt 	assert(coldp != NULL);
752df930be7Sderaadt 	m->coldp = coldp;
753df930be7Sderaadt 	if (ISSET(st, stopst))
754df930be7Sderaadt 		return(p+1);
755df930be7Sderaadt 	else
756df930be7Sderaadt 		return(NULL);
757df930be7Sderaadt }
758df930be7Sderaadt 
759df930be7Sderaadt /*
760df930be7Sderaadt  - slow - step through the string more deliberately
761df930be7Sderaadt  */
762d1a1db7fSmartijn static const char *		/* where it ended */
slow(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst)763d1a1db7fSmartijn slow(struct match *m, const char *start, const char *stop, sopno startst,
764d1a1db7fSmartijn     sopno stopst)
765df930be7Sderaadt {
7663d7c72a1Sotto 	states st = m->st;
7673d7c72a1Sotto 	states empty = m->empty;
7683d7c72a1Sotto 	states tmp = m->tmp;
769d1a1db7fSmartijn 	const char *p = start;
770e315dedfSmartijn 	int c;
7713d7c72a1Sotto 	int lastc;		/* previous c */
7723d7c72a1Sotto 	int flagch;
7733d7c72a1Sotto 	int i;
774d1a1db7fSmartijn 	const char *matchp;	/* last p at which a match ended */
775df930be7Sderaadt 
776e315dedfSmartijn 	if (start == m->offp || (start == m->beginp && !(m->eflags&REG_NOTBOL)))
777e315dedfSmartijn 		c = OUT;
778e315dedfSmartijn 	else
779e315dedfSmartijn 		c = *(start-1);
780e315dedfSmartijn 
781df930be7Sderaadt 	AT("slow", start, stop, startst, stopst);
782df930be7Sderaadt 	CLEAR(st);
783df930be7Sderaadt 	SET1(st, startst);
784df930be7Sderaadt 	SP("sstart", st, *p);
785df930be7Sderaadt 	st = step(m->g, startst, stopst, st, NOTHING, st);
786df930be7Sderaadt 	matchp = NULL;
787df930be7Sderaadt 	for (;;) {
788df930be7Sderaadt 		/* next character */
789df930be7Sderaadt 		lastc = c;
790df930be7Sderaadt 		c = (p == m->endp) ? OUT : *p;
791df930be7Sderaadt 
792df930be7Sderaadt 		/* is there an EOL and/or BOL between lastc and c? */
793df930be7Sderaadt 		flagch = '\0';
794df930be7Sderaadt 		i = 0;
795df930be7Sderaadt 		if ((lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
796df930be7Sderaadt 		    (lastc == OUT && !(m->eflags&REG_NOTBOL))) {
797df930be7Sderaadt 			flagch = BOL;
798df930be7Sderaadt 			i = m->g->nbol;
799df930be7Sderaadt 		}
800df930be7Sderaadt 		if ((c == '\n' && m->g->cflags&REG_NEWLINE) ||
801df930be7Sderaadt 		    (c == OUT && !(m->eflags&REG_NOTEOL))) {
802df930be7Sderaadt 			flagch = (flagch == BOL) ? BOLEOL : EOL;
803df930be7Sderaadt 			i += m->g->neol;
804df930be7Sderaadt 		}
805df930be7Sderaadt 		if (i != 0) {
806df930be7Sderaadt 			for (; i > 0; i--)
807af486f33Sschwarze 				st = step(m->g, startst, stopst,
808af486f33Sschwarze 				    st, flagch, st);
809df930be7Sderaadt 			SP("sboleol", st, c);
810df930be7Sderaadt 		}
811df930be7Sderaadt 
812df930be7Sderaadt 		/* how about a word boundary? */
813df930be7Sderaadt 		if ((flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
814af486f33Sschwarze 		    (c != OUT && ISWORD(c)))
815df930be7Sderaadt 			flagch = BOW;
816df930be7Sderaadt 		if ((lastc != OUT && ISWORD(lastc)) &&
817af486f33Sschwarze 		    (flagch == EOL || (c != OUT && !ISWORD(c))))
818df930be7Sderaadt 			flagch = EOW;
819df930be7Sderaadt 		if (flagch == BOW || flagch == EOW) {
820df930be7Sderaadt 			st = step(m->g, startst, stopst, st, flagch, st);
821df930be7Sderaadt 			SP("sboweow", st, c);
822df930be7Sderaadt 		}
823df930be7Sderaadt 
824df930be7Sderaadt 		/* are we done? */
825df930be7Sderaadt 		if (ISSET(st, stopst))
826df930be7Sderaadt 			matchp = p;
827df930be7Sderaadt 		if (EQ(st, empty) || p == stop)
828df930be7Sderaadt 			break;		/* NOTE BREAK OUT */
829df930be7Sderaadt 
830df930be7Sderaadt 		/* no, we must deal with this character */
831df930be7Sderaadt 		ASSIGN(tmp, st);
832df930be7Sderaadt 		ASSIGN(st, empty);
833df930be7Sderaadt 		assert(c != OUT);
834df930be7Sderaadt 		st = step(m->g, startst, stopst, tmp, c, st);
835df930be7Sderaadt 		SP("saft", st, c);
836df930be7Sderaadt 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
837df930be7Sderaadt 		p++;
838df930be7Sderaadt 	}
839df930be7Sderaadt 
840df930be7Sderaadt 	return(matchp);
841df930be7Sderaadt }
842df930be7Sderaadt 
843df930be7Sderaadt 
844df930be7Sderaadt /*
845df930be7Sderaadt  - step - map set of states reachable before char to set reachable after
846df930be7Sderaadt  */
847df930be7Sderaadt static states
step(struct re_guts * g,sopno start,sopno stop,states bef,int ch,states aft)8483d7c72a1Sotto step(struct re_guts *g,
8493d7c72a1Sotto     sopno start,		/* start state within strip */
8503d7c72a1Sotto     sopno stop,			/* state after stop state within strip */
8513d7c72a1Sotto     states bef,			/* states reachable before */
8523d7c72a1Sotto     int ch,			/* character or NONCHAR code */
8533d7c72a1Sotto     states aft)			/* states already known reachable after */
854df930be7Sderaadt {
8553d7c72a1Sotto 	cset *cs;
8563d7c72a1Sotto 	sop s;
8573d7c72a1Sotto 	sopno pc;
8583d7c72a1Sotto 	onestate here;		/* note, macros know this name */
8593d7c72a1Sotto 	sopno look;
8603d7c72a1Sotto 	int i;
861df930be7Sderaadt 
862df930be7Sderaadt 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
863df930be7Sderaadt 		s = g->strip[pc];
864df930be7Sderaadt 		switch (OP(s)) {
865df930be7Sderaadt 		case OEND:
866df930be7Sderaadt 			assert(pc == stop-1);
867df930be7Sderaadt 			break;
868df930be7Sderaadt 		case OCHAR:
869df930be7Sderaadt 			/* only characters can match */
870df930be7Sderaadt 			assert(!NONCHAR(ch) || ch != (char)OPND(s));
871df930be7Sderaadt 			if (ch == (char)OPND(s))
872df930be7Sderaadt 				FWD(aft, bef, 1);
873df930be7Sderaadt 			break;
874df930be7Sderaadt 		case OBOL:
875df930be7Sderaadt 			if (ch == BOL || ch == BOLEOL)
876df930be7Sderaadt 				FWD(aft, bef, 1);
877df930be7Sderaadt 			break;
878df930be7Sderaadt 		case OEOL:
879df930be7Sderaadt 			if (ch == EOL || ch == BOLEOL)
880df930be7Sderaadt 				FWD(aft, bef, 1);
881df930be7Sderaadt 			break;
882df930be7Sderaadt 		case OBOW:
883df930be7Sderaadt 			if (ch == BOW)
884df930be7Sderaadt 				FWD(aft, bef, 1);
885df930be7Sderaadt 			break;
886df930be7Sderaadt 		case OEOW:
887df930be7Sderaadt 			if (ch == EOW)
888df930be7Sderaadt 				FWD(aft, bef, 1);
889df930be7Sderaadt 			break;
890df930be7Sderaadt 		case OANY:
891df930be7Sderaadt 			if (!NONCHAR(ch))
892df930be7Sderaadt 				FWD(aft, bef, 1);
893df930be7Sderaadt 			break;
894df930be7Sderaadt 		case OANYOF:
895df930be7Sderaadt 			cs = &g->sets[OPND(s)];
896df930be7Sderaadt 			if (!NONCHAR(ch) && CHIN(cs, ch))
897df930be7Sderaadt 				FWD(aft, bef, 1);
898df930be7Sderaadt 			break;
899df930be7Sderaadt 		case OBACK_:		/* ignored here */
900df930be7Sderaadt 		case O_BACK:
901df930be7Sderaadt 			FWD(aft, aft, 1);
902df930be7Sderaadt 			break;
903df930be7Sderaadt 		case OPLUS_:		/* forward, this is just an empty */
904df930be7Sderaadt 			FWD(aft, aft, 1);
905df930be7Sderaadt 			break;
906df930be7Sderaadt 		case O_PLUS:		/* both forward and back */
907df930be7Sderaadt 			FWD(aft, aft, 1);
908df930be7Sderaadt 			i = ISSETBACK(aft, OPND(s));
909df930be7Sderaadt 			BACK(aft, aft, OPND(s));
910df930be7Sderaadt 			if (!i && ISSETBACK(aft, OPND(s))) {
911df930be7Sderaadt 				/* oho, must reconsider loop body */
912df930be7Sderaadt 				pc -= OPND(s) + 1;
913df930be7Sderaadt 				INIT(here, pc);
914df930be7Sderaadt 			}
915df930be7Sderaadt 			break;
916df930be7Sderaadt 		case OQUEST_:		/* two branches, both forward */
917df930be7Sderaadt 			FWD(aft, aft, 1);
918df930be7Sderaadt 			FWD(aft, aft, OPND(s));
919df930be7Sderaadt 			break;
920df930be7Sderaadt 		case O_QUEST:		/* just an empty */
921df930be7Sderaadt 			FWD(aft, aft, 1);
922df930be7Sderaadt 			break;
923df930be7Sderaadt 		case OLPAREN:		/* not significant here */
924df930be7Sderaadt 		case ORPAREN:
925df930be7Sderaadt 			FWD(aft, aft, 1);
926df930be7Sderaadt 			break;
927df930be7Sderaadt 		case OCH_:		/* mark the first two branches */
928df930be7Sderaadt 			FWD(aft, aft, 1);
929df930be7Sderaadt 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
930df930be7Sderaadt 			FWD(aft, aft, OPND(s));
931df930be7Sderaadt 			break;
932df930be7Sderaadt 		case OOR1:		/* done a branch, find the O_CH */
933df930be7Sderaadt 			if (ISSTATEIN(aft, here)) {
934df930be7Sderaadt 				for (look = 1;
935df930be7Sderaadt 				    OP(s = g->strip[pc+look]) != O_CH;
936df930be7Sderaadt 				    look += OPND(s))
937df930be7Sderaadt 					assert(OP(s) == OOR2);
938*b6faad1aSmillert 				FWD(aft, aft, look + 1);
939df930be7Sderaadt 			}
940df930be7Sderaadt 			break;
941df930be7Sderaadt 		case OOR2:		/* propagate OCH_'s marking */
942df930be7Sderaadt 			FWD(aft, aft, 1);
943df930be7Sderaadt 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
944df930be7Sderaadt 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
945df930be7Sderaadt 				FWD(aft, aft, OPND(s));
946df930be7Sderaadt 			}
947df930be7Sderaadt 			break;
948df930be7Sderaadt 		case O_CH:		/* just empty */
949df930be7Sderaadt 			FWD(aft, aft, 1);
950df930be7Sderaadt 			break;
951df930be7Sderaadt 		default:		/* ooooops... */
952df930be7Sderaadt 			assert(nope);
953df930be7Sderaadt 			break;
954df930be7Sderaadt 		}
955df930be7Sderaadt 	}
956df930be7Sderaadt 
957df930be7Sderaadt 	return(aft);
958df930be7Sderaadt }
959df930be7Sderaadt 
960df930be7Sderaadt #ifdef REDEBUG
961df930be7Sderaadt /*
962df930be7Sderaadt  - print - print a set of states
963df930be7Sderaadt  */
964df930be7Sderaadt static void
print(struct match * m,const char * caption,states st,int ch,FILE * d)965d1a1db7fSmartijn print(struct match *m, const char *caption, states st, int ch, FILE *d)
966df930be7Sderaadt {
9673d7c72a1Sotto 	struct re_guts *g = m->g;
9683d7c72a1Sotto 	int i;
9693d7c72a1Sotto 	int first = 1;
970df930be7Sderaadt 
971df930be7Sderaadt 	if (!(m->eflags&REG_TRACE))
972df930be7Sderaadt 		return;
973df930be7Sderaadt 
974442a6afdSmillert 	(void)fprintf(d, "%s", caption);
975442a6afdSmillert 	(void)fprintf(d, " %s", pchar(ch));
976af486f33Sschwarze 	for (i = 0; i < g->nstates; i++) {
977df930be7Sderaadt 		if (ISSET(st, i)) {
978442a6afdSmillert 			(void)fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
979df930be7Sderaadt 			first = 0;
980df930be7Sderaadt 		}
981af486f33Sschwarze 	}
982442a6afdSmillert 	(void)fprintf(d, "\n");
983df930be7Sderaadt }
984df930be7Sderaadt 
985df930be7Sderaadt /*
986df930be7Sderaadt  - at - print current situation
987df930be7Sderaadt  */
988df930be7Sderaadt static void
at(struct match * m,const char * title,const char * start,const char * stop,sopno startst,sopno stopst)989d1a1db7fSmartijn at(struct match *m, const char *title, const char *start, const char *stop,
990d1a1db7fSmartijn     sopno startst, sopno stopst)
991df930be7Sderaadt {
992df930be7Sderaadt 	if (!(m->eflags&REG_TRACE))
993df930be7Sderaadt 		return;
994df930be7Sderaadt 
995442a6afdSmillert 	(void)printf("%s %s-", title, pchar(*start));
996442a6afdSmillert 	(void)printf("%s ", pchar(*stop));
997442a6afdSmillert 	(void)printf("%ld-%ld\n", (long)startst, (long)stopst);
998df930be7Sderaadt }
999df930be7Sderaadt 
1000df930be7Sderaadt #ifndef PCHARDONE
1001df930be7Sderaadt #define	PCHARDONE	/* never again */
10020595d4dbSguenther static const char *nonchars[] =
10030595d4dbSguenther     { "OUT", "BOL", "EOL", "BOLEOL", "NOTHING", "BOW", "EOW" };
10040595d4dbSguenther #define	PNONCHAR(c)						\
10050595d4dbSguenther 	((c) - OUT < (sizeof(nonchars)/sizeof(nonchars[0]))	\
10060595d4dbSguenther 	    ? nonchars[(c) - OUT] : "invalid")
10070595d4dbSguenther 
1008df930be7Sderaadt /*
1009df930be7Sderaadt  - pchar - make a character printable
1010df930be7Sderaadt  *
1011df930be7Sderaadt  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
1012df930be7Sderaadt  * duplicate here avoids having a debugging-capable regexec.o tied to
1013df930be7Sderaadt  * a matching debug.o, and this is convenient.  It all disappears in
1014df930be7Sderaadt  * the non-debug compilation anyway, so it doesn't matter much.
1015df930be7Sderaadt  */
10160595d4dbSguenther static const char *		/* -> representation */
pchar(int ch)10173d7c72a1Sotto pchar(int ch)
1018df930be7Sderaadt {
1019df930be7Sderaadt 	static char pbuf[10];
1020df930be7Sderaadt 
10210595d4dbSguenther 	if (NONCHAR(ch)) {
10220595d4dbSguenther 		if (ch - OUT < (sizeof(nonchars)/sizeof(nonchars[0])))
10230595d4dbSguenther 			return nonchars[ch - OUT];
10240595d4dbSguenther 		return "invalid";
10250595d4dbSguenther 	}
10260595d4dbSguenther 	if (isprint((unsigned char)ch) || ch == ' ')
1027c364cbbdSderaadt 		(void)snprintf(pbuf, sizeof pbuf, "%c", ch);
1028df930be7Sderaadt 	else
1029c364cbbdSderaadt 		(void)snprintf(pbuf, sizeof pbuf, "\\%o", ch);
1030df930be7Sderaadt 	return(pbuf);
1031df930be7Sderaadt }
1032df930be7Sderaadt #endif
1033df930be7Sderaadt #endif
1034df930be7Sderaadt 
1035df930be7Sderaadt #undef	matcher
1036df930be7Sderaadt #undef	fast
1037df930be7Sderaadt #undef	slow
1038df930be7Sderaadt #undef	dissect
1039df930be7Sderaadt #undef	backref
1040df930be7Sderaadt #undef	step
1041df930be7Sderaadt #undef	print
1042df930be7Sderaadt #undef	at
1043df930be7Sderaadt #undef	match
10445b9192c4Smillert #undef	nope
1045