xref: /freebsd/lib/libc/regex/engine.c (revision 16252f116697edcd02a34a34cc845159abe0a1d3)
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  * 3. All advertising materials mentioning features or use of this software
1858f0484fSRodney W. Grimes  *    must display the following acknowledgement:
1958f0484fSRodney W. Grimes  *	This product includes software developed by the University of
2058f0484fSRodney W. Grimes  *	California, Berkeley and its contributors.
2158f0484fSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
2258f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
2358f0484fSRodney W. Grimes  *    without specific prior written permission.
2458f0484fSRodney W. Grimes  *
2558f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2658f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2758f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2858f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2958f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3058f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3158f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3258f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3358f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3458f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3558f0484fSRodney W. Grimes  * SUCH DAMAGE.
3658f0484fSRodney W. Grimes  *
3758f0484fSRodney W. Grimes  *	@(#)engine.c	8.5 (Berkeley) 3/20/94
3858f0484fSRodney W. Grimes  */
3958f0484fSRodney W. Grimes 
4058f0484fSRodney W. Grimes /*
4158f0484fSRodney W. Grimes  * The matching engine and friends.  This file is #included by regexec.c
4258f0484fSRodney W. Grimes  * after suitable #defines of a variety of macros used herein, so that
4358f0484fSRodney W. Grimes  * different state representations can be used without duplicating masses
4458f0484fSRodney W. Grimes  * of code.
4558f0484fSRodney W. Grimes  */
4658f0484fSRodney W. Grimes 
4758f0484fSRodney W. Grimes #ifdef SNAMES
4858f0484fSRodney W. Grimes #define	matcher	smatcher
4958f0484fSRodney W. Grimes #define	fast	sfast
5058f0484fSRodney W. Grimes #define	slow	sslow
5158f0484fSRodney W. Grimes #define	dissect	sdissect
5258f0484fSRodney W. Grimes #define	backref	sbackref
5358f0484fSRodney W. Grimes #define	step	sstep
5458f0484fSRodney W. Grimes #define	print	sprint
5558f0484fSRodney W. Grimes #define	at	sat
5658f0484fSRodney W. Grimes #define	match	smat
5758f0484fSRodney W. Grimes #endif
5858f0484fSRodney W. Grimes #ifdef LNAMES
5958f0484fSRodney W. Grimes #define	matcher	lmatcher
6058f0484fSRodney W. Grimes #define	fast	lfast
6158f0484fSRodney W. Grimes #define	slow	lslow
6258f0484fSRodney W. Grimes #define	dissect	ldissect
6358f0484fSRodney W. Grimes #define	backref	lbackref
6458f0484fSRodney W. Grimes #define	step	lstep
6558f0484fSRodney W. Grimes #define	print	lprint
6658f0484fSRodney W. Grimes #define	at	lat
6758f0484fSRodney W. Grimes #define	match	lmat
6858f0484fSRodney W. Grimes #endif
6958f0484fSRodney W. Grimes 
7058f0484fSRodney W. Grimes /* another structure passed up and down to avoid zillions of parameters */
7158f0484fSRodney W. Grimes struct match {
7258f0484fSRodney W. Grimes 	struct re_guts *g;
7358f0484fSRodney W. Grimes 	int eflags;
7458f0484fSRodney W. Grimes 	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
7558f0484fSRodney W. Grimes 	char *offp;		/* offsets work from here */
7658f0484fSRodney W. Grimes 	char *beginp;		/* start of string -- virtual NUL precedes */
7758f0484fSRodney W. Grimes 	char *endp;		/* end of string -- virtual NUL here */
7858f0484fSRodney W. Grimes 	char *coldp;		/* can be no match starting before here */
7958f0484fSRodney W. Grimes 	char **lastpos;		/* [nplus+1] */
8058f0484fSRodney W. Grimes 	STATEVARS;
8158f0484fSRodney W. Grimes 	states st;		/* current states */
8258f0484fSRodney W. Grimes 	states fresh;		/* states for a fresh start */
8358f0484fSRodney W. Grimes 	states tmp;		/* temporary */
8458f0484fSRodney W. Grimes 	states empty;		/* empty set of states */
8558f0484fSRodney W. Grimes };
8658f0484fSRodney W. Grimes 
8758f0484fSRodney W. Grimes /* ========= begin header generated by ./mkh ========= */
8858f0484fSRodney W. Grimes #ifdef __cplusplus
8958f0484fSRodney W. Grimes extern "C" {
9058f0484fSRodney W. Grimes #endif
9158f0484fSRodney W. Grimes 
9258f0484fSRodney W. Grimes /* === engine.c === */
9358f0484fSRodney W. Grimes static int matcher __P((struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags));
9458f0484fSRodney W. Grimes static char *dissect __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
9558f0484fSRodney W. Grimes static char *backref __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev));
9658f0484fSRodney W. Grimes static char *fast __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
9758f0484fSRodney W. Grimes static char *slow __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
9858f0484fSRodney W. Grimes static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft));
9958f0484fSRodney W. Grimes #define	BOL	(OUT+1)
10058f0484fSRodney W. Grimes #define	EOL	(BOL+1)
10158f0484fSRodney W. Grimes #define	BOLEOL	(BOL+2)
10258f0484fSRodney W. Grimes #define	NOTHING	(BOL+3)
10358f0484fSRodney W. Grimes #define	BOW	(BOL+4)
10458f0484fSRodney W. Grimes #define	EOW	(BOL+5)
10558f0484fSRodney W. Grimes #define	CODEMAX	(BOL+5)		/* highest code used */
10658f0484fSRodney W. Grimes #define	NONCHAR(c)	((c) > CHAR_MAX)
10758f0484fSRodney W. Grimes #define	NNONCHAR	(CODEMAX-CHAR_MAX)
10858f0484fSRodney W. Grimes #ifdef REDEBUG
10958f0484fSRodney W. Grimes static void print __P((struct match *m, char *caption, states st, int ch, FILE *d));
11058f0484fSRodney W. Grimes #endif
11158f0484fSRodney W. Grimes #ifdef REDEBUG
11258f0484fSRodney W. Grimes static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
11358f0484fSRodney W. Grimes #endif
11458f0484fSRodney W. Grimes #ifdef REDEBUG
11558f0484fSRodney W. Grimes static char *pchar __P((int ch));
11658f0484fSRodney W. Grimes #endif
11758f0484fSRodney W. Grimes 
11858f0484fSRodney W. Grimes #ifdef __cplusplus
11958f0484fSRodney W. Grimes }
12058f0484fSRodney W. Grimes #endif
12158f0484fSRodney W. Grimes /* ========= end header generated by ./mkh ========= */
12258f0484fSRodney W. Grimes 
12358f0484fSRodney W. Grimes #ifdef REDEBUG
12458f0484fSRodney W. Grimes #define	SP(t, s, c)	print(m, t, s, c, stdout)
12558f0484fSRodney W. Grimes #define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
12658f0484fSRodney W. Grimes #define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
12758f0484fSRodney W. Grimes #else
12858f0484fSRodney W. Grimes #define	SP(t, s, c)	/* nothing */
12958f0484fSRodney W. Grimes #define	AT(t, p1, p2, s1, s2)	/* nothing */
13058f0484fSRodney W. Grimes #define	NOTE(s)	/* nothing */
13158f0484fSRodney W. Grimes #endif
13258f0484fSRodney W. Grimes 
13358f0484fSRodney W. Grimes /*
13458f0484fSRodney W. Grimes  - matcher - the actual matching engine
13558f0484fSRodney W. Grimes  == static int matcher(register struct re_guts *g, char *string, \
13658f0484fSRodney W. Grimes  ==	size_t nmatch, regmatch_t pmatch[], int eflags);
13758f0484fSRodney W. Grimes  */
13858f0484fSRodney W. Grimes static int			/* 0 success, REG_NOMATCH failure */
13958f0484fSRodney W. Grimes matcher(g, string, nmatch, pmatch, eflags)
14058f0484fSRodney W. Grimes register struct re_guts *g;
14158f0484fSRodney W. Grimes char *string;
14258f0484fSRodney W. Grimes size_t nmatch;
14358f0484fSRodney W. Grimes regmatch_t pmatch[];
14458f0484fSRodney W. Grimes int eflags;
14558f0484fSRodney W. Grimes {
14658f0484fSRodney W. Grimes 	register char *endp;
14758f0484fSRodney W. Grimes 	register int i;
14858f0484fSRodney W. Grimes 	struct match mv;
14958f0484fSRodney W. Grimes 	register struct match *m = &mv;
15058f0484fSRodney W. Grimes 	register char *dp;
15158f0484fSRodney W. Grimes 	const register sopno gf = g->firststate+1;	/* +1 for OEND */
15258f0484fSRodney W. Grimes 	const register sopno gl = g->laststate;
15358f0484fSRodney W. Grimes 	char *start;
15458f0484fSRodney W. Grimes 	char *stop;
15558f0484fSRodney W. Grimes 
15658f0484fSRodney W. Grimes 	/* simplify the situation where possible */
15758f0484fSRodney W. Grimes 	if (g->cflags&REG_NOSUB)
15858f0484fSRodney W. Grimes 		nmatch = 0;
15958f0484fSRodney W. Grimes 	if (eflags&REG_STARTEND) {
16058f0484fSRodney W. Grimes 		start = string + pmatch[0].rm_so;
16158f0484fSRodney W. Grimes 		stop = string + pmatch[0].rm_eo;
16258f0484fSRodney W. Grimes 	} else {
16358f0484fSRodney W. Grimes 		start = string;
16458f0484fSRodney W. Grimes 		stop = start + strlen(start);
16558f0484fSRodney W. Grimes 	}
16658f0484fSRodney W. Grimes 	if (stop < start)
16758f0484fSRodney W. Grimes 		return(REG_INVARG);
16858f0484fSRodney W. Grimes 
16958f0484fSRodney W. Grimes 	/* prescreening; this does wonders for this rather slow code */
17058f0484fSRodney W. Grimes 	if (g->must != NULL) {
17158f0484fSRodney W. Grimes 		for (dp = start; dp < stop; dp++)
17258f0484fSRodney W. Grimes 			if (*dp == g->must[0] && stop - dp >= g->mlen &&
17358f0484fSRodney W. Grimes 				memcmp(dp, g->must, (size_t)g->mlen) == 0)
17458f0484fSRodney W. Grimes 				break;
17558f0484fSRodney W. Grimes 		if (dp == stop)		/* we didn't find g->must */
17658f0484fSRodney W. Grimes 			return(REG_NOMATCH);
17758f0484fSRodney W. Grimes 	}
17858f0484fSRodney W. Grimes 
17958f0484fSRodney W. Grimes 	/* match struct setup */
18058f0484fSRodney W. Grimes 	m->g = g;
18158f0484fSRodney W. Grimes 	m->eflags = eflags;
18258f0484fSRodney W. Grimes 	m->pmatch = NULL;
18358f0484fSRodney W. Grimes 	m->lastpos = NULL;
18458f0484fSRodney W. Grimes 	m->offp = string;
18558f0484fSRodney W. Grimes 	m->beginp = start;
18658f0484fSRodney W. Grimes 	m->endp = stop;
18758f0484fSRodney W. Grimes 	STATESETUP(m, 4);
18858f0484fSRodney W. Grimes 	SETUP(m->st);
18958f0484fSRodney W. Grimes 	SETUP(m->fresh);
19058f0484fSRodney W. Grimes 	SETUP(m->tmp);
19158f0484fSRodney W. Grimes 	SETUP(m->empty);
19258f0484fSRodney W. Grimes 	CLEAR(m->empty);
19358f0484fSRodney W. Grimes 
19458f0484fSRodney W. Grimes 	/* this loop does only one repetition except for backrefs */
19558f0484fSRodney W. Grimes 	for (;;) {
19658f0484fSRodney W. Grimes 		endp = fast(m, start, stop, gf, gl);
19758f0484fSRodney W. Grimes 		if (endp == NULL) {		/* a miss */
19858f0484fSRodney W. Grimes 			STATETEARDOWN(m);
19958f0484fSRodney W. Grimes 			return(REG_NOMATCH);
20058f0484fSRodney W. Grimes 		}
20158f0484fSRodney W. Grimes 		if (nmatch == 0 && !g->backrefs)
20258f0484fSRodney W. Grimes 			break;		/* no further info needed */
20358f0484fSRodney W. Grimes 
20458f0484fSRodney W. Grimes 		/* where? */
20558f0484fSRodney W. Grimes 		assert(m->coldp != NULL);
20658f0484fSRodney W. Grimes 		for (;;) {
20758f0484fSRodney W. Grimes 			NOTE("finding start");
20858f0484fSRodney W. Grimes 			endp = slow(m, m->coldp, stop, gf, gl);
20958f0484fSRodney W. Grimes 			if (endp != NULL)
21058f0484fSRodney W. Grimes 				break;
21158f0484fSRodney W. Grimes 			assert(m->coldp < m->endp);
21258f0484fSRodney W. Grimes 			m->coldp++;
21358f0484fSRodney W. Grimes 		}
21458f0484fSRodney W. Grimes 		if (nmatch == 1 && !g->backrefs)
21558f0484fSRodney W. Grimes 			break;		/* no further info needed */
21658f0484fSRodney W. Grimes 
21758f0484fSRodney W. Grimes 		/* oh my, he wants the subexpressions... */
21858f0484fSRodney W. Grimes 		if (m->pmatch == NULL)
21958f0484fSRodney W. Grimes 			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
22058f0484fSRodney W. Grimes 							sizeof(regmatch_t));
22158f0484fSRodney W. Grimes 		if (m->pmatch == NULL) {
22258f0484fSRodney W. Grimes 			STATETEARDOWN(m);
22358f0484fSRodney W. Grimes 			return(REG_ESPACE);
22458f0484fSRodney W. Grimes 		}
22558f0484fSRodney W. Grimes 		for (i = 1; i <= m->g->nsub; i++)
22658f0484fSRodney W. Grimes 			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
22758f0484fSRodney W. Grimes 		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
22858f0484fSRodney W. Grimes 			NOTE("dissecting");
22958f0484fSRodney W. Grimes 			dp = dissect(m, m->coldp, endp, gf, gl);
23058f0484fSRodney W. Grimes 		} else {
23158f0484fSRodney W. Grimes 			if (g->nplus > 0 && m->lastpos == NULL)
23258f0484fSRodney W. Grimes 				m->lastpos = (char **)malloc((g->nplus+1) *
23358f0484fSRodney W. Grimes 							sizeof(char *));
23458f0484fSRodney W. Grimes 			if (g->nplus > 0 && m->lastpos == NULL) {
23558f0484fSRodney W. Grimes 				free(m->pmatch);
23658f0484fSRodney W. Grimes 				STATETEARDOWN(m);
23758f0484fSRodney W. Grimes 				return(REG_ESPACE);
23858f0484fSRodney W. Grimes 			}
23958f0484fSRodney W. Grimes 			NOTE("backref dissect");
24058f0484fSRodney W. Grimes 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
24158f0484fSRodney W. Grimes 		}
24258f0484fSRodney W. Grimes 		if (dp != NULL)
24358f0484fSRodney W. Grimes 			break;
24458f0484fSRodney W. Grimes 
24558f0484fSRodney W. Grimes 		/* uh-oh... we couldn't find a subexpression-level match */
24658f0484fSRodney W. Grimes 		assert(g->backrefs);	/* must be back references doing it */
24758f0484fSRodney W. Grimes 		assert(g->nplus == 0 || m->lastpos != NULL);
24858f0484fSRodney W. Grimes 		for (;;) {
24958f0484fSRodney W. Grimes 			if (dp != NULL || endp <= m->coldp)
25058f0484fSRodney W. Grimes 				break;		/* defeat */
25158f0484fSRodney W. Grimes 			NOTE("backoff");
25258f0484fSRodney W. Grimes 			endp = slow(m, m->coldp, endp-1, gf, gl);
25358f0484fSRodney W. Grimes 			if (endp == NULL)
25458f0484fSRodney W. Grimes 				break;		/* defeat */
25558f0484fSRodney W. Grimes 			/* try it on a shorter possibility */
25658f0484fSRodney W. Grimes #ifndef NDEBUG
25758f0484fSRodney W. Grimes 			for (i = 1; i <= m->g->nsub; i++) {
25858f0484fSRodney W. Grimes 				assert(m->pmatch[i].rm_so == -1);
25958f0484fSRodney W. Grimes 				assert(m->pmatch[i].rm_eo == -1);
26058f0484fSRodney W. Grimes 			}
26158f0484fSRodney W. Grimes #endif
26258f0484fSRodney W. Grimes 			NOTE("backoff dissect");
26358f0484fSRodney W. Grimes 			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
26458f0484fSRodney W. Grimes 		}
26558f0484fSRodney W. Grimes 		assert(dp == NULL || dp == endp);
26658f0484fSRodney W. Grimes 		if (dp != NULL)		/* found a shorter one */
26758f0484fSRodney W. Grimes 			break;
26858f0484fSRodney W. Grimes 
26958f0484fSRodney W. Grimes 		/* despite initial appearances, there is no match here */
27058f0484fSRodney W. Grimes 		NOTE("false alarm");
27158f0484fSRodney W. Grimes 		start = m->coldp + 1;	/* recycle starting later */
27258f0484fSRodney W. Grimes 		assert(start <= stop);
27358f0484fSRodney W. Grimes 	}
27458f0484fSRodney W. Grimes 
27558f0484fSRodney W. Grimes 	/* fill in the details if requested */
27658f0484fSRodney W. Grimes 	if (nmatch > 0) {
27758f0484fSRodney W. Grimes 		pmatch[0].rm_so = m->coldp - m->offp;
27858f0484fSRodney W. Grimes 		pmatch[0].rm_eo = endp - m->offp;
27958f0484fSRodney W. Grimes 	}
28058f0484fSRodney W. Grimes 	if (nmatch > 1) {
28158f0484fSRodney W. Grimes 		assert(m->pmatch != NULL);
28258f0484fSRodney W. Grimes 		for (i = 1; i < nmatch; i++)
28358f0484fSRodney W. Grimes 			if (i <= m->g->nsub)
28458f0484fSRodney W. Grimes 				pmatch[i] = m->pmatch[i];
28558f0484fSRodney W. Grimes 			else {
28658f0484fSRodney W. Grimes 				pmatch[i].rm_so = -1;
28758f0484fSRodney W. Grimes 				pmatch[i].rm_eo = -1;
28858f0484fSRodney W. Grimes 			}
28958f0484fSRodney W. Grimes 	}
29058f0484fSRodney W. Grimes 
29158f0484fSRodney W. Grimes 	if (m->pmatch != NULL)
29258f0484fSRodney W. Grimes 		free((char *)m->pmatch);
29358f0484fSRodney W. Grimes 	if (m->lastpos != NULL)
29458f0484fSRodney W. Grimes 		free((char *)m->lastpos);
29558f0484fSRodney W. Grimes 	STATETEARDOWN(m);
29658f0484fSRodney W. Grimes 	return(0);
29758f0484fSRodney W. Grimes }
29858f0484fSRodney W. Grimes 
29958f0484fSRodney W. Grimes /*
30058f0484fSRodney W. Grimes  - dissect - figure out what matched what, no back references
30158f0484fSRodney W. Grimes  == static char *dissect(register struct match *m, char *start, \
30258f0484fSRodney W. Grimes  ==	char *stop, sopno startst, sopno stopst);
30358f0484fSRodney W. Grimes  */
30458f0484fSRodney W. Grimes static char *			/* == stop (success) always */
30558f0484fSRodney W. Grimes dissect(m, start, stop, startst, stopst)
30658f0484fSRodney W. Grimes register struct match *m;
30758f0484fSRodney W. Grimes char *start;
30858f0484fSRodney W. Grimes char *stop;
30958f0484fSRodney W. Grimes sopno startst;
31058f0484fSRodney W. Grimes sopno stopst;
31158f0484fSRodney W. Grimes {
31258f0484fSRodney W. Grimes 	register int i;
31358f0484fSRodney W. Grimes 	register sopno ss;	/* start sop of current subRE */
31458f0484fSRodney W. Grimes 	register sopno es;	/* end sop of current subRE */
31558f0484fSRodney W. Grimes 	register char *sp;	/* start of string matched by it */
31658f0484fSRodney W. Grimes 	register char *stp;	/* string matched by it cannot pass here */
31758f0484fSRodney W. Grimes 	register char *rest;	/* start of rest of string */
31858f0484fSRodney W. Grimes 	register char *tail;	/* string unmatched by rest of RE */
31958f0484fSRodney W. Grimes 	register sopno ssub;	/* start sop of subsubRE */
32058f0484fSRodney W. Grimes 	register sopno esub;	/* end sop of subsubRE */
32158f0484fSRodney W. Grimes 	register char *ssp;	/* start of string matched by subsubRE */
32258f0484fSRodney W. Grimes 	register char *sep;	/* end of string matched by subsubRE */
32358f0484fSRodney W. Grimes 	register char *oldssp;	/* previous ssp */
32458f0484fSRodney W. Grimes 	register char *dp;
32558f0484fSRodney W. Grimes 
32658f0484fSRodney W. Grimes 	AT("diss", start, stop, startst, stopst);
32758f0484fSRodney W. Grimes 	sp = start;
32858f0484fSRodney W. Grimes 	for (ss = startst; ss < stopst; ss = es) {
32958f0484fSRodney W. Grimes 		/* identify end of subRE */
33058f0484fSRodney W. Grimes 		es = ss;
33158f0484fSRodney W. Grimes 		switch (OP(m->g->strip[es])) {
33258f0484fSRodney W. Grimes 		case OPLUS_:
33358f0484fSRodney W. Grimes 		case OQUEST_:
33458f0484fSRodney W. Grimes 			es += OPND(m->g->strip[es]);
33558f0484fSRodney W. Grimes 			break;
33658f0484fSRodney W. Grimes 		case OCH_:
33758f0484fSRodney W. Grimes 			while (OP(m->g->strip[es]) != O_CH)
33858f0484fSRodney W. Grimes 				es += OPND(m->g->strip[es]);
33958f0484fSRodney W. Grimes 			break;
34058f0484fSRodney W. Grimes 		}
34158f0484fSRodney W. Grimes 		es++;
34258f0484fSRodney W. Grimes 
34358f0484fSRodney W. Grimes 		/* figure out what it matched */
34458f0484fSRodney W. Grimes 		switch (OP(m->g->strip[ss])) {
34558f0484fSRodney W. Grimes 		case OEND:
34658f0484fSRodney W. Grimes 			assert(nope);
34758f0484fSRodney W. Grimes 			break;
34858f0484fSRodney W. Grimes 		case OCHAR:
34958f0484fSRodney W. Grimes 			sp++;
35058f0484fSRodney W. Grimes 			break;
35158f0484fSRodney W. Grimes 		case OBOL:
35258f0484fSRodney W. Grimes 		case OEOL:
35358f0484fSRodney W. Grimes 		case OBOW:
35458f0484fSRodney W. Grimes 		case OEOW:
35558f0484fSRodney W. Grimes 			break;
35658f0484fSRodney W. Grimes 		case OANY:
35758f0484fSRodney W. Grimes 		case OANYOF:
35858f0484fSRodney W. Grimes 			sp++;
35958f0484fSRodney W. Grimes 			break;
36058f0484fSRodney W. Grimes 		case OBACK_:
36158f0484fSRodney W. Grimes 		case O_BACK:
36258f0484fSRodney W. Grimes 			assert(nope);
36358f0484fSRodney W. Grimes 			break;
36458f0484fSRodney W. Grimes 		/* cases where length of match is hard to find */
36558f0484fSRodney W. Grimes 		case OQUEST_:
36658f0484fSRodney W. Grimes 			stp = stop;
36758f0484fSRodney W. Grimes 			for (;;) {
36858f0484fSRodney W. Grimes 				/* how long could this one be? */
36958f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
37058f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
37158f0484fSRodney W. Grimes 				/* could the rest match the rest? */
37258f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
37358f0484fSRodney W. Grimes 				if (tail == stop)
37458f0484fSRodney W. Grimes 					break;		/* yes! */
37558f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
37658f0484fSRodney W. Grimes 				stp = rest - 1;
37758f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
37858f0484fSRodney W. Grimes 			}
37958f0484fSRodney W. Grimes 			ssub = ss + 1;
38058f0484fSRodney W. Grimes 			esub = es - 1;
38158f0484fSRodney W. Grimes 			/* did innards match? */
38258f0484fSRodney W. Grimes 			if (slow(m, sp, rest, ssub, esub) != NULL) {
38358f0484fSRodney W. Grimes 				dp = dissect(m, sp, rest, ssub, esub);
38458f0484fSRodney W. Grimes 				assert(dp == rest);
38558f0484fSRodney W. Grimes 			} else		/* no */
38658f0484fSRodney W. Grimes 				assert(sp == rest);
38758f0484fSRodney W. Grimes 			sp = rest;
38858f0484fSRodney W. Grimes 			break;
38958f0484fSRodney W. Grimes 		case OPLUS_:
39058f0484fSRodney W. Grimes 			stp = stop;
39158f0484fSRodney W. Grimes 			for (;;) {
39258f0484fSRodney W. Grimes 				/* how long could this one be? */
39358f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
39458f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
39558f0484fSRodney W. Grimes 				/* could the rest match the rest? */
39658f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
39758f0484fSRodney W. Grimes 				if (tail == stop)
39858f0484fSRodney W. Grimes 					break;		/* yes! */
39958f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
40058f0484fSRodney W. Grimes 				stp = rest - 1;
40158f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
40258f0484fSRodney W. Grimes 			}
40358f0484fSRodney W. Grimes 			ssub = ss + 1;
40458f0484fSRodney W. Grimes 			esub = es - 1;
40558f0484fSRodney W. Grimes 			ssp = sp;
40658f0484fSRodney W. Grimes 			oldssp = ssp;
40758f0484fSRodney W. Grimes 			for (;;) {	/* find last match of innards */
40858f0484fSRodney W. Grimes 				sep = slow(m, ssp, rest, ssub, esub);
40958f0484fSRodney W. Grimes 				if (sep == NULL || sep == ssp)
41058f0484fSRodney W. Grimes 					break;	/* failed or matched null */
41158f0484fSRodney W. Grimes 				oldssp = ssp;	/* on to next try */
41258f0484fSRodney W. Grimes 				ssp = sep;
41358f0484fSRodney W. Grimes 			}
41458f0484fSRodney W. Grimes 			if (sep == NULL) {
41558f0484fSRodney W. Grimes 				/* last successful match */
41658f0484fSRodney W. Grimes 				sep = ssp;
41758f0484fSRodney W. Grimes 				ssp = oldssp;
41858f0484fSRodney W. Grimes 			}
41958f0484fSRodney W. Grimes 			assert(sep == rest);	/* must exhaust substring */
42058f0484fSRodney W. Grimes 			assert(slow(m, ssp, sep, ssub, esub) == rest);
42158f0484fSRodney W. Grimes 			dp = dissect(m, ssp, sep, ssub, esub);
42258f0484fSRodney W. Grimes 			assert(dp == sep);
42358f0484fSRodney W. Grimes 			sp = rest;
42458f0484fSRodney W. Grimes 			break;
42558f0484fSRodney W. Grimes 		case OCH_:
42658f0484fSRodney W. Grimes 			stp = stop;
42758f0484fSRodney W. Grimes 			for (;;) {
42858f0484fSRodney W. Grimes 				/* how long could this one be? */
42958f0484fSRodney W. Grimes 				rest = slow(m, sp, stp, ss, es);
43058f0484fSRodney W. Grimes 				assert(rest != NULL);	/* it did match */
43158f0484fSRodney W. Grimes 				/* could the rest match the rest? */
43258f0484fSRodney W. Grimes 				tail = slow(m, rest, stop, es, stopst);
43358f0484fSRodney W. Grimes 				if (tail == stop)
43458f0484fSRodney W. Grimes 					break;		/* yes! */
43558f0484fSRodney W. Grimes 				/* no -- try a shorter match for this one */
43658f0484fSRodney W. Grimes 				stp = rest - 1;
43758f0484fSRodney W. Grimes 				assert(stp >= sp);	/* it did work */
43858f0484fSRodney W. Grimes 			}
43958f0484fSRodney W. Grimes 			ssub = ss + 1;
44058f0484fSRodney W. Grimes 			esub = ss + OPND(m->g->strip[ss]) - 1;
44158f0484fSRodney W. Grimes 			assert(OP(m->g->strip[esub]) == OOR1);
44258f0484fSRodney W. Grimes 			for (;;) {	/* find first matching branch */
44358f0484fSRodney W. Grimes 				if (slow(m, sp, rest, ssub, esub) == rest)
44458f0484fSRodney W. Grimes 					break;	/* it matched all of it */
44558f0484fSRodney W. Grimes 				/* that one missed, try next one */
44658f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == OOR1);
44758f0484fSRodney W. Grimes 				esub++;
44858f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == OOR2);
44958f0484fSRodney W. Grimes 				ssub = esub + 1;
45058f0484fSRodney W. Grimes 				esub += OPND(m->g->strip[esub]);
45158f0484fSRodney W. Grimes 				if (OP(m->g->strip[esub]) == OOR2)
45258f0484fSRodney W. Grimes 					esub--;
45358f0484fSRodney W. Grimes 				else
45458f0484fSRodney W. Grimes 					assert(OP(m->g->strip[esub]) == O_CH);
45558f0484fSRodney W. Grimes 			}
45658f0484fSRodney W. Grimes 			dp = dissect(m, sp, rest, ssub, esub);
45758f0484fSRodney W. Grimes 			assert(dp == rest);
45858f0484fSRodney W. Grimes 			sp = rest;
45958f0484fSRodney W. Grimes 			break;
46058f0484fSRodney W. Grimes 		case O_PLUS:
46158f0484fSRodney W. Grimes 		case O_QUEST:
46258f0484fSRodney W. Grimes 		case OOR1:
46358f0484fSRodney W. Grimes 		case OOR2:
46458f0484fSRodney W. Grimes 		case O_CH:
46558f0484fSRodney W. Grimes 			assert(nope);
46658f0484fSRodney W. Grimes 			break;
46758f0484fSRodney W. Grimes 		case OLPAREN:
46858f0484fSRodney W. Grimes 			i = OPND(m->g->strip[ss]);
46958f0484fSRodney W. Grimes 			assert(0 < i && i <= m->g->nsub);
47058f0484fSRodney W. Grimes 			m->pmatch[i].rm_so = sp - m->offp;
47158f0484fSRodney W. Grimes 			break;
47258f0484fSRodney W. Grimes 		case ORPAREN:
47358f0484fSRodney W. Grimes 			i = OPND(m->g->strip[ss]);
47458f0484fSRodney W. Grimes 			assert(0 < i && i <= m->g->nsub);
47558f0484fSRodney W. Grimes 			m->pmatch[i].rm_eo = sp - m->offp;
47658f0484fSRodney W. Grimes 			break;
47758f0484fSRodney W. Grimes 		default:		/* uh oh */
47858f0484fSRodney W. Grimes 			assert(nope);
47958f0484fSRodney W. Grimes 			break;
48058f0484fSRodney W. Grimes 		}
48158f0484fSRodney W. Grimes 	}
48258f0484fSRodney W. Grimes 
48358f0484fSRodney W. Grimes 	assert(sp == stop);
48458f0484fSRodney W. Grimes 	return(sp);
48558f0484fSRodney W. Grimes }
48658f0484fSRodney W. Grimes 
48758f0484fSRodney W. Grimes /*
48858f0484fSRodney W. Grimes  - backref - figure out what matched what, figuring in back references
48958f0484fSRodney W. Grimes  == static char *backref(register struct match *m, char *start, \
49058f0484fSRodney W. Grimes  ==	char *stop, sopno startst, sopno stopst, sopno lev);
49158f0484fSRodney W. Grimes  */
49258f0484fSRodney W. Grimes static char *			/* == stop (success) or NULL (failure) */
49358f0484fSRodney W. Grimes backref(m, start, stop, startst, stopst, lev)
49458f0484fSRodney W. Grimes register struct match *m;
49558f0484fSRodney W. Grimes char *start;
49658f0484fSRodney W. Grimes char *stop;
49758f0484fSRodney W. Grimes sopno startst;
49858f0484fSRodney W. Grimes sopno stopst;
49958f0484fSRodney W. Grimes sopno lev;			/* PLUS nesting level */
50058f0484fSRodney W. Grimes {
50158f0484fSRodney W. Grimes 	register int i;
50258f0484fSRodney W. Grimes 	register sopno ss;	/* start sop of current subRE */
50358f0484fSRodney W. Grimes 	register char *sp;	/* start of string matched by it */
50458f0484fSRodney W. Grimes 	register sopno ssub;	/* start sop of subsubRE */
50558f0484fSRodney W. Grimes 	register sopno esub;	/* end sop of subsubRE */
50658f0484fSRodney W. Grimes 	register char *ssp;	/* start of string matched by subsubRE */
50758f0484fSRodney W. Grimes 	register char *dp;
50858f0484fSRodney W. Grimes 	register size_t len;
50958f0484fSRodney W. Grimes 	register int hard;
51058f0484fSRodney W. Grimes 	register sop s;
51158f0484fSRodney W. Grimes 	register regoff_t offsave;
51258f0484fSRodney W. Grimes 	register cset *cs;
51358f0484fSRodney W. Grimes 
51458f0484fSRodney W. Grimes 	AT("back", start, stop, startst, stopst);
51558f0484fSRodney W. Grimes 	sp = start;
51658f0484fSRodney W. Grimes 
51758f0484fSRodney W. Grimes 	/* get as far as we can with easy stuff */
51858f0484fSRodney W. Grimes 	hard = 0;
51958f0484fSRodney W. Grimes 	for (ss = startst; !hard && ss < stopst; ss++)
52058f0484fSRodney W. Grimes 		switch (OP(s = m->g->strip[ss])) {
52158f0484fSRodney W. Grimes 		case OCHAR:
52258f0484fSRodney W. Grimes 			if (sp == stop || *sp++ != (char)OPND(s))
52358f0484fSRodney W. Grimes 				return(NULL);
52458f0484fSRodney W. Grimes 			break;
52558f0484fSRodney W. Grimes 		case OANY:
52658f0484fSRodney W. Grimes 			if (sp == stop)
52758f0484fSRodney W. Grimes 				return(NULL);
52858f0484fSRodney W. Grimes 			sp++;
52958f0484fSRodney W. Grimes 			break;
53058f0484fSRodney W. Grimes 		case OANYOF:
53158f0484fSRodney W. Grimes 			cs = &m->g->sets[OPND(s)];
53258f0484fSRodney W. Grimes 			if (sp == stop || !CHIN(cs, *sp++))
53358f0484fSRodney W. Grimes 				return(NULL);
53458f0484fSRodney W. Grimes 			break;
53558f0484fSRodney W. Grimes 		case OBOL:
53658f0484fSRodney W. Grimes 			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
53758f0484fSRodney W. Grimes 					(sp < m->endp && *(sp-1) == '\n' &&
53858f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) )
53958f0484fSRodney W. Grimes 				{ /* yes */ }
54058f0484fSRodney W. Grimes 			else
54158f0484fSRodney W. Grimes 				return(NULL);
54258f0484fSRodney W. Grimes 			break;
54358f0484fSRodney W. Grimes 		case OEOL:
54458f0484fSRodney W. Grimes 			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
54558f0484fSRodney W. Grimes 					(sp < m->endp && *sp == '\n' &&
54658f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) )
54758f0484fSRodney W. Grimes 				{ /* yes */ }
54858f0484fSRodney W. Grimes 			else
54958f0484fSRodney W. Grimes 				return(NULL);
55058f0484fSRodney W. Grimes 			break;
55158f0484fSRodney W. Grimes 		case OBOW:
55258f0484fSRodney W. Grimes 			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
55358f0484fSRodney W. Grimes 					(sp < m->endp && *(sp-1) == '\n' &&
55458f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) ||
55558f0484fSRodney W. Grimes 					(sp > m->beginp &&
55658f0484fSRodney W. Grimes 							!ISWORD(*(sp-1))) ) &&
55758f0484fSRodney W. Grimes 					(sp < m->endp && ISWORD(*sp)) )
55858f0484fSRodney W. Grimes 				{ /* yes */ }
55958f0484fSRodney W. Grimes 			else
56058f0484fSRodney W. Grimes 				return(NULL);
56158f0484fSRodney W. Grimes 			break;
56258f0484fSRodney W. Grimes 		case OEOW:
56358f0484fSRodney W. Grimes 			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
56458f0484fSRodney W. Grimes 					(sp < m->endp && *sp == '\n' &&
56558f0484fSRodney W. Grimes 						(m->g->cflags&REG_NEWLINE)) ||
56658f0484fSRodney W. Grimes 					(sp < m->endp && !ISWORD(*sp)) ) &&
56758f0484fSRodney W. Grimes 					(sp > m->beginp && ISWORD(*(sp-1))) )
56858f0484fSRodney W. Grimes 				{ /* yes */ }
56958f0484fSRodney W. Grimes 			else
57058f0484fSRodney W. Grimes 				return(NULL);
57158f0484fSRodney W. Grimes 			break;
57258f0484fSRodney W. Grimes 		case O_QUEST:
57358f0484fSRodney W. Grimes 			break;
57458f0484fSRodney W. Grimes 		case OOR1:	/* matches null but needs to skip */
57558f0484fSRodney W. Grimes 			ss++;
57658f0484fSRodney W. Grimes 			s = m->g->strip[ss];
57758f0484fSRodney W. Grimes 			do {
57858f0484fSRodney W. Grimes 				assert(OP(s) == OOR2);
57958f0484fSRodney W. Grimes 				ss += OPND(s);
58058f0484fSRodney W. Grimes 			} while (OP(s = m->g->strip[ss]) != O_CH);
58158f0484fSRodney W. Grimes 			/* note that the ss++ gets us past the O_CH */
58258f0484fSRodney W. Grimes 			break;
58358f0484fSRodney W. Grimes 		default:	/* have to make a choice */
58458f0484fSRodney W. Grimes 			hard = 1;
58558f0484fSRodney W. Grimes 			break;
58658f0484fSRodney W. Grimes 		}
58758f0484fSRodney W. Grimes 	if (!hard) {		/* that was it! */
58858f0484fSRodney W. Grimes 		if (sp != stop)
58958f0484fSRodney W. Grimes 			return(NULL);
59058f0484fSRodney W. Grimes 		return(sp);
59158f0484fSRodney W. Grimes 	}
59258f0484fSRodney W. Grimes 	ss--;			/* adjust for the for's final increment */
59358f0484fSRodney W. Grimes 
59458f0484fSRodney W. Grimes 	/* the hard stuff */
59558f0484fSRodney W. Grimes 	AT("hard", sp, stop, ss, stopst);
59658f0484fSRodney W. Grimes 	s = m->g->strip[ss];
59758f0484fSRodney W. Grimes 	switch (OP(s)) {
59858f0484fSRodney W. Grimes 	case OBACK_:		/* the vilest depths */
59958f0484fSRodney W. Grimes 		i = OPND(s);
60058f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
60158f0484fSRodney W. Grimes 		if (m->pmatch[i].rm_eo == -1)
60258f0484fSRodney W. Grimes 			return(NULL);
60358f0484fSRodney W. Grimes 		assert(m->pmatch[i].rm_so != -1);
60458f0484fSRodney W. Grimes 		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
60558f0484fSRodney W. Grimes 		assert(stop - m->beginp >= len);
60658f0484fSRodney W. Grimes 		if (sp > stop - len)
60758f0484fSRodney W. Grimes 			return(NULL);	/* not enough left to match */
60858f0484fSRodney W. Grimes 		ssp = m->offp + m->pmatch[i].rm_so;
60958f0484fSRodney W. Grimes 		if (memcmp(sp, ssp, len) != 0)
61058f0484fSRodney W. Grimes 			return(NULL);
61158f0484fSRodney W. Grimes 		while (m->g->strip[ss] != SOP(O_BACK, i))
61258f0484fSRodney W. Grimes 			ss++;
61358f0484fSRodney W. Grimes 		return(backref(m, sp+len, stop, ss+1, stopst, lev));
61458f0484fSRodney W. Grimes 		break;
61558f0484fSRodney W. Grimes 	case OQUEST_:		/* to null or not */
61658f0484fSRodney W. Grimes 		dp = backref(m, sp, stop, ss+1, stopst, lev);
61758f0484fSRodney W. Grimes 		if (dp != NULL)
61858f0484fSRodney W. Grimes 			return(dp);	/* not */
61958f0484fSRodney W. Grimes 		return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
62058f0484fSRodney W. Grimes 		break;
62158f0484fSRodney W. Grimes 	case OPLUS_:
62258f0484fSRodney W. Grimes 		assert(m->lastpos != NULL);
62358f0484fSRodney W. Grimes 		assert(lev+1 <= m->g->nplus);
62458f0484fSRodney W. Grimes 		m->lastpos[lev+1] = sp;
62558f0484fSRodney W. Grimes 		return(backref(m, sp, stop, ss+1, stopst, lev+1));
62658f0484fSRodney W. Grimes 		break;
62758f0484fSRodney W. Grimes 	case O_PLUS:
62858f0484fSRodney W. Grimes 		if (sp == m->lastpos[lev])	/* last pass matched null */
62958f0484fSRodney W. Grimes 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
63058f0484fSRodney W. Grimes 		/* try another pass */
63158f0484fSRodney W. Grimes 		m->lastpos[lev] = sp;
63258f0484fSRodney W. Grimes 		dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
63358f0484fSRodney W. Grimes 		if (dp == NULL)
63458f0484fSRodney W. Grimes 			return(backref(m, sp, stop, ss+1, stopst, lev-1));
63558f0484fSRodney W. Grimes 		else
63658f0484fSRodney W. Grimes 			return(dp);
63758f0484fSRodney W. Grimes 		break;
63858f0484fSRodney W. Grimes 	case OCH_:		/* find the right one, if any */
63958f0484fSRodney W. Grimes 		ssub = ss + 1;
64058f0484fSRodney W. Grimes 		esub = ss + OPND(s) - 1;
64158f0484fSRodney W. Grimes 		assert(OP(m->g->strip[esub]) == OOR1);
64258f0484fSRodney W. Grimes 		for (;;) {	/* find first matching branch */
64358f0484fSRodney W. Grimes 			dp = backref(m, sp, stop, ssub, esub, lev);
64458f0484fSRodney W. Grimes 			if (dp != NULL)
64558f0484fSRodney W. Grimes 				return(dp);
64658f0484fSRodney W. Grimes 			/* that one missed, try next one */
64758f0484fSRodney W. Grimes 			if (OP(m->g->strip[esub]) == O_CH)
64858f0484fSRodney W. Grimes 				return(NULL);	/* there is none */
64958f0484fSRodney W. Grimes 			esub++;
65058f0484fSRodney W. Grimes 			assert(OP(m->g->strip[esub]) == OOR2);
65158f0484fSRodney W. Grimes 			ssub = esub + 1;
65258f0484fSRodney W. Grimes 			esub += OPND(m->g->strip[esub]);
65358f0484fSRodney W. Grimes 			if (OP(m->g->strip[esub]) == OOR2)
65458f0484fSRodney W. Grimes 				esub--;
65558f0484fSRodney W. Grimes 			else
65658f0484fSRodney W. Grimes 				assert(OP(m->g->strip[esub]) == O_CH);
65758f0484fSRodney W. Grimes 		}
65858f0484fSRodney W. Grimes 		break;
65958f0484fSRodney W. Grimes 	case OLPAREN:		/* must undo assignment if rest fails */
66058f0484fSRodney W. Grimes 		i = OPND(s);
66158f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
66258f0484fSRodney W. Grimes 		offsave = m->pmatch[i].rm_so;
66358f0484fSRodney W. Grimes 		m->pmatch[i].rm_so = sp - m->offp;
66458f0484fSRodney W. Grimes 		dp = backref(m, sp, stop, ss+1, stopst, lev);
66558f0484fSRodney W. Grimes 		if (dp != NULL)
66658f0484fSRodney W. Grimes 			return(dp);
66758f0484fSRodney W. Grimes 		m->pmatch[i].rm_so = offsave;
66858f0484fSRodney W. Grimes 		return(NULL);
66958f0484fSRodney W. Grimes 		break;
67058f0484fSRodney W. Grimes 	case ORPAREN:		/* must undo assignment if rest fails */
67158f0484fSRodney W. Grimes 		i = OPND(s);
67258f0484fSRodney W. Grimes 		assert(0 < i && i <= m->g->nsub);
67358f0484fSRodney W. Grimes 		offsave = m->pmatch[i].rm_eo;
67458f0484fSRodney W. Grimes 		m->pmatch[i].rm_eo = sp - m->offp;
67558f0484fSRodney W. Grimes 		dp = backref(m, sp, stop, ss+1, stopst, lev);
67658f0484fSRodney W. Grimes 		if (dp != NULL)
67758f0484fSRodney W. Grimes 			return(dp);
67858f0484fSRodney W. Grimes 		m->pmatch[i].rm_eo = offsave;
67958f0484fSRodney W. Grimes 		return(NULL);
68058f0484fSRodney W. Grimes 		break;
68158f0484fSRodney W. Grimes 	default:		/* uh oh */
68258f0484fSRodney W. Grimes 		assert(nope);
68358f0484fSRodney W. Grimes 		break;
68458f0484fSRodney W. Grimes 	}
68558f0484fSRodney W. Grimes 
68658f0484fSRodney W. Grimes 	/* "can't happen" */
68758f0484fSRodney W. Grimes 	assert(nope);
68858f0484fSRodney W. Grimes 	/* NOTREACHED */
68916252f11SPoul-Henning Kamp 	return "shut up gcc";
69058f0484fSRodney W. Grimes }
69158f0484fSRodney W. Grimes 
69258f0484fSRodney W. Grimes /*
69358f0484fSRodney W. Grimes  - fast - step through the string at top speed
69458f0484fSRodney W. Grimes  == static char *fast(register struct match *m, char *start, \
69558f0484fSRodney W. Grimes  ==	char *stop, sopno startst, sopno stopst);
69658f0484fSRodney W. Grimes  */
69758f0484fSRodney W. Grimes static char *			/* where tentative match ended, or NULL */
69858f0484fSRodney W. Grimes fast(m, start, stop, startst, stopst)
69958f0484fSRodney W. Grimes register struct match *m;
70058f0484fSRodney W. Grimes char *start;
70158f0484fSRodney W. Grimes char *stop;
70258f0484fSRodney W. Grimes sopno startst;
70358f0484fSRodney W. Grimes sopno stopst;
70458f0484fSRodney W. Grimes {
70558f0484fSRodney W. Grimes 	register states st = m->st;
70658f0484fSRodney W. Grimes 	register states fresh = m->fresh;
70758f0484fSRodney W. Grimes 	register states tmp = m->tmp;
70858f0484fSRodney W. Grimes 	register char *p = start;
70958f0484fSRodney W. Grimes 	register int c = (start == m->beginp) ? OUT : *(start-1);
71058f0484fSRodney W. Grimes 	register int lastc;	/* previous c */
71158f0484fSRodney W. Grimes 	register int flagch;
71258f0484fSRodney W. Grimes 	register int i;
71358f0484fSRodney W. Grimes 	register char *coldp;	/* last p after which no match was underway */
71458f0484fSRodney W. Grimes 
71558f0484fSRodney W. Grimes 	CLEAR(st);
71658f0484fSRodney W. Grimes 	SET1(st, startst);
71758f0484fSRodney W. Grimes 	st = step(m->g, startst, stopst, st, NOTHING, st);
71858f0484fSRodney W. Grimes 	ASSIGN(fresh, st);
71958f0484fSRodney W. Grimes 	SP("start", st, *p);
72058f0484fSRodney W. Grimes 	coldp = NULL;
72158f0484fSRodney W. Grimes 	for (;;) {
72258f0484fSRodney W. Grimes 		/* next character */
72358f0484fSRodney W. Grimes 		lastc = c;
72458f0484fSRodney W. Grimes 		c = (p == m->endp) ? OUT : *p;
72558f0484fSRodney W. Grimes 		if (EQ(st, fresh))
72658f0484fSRodney W. Grimes 			coldp = p;
72758f0484fSRodney W. Grimes 
72858f0484fSRodney W. Grimes 		/* is there an EOL and/or BOL between lastc and c? */
72958f0484fSRodney W. Grimes 		flagch = '\0';
73058f0484fSRodney W. Grimes 		i = 0;
73158f0484fSRodney W. Grimes 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
73258f0484fSRodney W. Grimes 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
73358f0484fSRodney W. Grimes 			flagch = BOL;
73458f0484fSRodney W. Grimes 			i = m->g->nbol;
73558f0484fSRodney W. Grimes 		}
73658f0484fSRodney W. Grimes 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
73758f0484fSRodney W. Grimes 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
73858f0484fSRodney W. Grimes 			flagch = (flagch == BOL) ? BOLEOL : EOL;
73958f0484fSRodney W. Grimes 			i += m->g->neol;
74058f0484fSRodney W. Grimes 		}
74158f0484fSRodney W. Grimes 		if (i != 0) {
74258f0484fSRodney W. Grimes 			for (; i > 0; i--)
74358f0484fSRodney W. Grimes 				st = step(m->g, startst, stopst, st, flagch, st);
74458f0484fSRodney W. Grimes 			SP("boleol", st, c);
74558f0484fSRodney W. Grimes 		}
74658f0484fSRodney W. Grimes 
74758f0484fSRodney W. Grimes 		/* how about a word boundary? */
74858f0484fSRodney W. Grimes 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
74958f0484fSRodney W. Grimes 					(c != OUT && ISWORD(c)) ) {
75058f0484fSRodney W. Grimes 			flagch = BOW;
75158f0484fSRodney W. Grimes 		}
75258f0484fSRodney W. Grimes 		if ( (lastc != OUT && ISWORD(lastc)) &&
75358f0484fSRodney W. Grimes 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
75458f0484fSRodney W. Grimes 			flagch = EOW;
75558f0484fSRodney W. Grimes 		}
75658f0484fSRodney W. Grimes 		if (flagch == BOW || flagch == EOW) {
75758f0484fSRodney W. Grimes 			st = step(m->g, startst, stopst, st, flagch, st);
75858f0484fSRodney W. Grimes 			SP("boweow", st, c);
75958f0484fSRodney W. Grimes 		}
76058f0484fSRodney W. Grimes 
76158f0484fSRodney W. Grimes 		/* are we done? */
76258f0484fSRodney W. Grimes 		if (ISSET(st, stopst) || p == stop)
76358f0484fSRodney W. Grimes 			break;		/* NOTE BREAK OUT */
76458f0484fSRodney W. Grimes 
76558f0484fSRodney W. Grimes 		/* no, we must deal with this character */
76658f0484fSRodney W. Grimes 		ASSIGN(tmp, st);
76758f0484fSRodney W. Grimes 		ASSIGN(st, fresh);
76858f0484fSRodney W. Grimes 		assert(c != OUT);
76958f0484fSRodney W. Grimes 		st = step(m->g, startst, stopst, tmp, c, st);
77058f0484fSRodney W. Grimes 		SP("aft", st, c);
77158f0484fSRodney W. Grimes 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
77258f0484fSRodney W. Grimes 		p++;
77358f0484fSRodney W. Grimes 	}
77458f0484fSRodney W. Grimes 
77558f0484fSRodney W. Grimes 	assert(coldp != NULL);
77658f0484fSRodney W. Grimes 	m->coldp = coldp;
77758f0484fSRodney W. Grimes 	if (ISSET(st, stopst))
77858f0484fSRodney W. Grimes 		return(p+1);
77958f0484fSRodney W. Grimes 	else
78058f0484fSRodney W. Grimes 		return(NULL);
78158f0484fSRodney W. Grimes }
78258f0484fSRodney W. Grimes 
78358f0484fSRodney W. Grimes /*
78458f0484fSRodney W. Grimes  - slow - step through the string more deliberately
78558f0484fSRodney W. Grimes  == static char *slow(register struct match *m, char *start, \
78658f0484fSRodney W. Grimes  ==	char *stop, sopno startst, sopno stopst);
78758f0484fSRodney W. Grimes  */
78858f0484fSRodney W. Grimes static char *			/* where it ended */
78958f0484fSRodney W. Grimes slow(m, start, stop, startst, stopst)
79058f0484fSRodney W. Grimes register struct match *m;
79158f0484fSRodney W. Grimes char *start;
79258f0484fSRodney W. Grimes char *stop;
79358f0484fSRodney W. Grimes sopno startst;
79458f0484fSRodney W. Grimes sopno stopst;
79558f0484fSRodney W. Grimes {
79658f0484fSRodney W. Grimes 	register states st = m->st;
79758f0484fSRodney W. Grimes 	register states empty = m->empty;
79858f0484fSRodney W. Grimes 	register states tmp = m->tmp;
79958f0484fSRodney W. Grimes 	register char *p = start;
80058f0484fSRodney W. Grimes 	register int c = (start == m->beginp) ? OUT : *(start-1);
80158f0484fSRodney W. Grimes 	register int lastc;	/* previous c */
80258f0484fSRodney W. Grimes 	register int flagch;
80358f0484fSRodney W. Grimes 	register int i;
80458f0484fSRodney W. Grimes 	register char *matchp;	/* last p at which a match ended */
80558f0484fSRodney W. Grimes 
80658f0484fSRodney W. Grimes 	AT("slow", start, stop, startst, stopst);
80758f0484fSRodney W. Grimes 	CLEAR(st);
80858f0484fSRodney W. Grimes 	SET1(st, startst);
80958f0484fSRodney W. Grimes 	SP("sstart", st, *p);
81058f0484fSRodney W. Grimes 	st = step(m->g, startst, stopst, st, NOTHING, st);
81158f0484fSRodney W. Grimes 	matchp = NULL;
81258f0484fSRodney W. Grimes 	for (;;) {
81358f0484fSRodney W. Grimes 		/* next character */
81458f0484fSRodney W. Grimes 		lastc = c;
81558f0484fSRodney W. Grimes 		c = (p == m->endp) ? OUT : *p;
81658f0484fSRodney W. Grimes 
81758f0484fSRodney W. Grimes 		/* is there an EOL and/or BOL between lastc and c? */
81858f0484fSRodney W. Grimes 		flagch = '\0';
81958f0484fSRodney W. Grimes 		i = 0;
82058f0484fSRodney W. Grimes 		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
82158f0484fSRodney W. Grimes 				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
82258f0484fSRodney W. Grimes 			flagch = BOL;
82358f0484fSRodney W. Grimes 			i = m->g->nbol;
82458f0484fSRodney W. Grimes 		}
82558f0484fSRodney W. Grimes 		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
82658f0484fSRodney W. Grimes 				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
82758f0484fSRodney W. Grimes 			flagch = (flagch == BOL) ? BOLEOL : EOL;
82858f0484fSRodney W. Grimes 			i += m->g->neol;
82958f0484fSRodney W. Grimes 		}
83058f0484fSRodney W. Grimes 		if (i != 0) {
83158f0484fSRodney W. Grimes 			for (; i > 0; i--)
83258f0484fSRodney W. Grimes 				st = step(m->g, startst, stopst, st, flagch, st);
83358f0484fSRodney W. Grimes 			SP("sboleol", st, c);
83458f0484fSRodney W. Grimes 		}
83558f0484fSRodney W. Grimes 
83658f0484fSRodney W. Grimes 		/* how about a word boundary? */
83758f0484fSRodney W. Grimes 		if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
83858f0484fSRodney W. Grimes 					(c != OUT && ISWORD(c)) ) {
83958f0484fSRodney W. Grimes 			flagch = BOW;
84058f0484fSRodney W. Grimes 		}
84158f0484fSRodney W. Grimes 		if ( (lastc != OUT && ISWORD(lastc)) &&
84258f0484fSRodney W. Grimes 				(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
84358f0484fSRodney W. Grimes 			flagch = EOW;
84458f0484fSRodney W. Grimes 		}
84558f0484fSRodney W. Grimes 		if (flagch == BOW || flagch == EOW) {
84658f0484fSRodney W. Grimes 			st = step(m->g, startst, stopst, st, flagch, st);
84758f0484fSRodney W. Grimes 			SP("sboweow", st, c);
84858f0484fSRodney W. Grimes 		}
84958f0484fSRodney W. Grimes 
85058f0484fSRodney W. Grimes 		/* are we done? */
85158f0484fSRodney W. Grimes 		if (ISSET(st, stopst))
85258f0484fSRodney W. Grimes 			matchp = p;
85358f0484fSRodney W. Grimes 		if (EQ(st, empty) || p == stop)
85458f0484fSRodney W. Grimes 			break;		/* NOTE BREAK OUT */
85558f0484fSRodney W. Grimes 
85658f0484fSRodney W. Grimes 		/* no, we must deal with this character */
85758f0484fSRodney W. Grimes 		ASSIGN(tmp, st);
85858f0484fSRodney W. Grimes 		ASSIGN(st, empty);
85958f0484fSRodney W. Grimes 		assert(c != OUT);
86058f0484fSRodney W. Grimes 		st = step(m->g, startst, stopst, tmp, c, st);
86158f0484fSRodney W. Grimes 		SP("saft", st, c);
86258f0484fSRodney W. Grimes 		assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
86358f0484fSRodney W. Grimes 		p++;
86458f0484fSRodney W. Grimes 	}
86558f0484fSRodney W. Grimes 
86658f0484fSRodney W. Grimes 	return(matchp);
86758f0484fSRodney W. Grimes }
86858f0484fSRodney W. Grimes 
86958f0484fSRodney W. Grimes 
87058f0484fSRodney W. Grimes /*
87158f0484fSRodney W. Grimes  - step - map set of states reachable before char to set reachable after
87258f0484fSRodney W. Grimes  == static states step(register struct re_guts *g, sopno start, sopno stop, \
87358f0484fSRodney W. Grimes  ==	register states bef, int ch, register states aft);
87458f0484fSRodney W. Grimes  == #define	BOL	(OUT+1)
87558f0484fSRodney W. Grimes  == #define	EOL	(BOL+1)
87658f0484fSRodney W. Grimes  == #define	BOLEOL	(BOL+2)
87758f0484fSRodney W. Grimes  == #define	NOTHING	(BOL+3)
87858f0484fSRodney W. Grimes  == #define	BOW	(BOL+4)
87958f0484fSRodney W. Grimes  == #define	EOW	(BOL+5)
88058f0484fSRodney W. Grimes  == #define	CODEMAX	(BOL+5)		// highest code used
88158f0484fSRodney W. Grimes  == #define	NONCHAR(c)	((c) > CHAR_MAX)
88258f0484fSRodney W. Grimes  == #define	NNONCHAR	(CODEMAX-CHAR_MAX)
88358f0484fSRodney W. Grimes  */
88458f0484fSRodney W. Grimes static states
88558f0484fSRodney W. Grimes step(g, start, stop, bef, ch, aft)
88658f0484fSRodney W. Grimes register struct re_guts *g;
88758f0484fSRodney W. Grimes sopno start;			/* start state within strip */
88858f0484fSRodney W. Grimes sopno stop;			/* state after stop state within strip */
88958f0484fSRodney W. Grimes register states bef;		/* states reachable before */
89058f0484fSRodney W. Grimes int ch;				/* character or NONCHAR code */
89158f0484fSRodney W. Grimes register states aft;		/* states already known reachable after */
89258f0484fSRodney W. Grimes {
89358f0484fSRodney W. Grimes 	register cset *cs;
89458f0484fSRodney W. Grimes 	register sop s;
89558f0484fSRodney W. Grimes 	register sopno pc;
89658f0484fSRodney W. Grimes 	register onestate here;		/* note, macros know this name */
89758f0484fSRodney W. Grimes 	register sopno look;
89858f0484fSRodney W. Grimes 	register int i;
89958f0484fSRodney W. Grimes 
90058f0484fSRodney W. Grimes 	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
90158f0484fSRodney W. Grimes 		s = g->strip[pc];
90258f0484fSRodney W. Grimes 		switch (OP(s)) {
90358f0484fSRodney W. Grimes 		case OEND:
90458f0484fSRodney W. Grimes 			assert(pc == stop-1);
90558f0484fSRodney W. Grimes 			break;
90658f0484fSRodney W. Grimes 		case OCHAR:
90758f0484fSRodney W. Grimes 			/* only characters can match */
90858f0484fSRodney W. Grimes 			assert(!NONCHAR(ch) || ch != (char)OPND(s));
90958f0484fSRodney W. Grimes 			if (ch == (char)OPND(s))
91058f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
91158f0484fSRodney W. Grimes 			break;
91258f0484fSRodney W. Grimes 		case OBOL:
91358f0484fSRodney W. Grimes 			if (ch == BOL || ch == BOLEOL)
91458f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
91558f0484fSRodney W. Grimes 			break;
91658f0484fSRodney W. Grimes 		case OEOL:
91758f0484fSRodney W. Grimes 			if (ch == EOL || ch == BOLEOL)
91858f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
91958f0484fSRodney W. Grimes 			break;
92058f0484fSRodney W. Grimes 		case OBOW:
92158f0484fSRodney W. Grimes 			if (ch == BOW)
92258f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
92358f0484fSRodney W. Grimes 			break;
92458f0484fSRodney W. Grimes 		case OEOW:
92558f0484fSRodney W. Grimes 			if (ch == EOW)
92658f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
92758f0484fSRodney W. Grimes 			break;
92858f0484fSRodney W. Grimes 		case OANY:
92958f0484fSRodney W. Grimes 			if (!NONCHAR(ch))
93058f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
93158f0484fSRodney W. Grimes 			break;
93258f0484fSRodney W. Grimes 		case OANYOF:
93358f0484fSRodney W. Grimes 			cs = &g->sets[OPND(s)];
93458f0484fSRodney W. Grimes 			if (!NONCHAR(ch) && CHIN(cs, ch))
93558f0484fSRodney W. Grimes 				FWD(aft, bef, 1);
93658f0484fSRodney W. Grimes 			break;
93758f0484fSRodney W. Grimes 		case OBACK_:		/* ignored here */
93858f0484fSRodney W. Grimes 		case O_BACK:
93958f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
94058f0484fSRodney W. Grimes 			break;
94158f0484fSRodney W. Grimes 		case OPLUS_:		/* forward, this is just an empty */
94258f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
94358f0484fSRodney W. Grimes 			break;
94458f0484fSRodney W. Grimes 		case O_PLUS:		/* both forward and back */
94558f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
94658f0484fSRodney W. Grimes 			i = ISSETBACK(aft, OPND(s));
94758f0484fSRodney W. Grimes 			BACK(aft, aft, OPND(s));
94858f0484fSRodney W. Grimes 			if (!i && ISSETBACK(aft, OPND(s))) {
94958f0484fSRodney W. Grimes 				/* oho, must reconsider loop body */
95058f0484fSRodney W. Grimes 				pc -= OPND(s) + 1;
95158f0484fSRodney W. Grimes 				INIT(here, pc);
95258f0484fSRodney W. Grimes 			}
95358f0484fSRodney W. Grimes 			break;
95458f0484fSRodney W. Grimes 		case OQUEST_:		/* two branches, both forward */
95558f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
95658f0484fSRodney W. Grimes 			FWD(aft, aft, OPND(s));
95758f0484fSRodney W. Grimes 			break;
95858f0484fSRodney W. Grimes 		case O_QUEST:		/* just an empty */
95958f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
96058f0484fSRodney W. Grimes 			break;
96158f0484fSRodney W. Grimes 		case OLPAREN:		/* not significant here */
96258f0484fSRodney W. Grimes 		case ORPAREN:
96358f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
96458f0484fSRodney W. Grimes 			break;
96558f0484fSRodney W. Grimes 		case OCH_:		/* mark the first two branches */
96658f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
96758f0484fSRodney W. Grimes 			assert(OP(g->strip[pc+OPND(s)]) == OOR2);
96858f0484fSRodney W. Grimes 			FWD(aft, aft, OPND(s));
96958f0484fSRodney W. Grimes 			break;
97058f0484fSRodney W. Grimes 		case OOR1:		/* done a branch, find the O_CH */
97158f0484fSRodney W. Grimes 			if (ISSTATEIN(aft, here)) {
97258f0484fSRodney W. Grimes 				for (look = 1;
97358f0484fSRodney W. Grimes 						OP(s = g->strip[pc+look]) != O_CH;
97458f0484fSRodney W. Grimes 						look += OPND(s))
97558f0484fSRodney W. Grimes 					assert(OP(s) == OOR2);
97658f0484fSRodney W. Grimes 				FWD(aft, aft, look);
97758f0484fSRodney W. Grimes 			}
97858f0484fSRodney W. Grimes 			break;
97958f0484fSRodney W. Grimes 		case OOR2:		/* propagate OCH_'s marking */
98058f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
98158f0484fSRodney W. Grimes 			if (OP(g->strip[pc+OPND(s)]) != O_CH) {
98258f0484fSRodney W. Grimes 				assert(OP(g->strip[pc+OPND(s)]) == OOR2);
98358f0484fSRodney W. Grimes 				FWD(aft, aft, OPND(s));
98458f0484fSRodney W. Grimes 			}
98558f0484fSRodney W. Grimes 			break;
98658f0484fSRodney W. Grimes 		case O_CH:		/* just empty */
98758f0484fSRodney W. Grimes 			FWD(aft, aft, 1);
98858f0484fSRodney W. Grimes 			break;
98958f0484fSRodney W. Grimes 		default:		/* ooooops... */
99058f0484fSRodney W. Grimes 			assert(nope);
99158f0484fSRodney W. Grimes 			break;
99258f0484fSRodney W. Grimes 		}
99358f0484fSRodney W. Grimes 	}
99458f0484fSRodney W. Grimes 
99558f0484fSRodney W. Grimes 	return(aft);
99658f0484fSRodney W. Grimes }
99758f0484fSRodney W. Grimes 
99858f0484fSRodney W. Grimes #ifdef REDEBUG
99958f0484fSRodney W. Grimes /*
100058f0484fSRodney W. Grimes  - print - print a set of states
100158f0484fSRodney W. Grimes  == #ifdef REDEBUG
100258f0484fSRodney W. Grimes  == static void print(struct match *m, char *caption, states st, \
100358f0484fSRodney W. Grimes  ==	int ch, FILE *d);
100458f0484fSRodney W. Grimes  == #endif
100558f0484fSRodney W. Grimes  */
100658f0484fSRodney W. Grimes static void
100758f0484fSRodney W. Grimes print(m, caption, st, ch, d)
100858f0484fSRodney W. Grimes struct match *m;
100958f0484fSRodney W. Grimes char *caption;
101058f0484fSRodney W. Grimes states st;
101158f0484fSRodney W. Grimes int ch;
101258f0484fSRodney W. Grimes FILE *d;
101358f0484fSRodney W. Grimes {
101458f0484fSRodney W. Grimes 	register struct re_guts *g = m->g;
101558f0484fSRodney W. Grimes 	register int i;
101658f0484fSRodney W. Grimes 	register int first = 1;
101758f0484fSRodney W. Grimes 
101858f0484fSRodney W. Grimes 	if (!(m->eflags&REG_TRACE))
101958f0484fSRodney W. Grimes 		return;
102058f0484fSRodney W. Grimes 
102158f0484fSRodney W. Grimes 	fprintf(d, "%s", caption);
102258f0484fSRodney W. Grimes 	if (ch != '\0')
102358f0484fSRodney W. Grimes 		fprintf(d, " %s", pchar(ch));
102458f0484fSRodney W. Grimes 	for (i = 0; i < g->nstates; i++)
102558f0484fSRodney W. Grimes 		if (ISSET(st, i)) {
102658f0484fSRodney W. Grimes 			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
102758f0484fSRodney W. Grimes 			first = 0;
102858f0484fSRodney W. Grimes 		}
102958f0484fSRodney W. Grimes 	fprintf(d, "\n");
103058f0484fSRodney W. Grimes }
103158f0484fSRodney W. Grimes 
103258f0484fSRodney W. Grimes /*
103358f0484fSRodney W. Grimes  - at - print current situation
103458f0484fSRodney W. Grimes  == #ifdef REDEBUG
103558f0484fSRodney W. Grimes  == static void at(struct match *m, char *title, char *start, char *stop, \
103658f0484fSRodney W. Grimes  ==						sopno startst, sopno stopst);
103758f0484fSRodney W. Grimes  == #endif
103858f0484fSRodney W. Grimes  */
103958f0484fSRodney W. Grimes static void
104058f0484fSRodney W. Grimes at(m, title, start, stop, startst, stopst)
104158f0484fSRodney W. Grimes struct match *m;
104258f0484fSRodney W. Grimes char *title;
104358f0484fSRodney W. Grimes char *start;
104458f0484fSRodney W. Grimes char *stop;
104558f0484fSRodney W. Grimes sopno startst;
104658f0484fSRodney W. Grimes sopno stopst;
104758f0484fSRodney W. Grimes {
104858f0484fSRodney W. Grimes 	if (!(m->eflags&REG_TRACE))
104958f0484fSRodney W. Grimes 		return;
105058f0484fSRodney W. Grimes 
105158f0484fSRodney W. Grimes 	printf("%s %s-", title, pchar(*start));
105258f0484fSRodney W. Grimes 	printf("%s ", pchar(*stop));
105358f0484fSRodney W. Grimes 	printf("%ld-%ld\n", (long)startst, (long)stopst);
105458f0484fSRodney W. Grimes }
105558f0484fSRodney W. Grimes 
105658f0484fSRodney W. Grimes #ifndef PCHARDONE
105758f0484fSRodney W. Grimes #define	PCHARDONE	/* never again */
105858f0484fSRodney W. Grimes /*
105958f0484fSRodney W. Grimes  - pchar - make a character printable
106058f0484fSRodney W. Grimes  == #ifdef REDEBUG
106158f0484fSRodney W. Grimes  == static char *pchar(int ch);
106258f0484fSRodney W. Grimes  == #endif
106358f0484fSRodney W. Grimes  *
106458f0484fSRodney W. Grimes  * Is this identical to regchar() over in debug.c?  Well, yes.  But a
106558f0484fSRodney W. Grimes  * duplicate here avoids having a debugging-capable regexec.o tied to
106658f0484fSRodney W. Grimes  * a matching debug.o, and this is convenient.  It all disappears in
106758f0484fSRodney W. Grimes  * the non-debug compilation anyway, so it doesn't matter much.
106858f0484fSRodney W. Grimes  */
106958f0484fSRodney W. Grimes static char *			/* -> representation */
107058f0484fSRodney W. Grimes pchar(ch)
107158f0484fSRodney W. Grimes int ch;
107258f0484fSRodney W. Grimes {
107358f0484fSRodney W. Grimes 	static char pbuf[10];
107458f0484fSRodney W. Grimes 
107558f0484fSRodney W. Grimes 	if (isprint(ch) || ch == ' ')
107658f0484fSRodney W. Grimes 		sprintf(pbuf, "%c", ch);
107758f0484fSRodney W. Grimes 	else
107858f0484fSRodney W. Grimes 		sprintf(pbuf, "\\%o", ch);
107958f0484fSRodney W. Grimes 	return(pbuf);
108058f0484fSRodney W. Grimes }
108158f0484fSRodney W. Grimes #endif
108258f0484fSRodney W. Grimes #endif
108358f0484fSRodney W. Grimes 
108458f0484fSRodney W. Grimes #undef	matcher
108558f0484fSRodney W. Grimes #undef	fast
108658f0484fSRodney W. Grimes #undef	slow
108758f0484fSRodney W. Grimes #undef	dissect
108858f0484fSRodney W. Grimes #undef	backref
108958f0484fSRodney W. Grimes #undef	step
109058f0484fSRodney W. Grimes #undef	print
109158f0484fSRodney W. Grimes #undef	at
109258f0484fSRodney W. Grimes #undef	match
1093