158f0484fSRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
458f0484fSRodney W. Grimes * Copyright (c) 1992, 1993, 1994 Henry Spencer.
558f0484fSRodney W. Grimes * Copyright (c) 1992, 1993, 1994
658f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved.
758f0484fSRodney W. Grimes *
858f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by
958f0484fSRodney W. Grimes * Henry Spencer.
1058f0484fSRodney W. Grimes *
1158f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without
1258f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions
1358f0484fSRodney W. Grimes * are met:
1458f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
1558f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer.
1658f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
1758f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
1858f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution.
19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
2058f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software
2158f0484fSRodney W. Grimes * without specific prior written permission.
2258f0484fSRodney W. Grimes *
2358f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2458f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2558f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2658f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2758f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2858f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2958f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3058f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3158f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3258f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3358f0484fSRodney W. Grimes * SUCH DAMAGE.
3458f0484fSRodney W. Grimes */
3558f0484fSRodney W. Grimes
36a0bf5d8aSKyle Evans #include <stdbool.h>
37a0bf5d8aSKyle Evans
3858f0484fSRodney W. Grimes /*
3958f0484fSRodney W. Grimes * The matching engine and friends. This file is #included by regexec.c
4058f0484fSRodney W. Grimes * after suitable #defines of a variety of macros used herein, so that
4158f0484fSRodney W. Grimes * different state representations can be used without duplicating masses
4258f0484fSRodney W. Grimes * of code.
4358f0484fSRodney W. Grimes */
4458f0484fSRodney W. Grimes
4558f0484fSRodney W. Grimes #ifdef SNAMES
4663cbe8d1SYuri Pankov #define stepback sstepback
4758f0484fSRodney W. Grimes #define matcher smatcher
48a0bf5d8aSKyle Evans #define walk swalk
4958f0484fSRodney W. Grimes #define dissect sdissect
5058f0484fSRodney W. Grimes #define backref sbackref
5158f0484fSRodney W. Grimes #define step sstep
5258f0484fSRodney W. Grimes #define print sprint
5358f0484fSRodney W. Grimes #define at sat
5458f0484fSRodney W. Grimes #define match smat
5558f0484fSRodney W. Grimes #endif
5658f0484fSRodney W. Grimes #ifdef LNAMES
5763cbe8d1SYuri Pankov #define stepback lstepback
5858f0484fSRodney W. Grimes #define matcher lmatcher
59a0bf5d8aSKyle Evans #define walk lwalk
6058f0484fSRodney W. Grimes #define dissect ldissect
6158f0484fSRodney W. Grimes #define backref lbackref
6258f0484fSRodney W. Grimes #define step lstep
6358f0484fSRodney W. Grimes #define print lprint
6458f0484fSRodney W. Grimes #define at lat
6558f0484fSRodney W. Grimes #define match lmat
6658f0484fSRodney W. Grimes #endif
67e5996857STim J. Robbins #ifdef MNAMES
6863cbe8d1SYuri Pankov #define stepback mstepback
69e5996857STim J. Robbins #define matcher mmatcher
70a0bf5d8aSKyle Evans #define walk mwalk
71e5996857STim J. Robbins #define dissect mdissect
72e5996857STim J. Robbins #define backref mbackref
73e5996857STim J. Robbins #define step mstep
74e5996857STim J. Robbins #define print mprint
75e5996857STim J. Robbins #define at mat
76e5996857STim J. Robbins #define match mmat
77e5996857STim J. Robbins #endif
7858f0484fSRodney W. Grimes
7958f0484fSRodney W. Grimes /* another structure passed up and down to avoid zillions of parameters */
8058f0484fSRodney W. Grimes struct match {
8158f0484fSRodney W. Grimes struct re_guts *g;
8258f0484fSRodney W. Grimes int eflags;
8358f0484fSRodney W. Grimes regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
84eb2b3d10SXin LI const char *offp; /* offsets work from here */
85eb2b3d10SXin LI const char *beginp; /* start of string -- virtual NUL precedes */
86eb2b3d10SXin LI const char *endp; /* end of string -- virtual NUL here */
87eb2b3d10SXin LI const char *coldp; /* can be no match starting before here */
88eb2b3d10SXin LI const char **lastpos; /* [nplus+1] */
8958f0484fSRodney W. Grimes STATEVARS;
9058f0484fSRodney W. Grimes states st; /* current states */
9158f0484fSRodney W. Grimes states fresh; /* states for a fresh start */
9258f0484fSRodney W. Grimes states tmp; /* temporary */
9358f0484fSRodney W. Grimes states empty; /* empty set of states */
94e5996857STim J. Robbins mbstate_t mbs; /* multibyte conversion state */
9558f0484fSRodney W. Grimes };
9658f0484fSRodney W. Grimes
9758f0484fSRodney W. Grimes /* ========= begin header generated by ./mkh ========= */
9858f0484fSRodney W. Grimes #ifdef __cplusplus
9958f0484fSRodney W. Grimes extern "C" {
10058f0484fSRodney W. Grimes #endif
10158f0484fSRodney W. Grimes
10258f0484fSRodney W. Grimes /* === engine.c === */
103eb2b3d10SXin LI static int matcher(struct re_guts *g, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
104eb2b3d10SXin LI static const char *dissect(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
105eb2b3d10SXin LI static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev, int);
106a0bf5d8aSKyle Evans static const char *walk(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, bool fast);
107ca53e5aeSKyle Evans static states step(struct re_guts *g, sopno start, sopno stop, states bef, wint_t ch, states aft, int sflags);
108082063a0SXin LI #define MAX_RECURSION 100
109e5996857STim J. Robbins #define BOL (OUT-1)
110e5996857STim J. Robbins #define EOL (BOL-1)
111e5996857STim J. Robbins #define BOLEOL (BOL-2)
112e5996857STim J. Robbins #define NOTHING (BOL-3)
113e5996857STim J. Robbins #define BOW (BOL-4)
114e5996857STim J. Robbins #define EOW (BOL-5)
115e5996857STim J. Robbins #define BADCHAR (BOL-6)
116*6b986646SKyle Evans #define NWBND (BOL-7)
117e5996857STim J. Robbins #define NONCHAR(c) ((c) <= OUT)
118ca53e5aeSKyle Evans /* sflags */
119ca53e5aeSKyle Evans #define SBOS 0x0001
120ca53e5aeSKyle Evans #define SEOS 0x0002
121ca53e5aeSKyle Evans
12258f0484fSRodney W. Grimes #ifdef REDEBUG
123eb2b3d10SXin LI static void print(struct match *m, const char *caption, states st, int ch, FILE *d);
12458f0484fSRodney W. Grimes #endif
12558f0484fSRodney W. Grimes #ifdef REDEBUG
126eb2b3d10SXin LI static void at(struct match *m, const char *title, const char *start, const char *stop, sopno startst, sopno stopst);
12758f0484fSRodney W. Grimes #endif
12858f0484fSRodney W. Grimes #ifdef REDEBUG
129eb2b3d10SXin LI static const char *pchar(int ch);
13058f0484fSRodney W. Grimes #endif
13158f0484fSRodney W. Grimes
13258f0484fSRodney W. Grimes #ifdef __cplusplus
13358f0484fSRodney W. Grimes }
13458f0484fSRodney W. Grimes #endif
13558f0484fSRodney W. Grimes /* ========= end header generated by ./mkh ========= */
13658f0484fSRodney W. Grimes
13758f0484fSRodney W. Grimes #ifdef REDEBUG
13858f0484fSRodney W. Grimes #define SP(t, s, c) print(m, t, s, c, stdout)
13958f0484fSRodney W. Grimes #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
14058f0484fSRodney W. Grimes #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); }
14158f0484fSRodney W. Grimes #else
14258f0484fSRodney W. Grimes #define SP(t, s, c) /* nothing */
14358f0484fSRodney W. Grimes #define AT(t, p1, p2, s1, s2) /* nothing */
14458f0484fSRodney W. Grimes #define NOTE(s) /* nothing */
14558f0484fSRodney W. Grimes #endif
14658f0484fSRodney W. Grimes
14758f0484fSRodney W. Grimes /*
14863cbe8d1SYuri Pankov * Given a multibyte string pointed to by start, step back nchar characters
14963cbe8d1SYuri Pankov * from current position pointed to by cur.
15063cbe8d1SYuri Pankov */
15163cbe8d1SYuri Pankov static const char *
stepback(const char * start,const char * cur,int nchar)15263cbe8d1SYuri Pankov stepback(const char *start, const char *cur, int nchar)
15363cbe8d1SYuri Pankov {
15463cbe8d1SYuri Pankov const char *ret;
15563cbe8d1SYuri Pankov int wc, mbc;
15663cbe8d1SYuri Pankov mbstate_t mbs;
15763cbe8d1SYuri Pankov size_t clen;
15863cbe8d1SYuri Pankov
15963cbe8d1SYuri Pankov if (MB_CUR_MAX == 1)
16063cbe8d1SYuri Pankov return ((cur - nchar) > start ? cur - nchar : NULL);
16163cbe8d1SYuri Pankov
16263cbe8d1SYuri Pankov ret = cur;
16363cbe8d1SYuri Pankov for (wc = nchar; wc > 0; wc--) {
16463cbe8d1SYuri Pankov for (mbc = 1; mbc <= MB_CUR_MAX; mbc++) {
16563cbe8d1SYuri Pankov if ((ret - mbc) < start)
16663cbe8d1SYuri Pankov return (NULL);
16763cbe8d1SYuri Pankov memset(&mbs, 0, sizeof(mbs));
16863cbe8d1SYuri Pankov clen = mbrtowc(NULL, ret - mbc, mbc, &mbs);
16963cbe8d1SYuri Pankov if (clen != (size_t)-1 && clen != (size_t)-2)
17063cbe8d1SYuri Pankov break;
17163cbe8d1SYuri Pankov }
17263cbe8d1SYuri Pankov if (mbc > MB_CUR_MAX)
17363cbe8d1SYuri Pankov return (NULL);
17463cbe8d1SYuri Pankov ret -= mbc;
17563cbe8d1SYuri Pankov }
17663cbe8d1SYuri Pankov
17763cbe8d1SYuri Pankov return (ret);
17863cbe8d1SYuri Pankov }
17963cbe8d1SYuri Pankov
18063cbe8d1SYuri Pankov /*
18158f0484fSRodney W. Grimes - matcher - the actual matching engine
182eb2b3d10SXin LI == static int matcher(struct re_guts *g, const char *string, \
18358f0484fSRodney W. Grimes == size_t nmatch, regmatch_t pmatch[], int eflags);
18458f0484fSRodney W. Grimes */
18558f0484fSRodney W. Grimes static int /* 0 success, REG_NOMATCH failure */
matcher(struct re_guts * g,const char * string,size_t nmatch,regmatch_t pmatch[],int eflags)186eb2b3d10SXin LI matcher(struct re_guts *g,
187eb2b3d10SXin LI const char *string,
188eb2b3d10SXin LI size_t nmatch,
189eb2b3d10SXin LI regmatch_t pmatch[],
190eb2b3d10SXin LI int eflags)
19158f0484fSRodney W. Grimes {
192eb2b3d10SXin LI const char *endp;
193039b877eSPedro F. Giffuni size_t i;
19458f0484fSRodney W. Grimes struct match mv;
1958fb3f3f6SDavid E. O'Brien struct match *m = &mv;
196d58abbfeSPedro F. Giffuni const char *dp = NULL;
1978fb3f3f6SDavid E. O'Brien const sopno gf = g->firststate+1; /* +1 for OEND */
1988fb3f3f6SDavid E. O'Brien const sopno gl = g->laststate;
199eb2b3d10SXin LI const char *start;
200eb2b3d10SXin LI const char *stop;
2016049d9f0SDaniel C. Sobral /* Boyer-Moore algorithms variables */
202eb2b3d10SXin LI const char *pp;
2036049d9f0SDaniel C. Sobral int cj, mj;
204eb2b3d10SXin LI const char *mustfirst;
205eb2b3d10SXin LI const char *mustlast;
2068fb3f3f6SDavid E. O'Brien int *matchjump;
2078fb3f3f6SDavid E. O'Brien int *charjump;
20858f0484fSRodney W. Grimes
20958f0484fSRodney W. Grimes /* simplify the situation where possible */
21058f0484fSRodney W. Grimes if (g->cflags®_NOSUB)
21158f0484fSRodney W. Grimes nmatch = 0;
21258f0484fSRodney W. Grimes if (eflags®_STARTEND) {
21358f0484fSRodney W. Grimes start = string + pmatch[0].rm_so;
21458f0484fSRodney W. Grimes stop = string + pmatch[0].rm_eo;
21558f0484fSRodney W. Grimes } else {
21658f0484fSRodney W. Grimes start = string;
21758f0484fSRodney W. Grimes stop = start + strlen(start);
21858f0484fSRodney W. Grimes }
21958f0484fSRodney W. Grimes if (stop < start)
22058f0484fSRodney W. Grimes return(REG_INVARG);
22158f0484fSRodney W. Grimes
22258f0484fSRodney W. Grimes /* prescreening; this does wonders for this rather slow code */
22358f0484fSRodney W. Grimes if (g->must != NULL) {
2246049d9f0SDaniel C. Sobral if (g->charjump != NULL && g->matchjump != NULL) {
2256049d9f0SDaniel C. Sobral mustfirst = g->must;
2266049d9f0SDaniel C. Sobral mustlast = g->must + g->mlen - 1;
2276049d9f0SDaniel C. Sobral charjump = g->charjump;
2286049d9f0SDaniel C. Sobral matchjump = g->matchjump;
2296049d9f0SDaniel C. Sobral pp = mustlast;
230c5e125bbSDaniel C. Sobral for (dp = start+g->mlen-1; dp < stop;) {
2316049d9f0SDaniel C. Sobral /* Fast skip non-matches */
232e0554a53SJacques Vidrine while (dp < stop && charjump[(int)*dp])
233e0554a53SJacques Vidrine dp += charjump[(int)*dp];
2346049d9f0SDaniel C. Sobral
235c5e125bbSDaniel C. Sobral if (dp >= stop)
2366049d9f0SDaniel C. Sobral break;
2376049d9f0SDaniel C. Sobral
2386049d9f0SDaniel C. Sobral /* Greedy matcher */
2396049d9f0SDaniel C. Sobral /* We depend on not being used for
2406049d9f0SDaniel C. Sobral * for strings of length 1
2416049d9f0SDaniel C. Sobral */
242c5e125bbSDaniel C. Sobral while (*--dp == *--pp && pp != mustfirst);
2436049d9f0SDaniel C. Sobral
244c5e125bbSDaniel C. Sobral if (*dp == *pp)
2456049d9f0SDaniel C. Sobral break;
2466049d9f0SDaniel C. Sobral
2476049d9f0SDaniel C. Sobral /* Jump to next possible match */
2486049d9f0SDaniel C. Sobral mj = matchjump[pp - mustfirst];
249e0554a53SJacques Vidrine cj = charjump[(int)*dp];
250c5e125bbSDaniel C. Sobral dp += (cj < mj ? mj : cj);
2516049d9f0SDaniel C. Sobral pp = mustlast;
2526049d9f0SDaniel C. Sobral }
2536049d9f0SDaniel C. Sobral if (pp != mustfirst)
2546049d9f0SDaniel C. Sobral return(REG_NOMATCH);
2556049d9f0SDaniel C. Sobral } else {
25658f0484fSRodney W. Grimes for (dp = start; dp < stop; dp++)
2576049d9f0SDaniel C. Sobral if (*dp == g->must[0] &&
2586049d9f0SDaniel C. Sobral stop - dp >= g->mlen &&
25958f0484fSRodney W. Grimes memcmp(dp, g->must, (size_t)g->mlen) == 0)
26058f0484fSRodney W. Grimes break;
26158f0484fSRodney W. Grimes if (dp == stop) /* we didn't find g->must */
26258f0484fSRodney W. Grimes return(REG_NOMATCH);
26358f0484fSRodney W. Grimes }
2646049d9f0SDaniel C. Sobral }
26558f0484fSRodney W. Grimes
26658f0484fSRodney W. Grimes /* match struct setup */
26758f0484fSRodney W. Grimes m->g = g;
26858f0484fSRodney W. Grimes m->eflags = eflags;
26958f0484fSRodney W. Grimes m->pmatch = NULL;
27058f0484fSRodney W. Grimes m->lastpos = NULL;
27158f0484fSRodney W. Grimes m->offp = string;
27258f0484fSRodney W. Grimes m->beginp = start;
27358f0484fSRodney W. Grimes m->endp = stop;
27458f0484fSRodney W. Grimes STATESETUP(m, 4);
27558f0484fSRodney W. Grimes SETUP(m->st);
27658f0484fSRodney W. Grimes SETUP(m->fresh);
27758f0484fSRodney W. Grimes SETUP(m->tmp);
27858f0484fSRodney W. Grimes SETUP(m->empty);
27958f0484fSRodney W. Grimes CLEAR(m->empty);
280e5996857STim J. Robbins ZAPSTATE(&m->mbs);
28158f0484fSRodney W. Grimes
282e6a886d8SDaniel C. Sobral /* Adjust start according to moffset, to speed things up */
28363cbe8d1SYuri Pankov if (dp != NULL && g->moffset > -1) {
28463cbe8d1SYuri Pankov const char *nstart;
28563cbe8d1SYuri Pankov
28663cbe8d1SYuri Pankov nstart = stepback(start, dp, g->moffset);
28763cbe8d1SYuri Pankov if (nstart != NULL)
28863cbe8d1SYuri Pankov start = nstart;
28963cbe8d1SYuri Pankov }
290e6a886d8SDaniel C. Sobral
291bca3476aSDiomidis Spinellis SP("mloop", m->st, *start);
292bca3476aSDiomidis Spinellis
29358f0484fSRodney W. Grimes /* this loop does only one repetition except for backrefs */
29458f0484fSRodney W. Grimes for (;;) {
295a0bf5d8aSKyle Evans endp = walk(m, start, stop, gf, gl, true);
29658f0484fSRodney W. Grimes if (endp == NULL) { /* a miss */
297c7ce9e21SDiomidis Spinellis if (m->pmatch != NULL)
298c7ce9e21SDiomidis Spinellis free((char *)m->pmatch);
299c7ce9e21SDiomidis Spinellis if (m->lastpos != NULL)
300c7ce9e21SDiomidis Spinellis free((char *)m->lastpos);
30158f0484fSRodney W. Grimes STATETEARDOWN(m);
30258f0484fSRodney W. Grimes return(REG_NOMATCH);
30358f0484fSRodney W. Grimes }
30458f0484fSRodney W. Grimes if (nmatch == 0 && !g->backrefs)
30558f0484fSRodney W. Grimes break; /* no further info needed */
30658f0484fSRodney W. Grimes
30758f0484fSRodney W. Grimes /* where? */
30858f0484fSRodney W. Grimes assert(m->coldp != NULL);
30958f0484fSRodney W. Grimes for (;;) {
31058f0484fSRodney W. Grimes NOTE("finding start");
311a0bf5d8aSKyle Evans endp = walk(m, m->coldp, stop, gf, gl, false);
31258f0484fSRodney W. Grimes if (endp != NULL)
31358f0484fSRodney W. Grimes break;
31458f0484fSRodney W. Grimes assert(m->coldp < m->endp);
315e5996857STim J. Robbins m->coldp += XMBRTOWC(NULL, m->coldp,
316e5996857STim J. Robbins m->endp - m->coldp, &m->mbs, 0);
31758f0484fSRodney W. Grimes }
31858f0484fSRodney W. Grimes if (nmatch == 1 && !g->backrefs)
31958f0484fSRodney W. Grimes break; /* no further info needed */
32058f0484fSRodney W. Grimes
32158f0484fSRodney W. Grimes /* oh my, he wants the subexpressions... */
32258f0484fSRodney W. Grimes if (m->pmatch == NULL)
32358f0484fSRodney W. Grimes m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
32458f0484fSRodney W. Grimes sizeof(regmatch_t));
32558f0484fSRodney W. Grimes if (m->pmatch == NULL) {
32658f0484fSRodney W. Grimes STATETEARDOWN(m);
32758f0484fSRodney W. Grimes return(REG_ESPACE);
32858f0484fSRodney W. Grimes }
32958f0484fSRodney W. Grimes for (i = 1; i <= m->g->nsub; i++)
33058f0484fSRodney W. Grimes m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
33158f0484fSRodney W. Grimes if (!g->backrefs && !(m->eflags®_BACKR)) {
33258f0484fSRodney W. Grimes NOTE("dissecting");
33358f0484fSRodney W. Grimes dp = dissect(m, m->coldp, endp, gf, gl);
33458f0484fSRodney W. Grimes } else {
33558f0484fSRodney W. Grimes if (g->nplus > 0 && m->lastpos == NULL)
336eb2b3d10SXin LI m->lastpos = malloc((g->nplus+1) *
337eb2b3d10SXin LI sizeof(const char *));
33858f0484fSRodney W. Grimes if (g->nplus > 0 && m->lastpos == NULL) {
33958f0484fSRodney W. Grimes free(m->pmatch);
34058f0484fSRodney W. Grimes STATETEARDOWN(m);
34158f0484fSRodney W. Grimes return(REG_ESPACE);
34258f0484fSRodney W. Grimes }
34358f0484fSRodney W. Grimes NOTE("backref dissect");
344082063a0SXin LI dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
34558f0484fSRodney W. Grimes }
34658f0484fSRodney W. Grimes if (dp != NULL)
34758f0484fSRodney W. Grimes break;
34858f0484fSRodney W. Grimes
34958f0484fSRodney W. Grimes /* uh-oh... we couldn't find a subexpression-level match */
35058f0484fSRodney W. Grimes assert(g->backrefs); /* must be back references doing it */
35158f0484fSRodney W. Grimes assert(g->nplus == 0 || m->lastpos != NULL);
35258f0484fSRodney W. Grimes for (;;) {
35358f0484fSRodney W. Grimes if (dp != NULL || endp <= m->coldp)
35458f0484fSRodney W. Grimes break; /* defeat */
35558f0484fSRodney W. Grimes NOTE("backoff");
356a0bf5d8aSKyle Evans endp = walk(m, m->coldp, endp-1, gf, gl, false);
35758f0484fSRodney W. Grimes if (endp == NULL)
35858f0484fSRodney W. Grimes break; /* defeat */
35958f0484fSRodney W. Grimes /* try it on a shorter possibility */
36058f0484fSRodney W. Grimes #ifndef NDEBUG
36158f0484fSRodney W. Grimes for (i = 1; i <= m->g->nsub; i++) {
36258f0484fSRodney W. Grimes assert(m->pmatch[i].rm_so == -1);
36358f0484fSRodney W. Grimes assert(m->pmatch[i].rm_eo == -1);
36458f0484fSRodney W. Grimes }
36558f0484fSRodney W. Grimes #endif
36658f0484fSRodney W. Grimes NOTE("backoff dissect");
367082063a0SXin LI dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
36858f0484fSRodney W. Grimes }
36958f0484fSRodney W. Grimes assert(dp == NULL || dp == endp);
37058f0484fSRodney W. Grimes if (dp != NULL) /* found a shorter one */
37158f0484fSRodney W. Grimes break;
37258f0484fSRodney W. Grimes
37358f0484fSRodney W. Grimes /* despite initial appearances, there is no match here */
37458f0484fSRodney W. Grimes NOTE("false alarm");
375e5996857STim J. Robbins /* recycle starting later */
376e5996857STim J. Robbins start = m->coldp + XMBRTOWC(NULL, m->coldp,
377bd9643b1STim J. Robbins stop - m->coldp, &m->mbs, 0);
37858f0484fSRodney W. Grimes assert(start <= stop);
37958f0484fSRodney W. Grimes }
38058f0484fSRodney W. Grimes
38158f0484fSRodney W. Grimes /* fill in the details if requested */
38258f0484fSRodney W. Grimes if (nmatch > 0) {
38358f0484fSRodney W. Grimes pmatch[0].rm_so = m->coldp - m->offp;
38458f0484fSRodney W. Grimes pmatch[0].rm_eo = endp - m->offp;
38558f0484fSRodney W. Grimes }
38658f0484fSRodney W. Grimes if (nmatch > 1) {
38758f0484fSRodney W. Grimes assert(m->pmatch != NULL);
38858f0484fSRodney W. Grimes for (i = 1; i < nmatch; i++)
38958f0484fSRodney W. Grimes if (i <= m->g->nsub)
39058f0484fSRodney W. Grimes pmatch[i] = m->pmatch[i];
39158f0484fSRodney W. Grimes else {
39258f0484fSRodney W. Grimes pmatch[i].rm_so = -1;
39358f0484fSRodney W. Grimes pmatch[i].rm_eo = -1;
39458f0484fSRodney W. Grimes }
39558f0484fSRodney W. Grimes }
39658f0484fSRodney W. Grimes
39758f0484fSRodney W. Grimes if (m->pmatch != NULL)
39858f0484fSRodney W. Grimes free((char *)m->pmatch);
39958f0484fSRodney W. Grimes if (m->lastpos != NULL)
40058f0484fSRodney W. Grimes free((char *)m->lastpos);
40158f0484fSRodney W. Grimes STATETEARDOWN(m);
40258f0484fSRodney W. Grimes return(0);
40358f0484fSRodney W. Grimes }
40458f0484fSRodney W. Grimes
40558f0484fSRodney W. Grimes /*
40658f0484fSRodney W. Grimes - dissect - figure out what matched what, no back references
407eb2b3d10SXin LI == static const char *dissect(struct match *m, const char *start, \
408eb2b3d10SXin LI == const char *stop, sopno startst, sopno stopst);
40958f0484fSRodney W. Grimes */
410eb2b3d10SXin LI static const char * /* == stop (success) always */
dissect(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst)411eb2b3d10SXin LI dissect(struct match *m,
412eb2b3d10SXin LI const char *start,
413eb2b3d10SXin LI const char *stop,
414eb2b3d10SXin LI sopno startst,
415eb2b3d10SXin LI sopno stopst)
41658f0484fSRodney W. Grimes {
4178fb3f3f6SDavid E. O'Brien int i;
4188fb3f3f6SDavid E. O'Brien sopno ss; /* start sop of current subRE */
4198fb3f3f6SDavid E. O'Brien sopno es; /* end sop of current subRE */
420eb2b3d10SXin LI const char *sp; /* start of string matched by it */
421eb2b3d10SXin LI const char *stp; /* string matched by it cannot pass here */
422eb2b3d10SXin LI const char *rest; /* start of rest of string */
423eb2b3d10SXin LI const char *tail; /* string unmatched by rest of RE */
4248fb3f3f6SDavid E. O'Brien sopno ssub; /* start sop of subsubRE */
4258fb3f3f6SDavid E. O'Brien sopno esub; /* end sop of subsubRE */
426eb2b3d10SXin LI const char *ssp; /* start of string matched by subsubRE */
427eb2b3d10SXin LI const char *sep; /* end of string matched by subsubRE */
428eb2b3d10SXin LI const char *oldssp; /* previous ssp */
429307546ecSToomas Soome const char *dp __unused;
43058f0484fSRodney W. Grimes
43158f0484fSRodney W. Grimes AT("diss", start, stop, startst, stopst);
43258f0484fSRodney W. Grimes sp = start;
43358f0484fSRodney W. Grimes for (ss = startst; ss < stopst; ss = es) {
43458f0484fSRodney W. Grimes /* identify end of subRE */
43558f0484fSRodney W. Grimes es = ss;
43658f0484fSRodney W. Grimes switch (OP(m->g->strip[es])) {
43758f0484fSRodney W. Grimes case OPLUS_:
43858f0484fSRodney W. Grimes case OQUEST_:
43958f0484fSRodney W. Grimes es += OPND(m->g->strip[es]);
44058f0484fSRodney W. Grimes break;
44158f0484fSRodney W. Grimes case OCH_:
4424f8f1c79SKyle Evans while (OP(m->g->strip[es]) != (sop)O_CH)
44358f0484fSRodney W. Grimes es += OPND(m->g->strip[es]);
44458f0484fSRodney W. Grimes break;
44558f0484fSRodney W. Grimes }
44658f0484fSRodney W. Grimes es++;
44758f0484fSRodney W. Grimes
44858f0484fSRodney W. Grimes /* figure out what it matched */
44958f0484fSRodney W. Grimes switch (OP(m->g->strip[ss])) {
45058f0484fSRodney W. Grimes case OEND:
45158f0484fSRodney W. Grimes assert(nope);
45258f0484fSRodney W. Grimes break;
45358f0484fSRodney W. Grimes case OCHAR:
454e5996857STim J. Robbins sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
45558f0484fSRodney W. Grimes break;
45658f0484fSRodney W. Grimes case OBOL:
45758f0484fSRodney W. Grimes case OEOL:
45858f0484fSRodney W. Grimes case OBOW:
45958f0484fSRodney W. Grimes case OEOW:
460ca53e5aeSKyle Evans case OBOS:
461ca53e5aeSKyle Evans case OEOS:
462*6b986646SKyle Evans case OWBND:
463*6b986646SKyle Evans case ONWBND:
46458f0484fSRodney W. Grimes break;
46558f0484fSRodney W. Grimes case OANY:
46658f0484fSRodney W. Grimes case OANYOF:
467e5996857STim J. Robbins sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
46858f0484fSRodney W. Grimes break;
46958f0484fSRodney W. Grimes case OBACK_:
47058f0484fSRodney W. Grimes case O_BACK:
47158f0484fSRodney W. Grimes assert(nope);
47258f0484fSRodney W. Grimes break;
47358f0484fSRodney W. Grimes /* cases where length of match is hard to find */
47458f0484fSRodney W. Grimes case OQUEST_:
47558f0484fSRodney W. Grimes stp = stop;
47658f0484fSRodney W. Grimes for (;;) {
47758f0484fSRodney W. Grimes /* how long could this one be? */
478a0bf5d8aSKyle Evans rest = walk(m, sp, stp, ss, es, false);
47958f0484fSRodney W. Grimes assert(rest != NULL); /* it did match */
48058f0484fSRodney W. Grimes /* could the rest match the rest? */
481a0bf5d8aSKyle Evans tail = walk(m, rest, stop, es, stopst, false);
48258f0484fSRodney W. Grimes if (tail == stop)
48358f0484fSRodney W. Grimes break; /* yes! */
48458f0484fSRodney W. Grimes /* no -- try a shorter match for this one */
48558f0484fSRodney W. Grimes stp = rest - 1;
48658f0484fSRodney W. Grimes assert(stp >= sp); /* it did work */
48758f0484fSRodney W. Grimes }
48858f0484fSRodney W. Grimes ssub = ss + 1;
48958f0484fSRodney W. Grimes esub = es - 1;
49058f0484fSRodney W. Grimes /* did innards match? */
491a0bf5d8aSKyle Evans if (walk(m, sp, rest, ssub, esub, false) != NULL) {
49258f0484fSRodney W. Grimes dp = dissect(m, sp, rest, ssub, esub);
49358f0484fSRodney W. Grimes assert(dp == rest);
49458f0484fSRodney W. Grimes } else /* no */
49558f0484fSRodney W. Grimes assert(sp == rest);
49658f0484fSRodney W. Grimes sp = rest;
49758f0484fSRodney W. Grimes break;
49858f0484fSRodney W. Grimes case OPLUS_:
49958f0484fSRodney W. Grimes stp = stop;
50058f0484fSRodney W. Grimes for (;;) {
50158f0484fSRodney W. Grimes /* how long could this one be? */
502a0bf5d8aSKyle Evans rest = walk(m, sp, stp, ss, es, false);
50358f0484fSRodney W. Grimes assert(rest != NULL); /* it did match */
50458f0484fSRodney W. Grimes /* could the rest match the rest? */
505a0bf5d8aSKyle Evans tail = walk(m, rest, stop, es, stopst, false);
50658f0484fSRodney W. Grimes if (tail == stop)
50758f0484fSRodney W. Grimes break; /* yes! */
50858f0484fSRodney W. Grimes /* no -- try a shorter match for this one */
50958f0484fSRodney W. Grimes stp = rest - 1;
51058f0484fSRodney W. Grimes assert(stp >= sp); /* it did work */
51158f0484fSRodney W. Grimes }
51258f0484fSRodney W. Grimes ssub = ss + 1;
51358f0484fSRodney W. Grimes esub = es - 1;
51458f0484fSRodney W. Grimes ssp = sp;
51558f0484fSRodney W. Grimes oldssp = ssp;
51658f0484fSRodney W. Grimes for (;;) { /* find last match of innards */
517a0bf5d8aSKyle Evans sep = walk(m, ssp, rest, ssub, esub, false);
51858f0484fSRodney W. Grimes if (sep == NULL || sep == ssp)
51958f0484fSRodney W. Grimes break; /* failed or matched null */
52058f0484fSRodney W. Grimes oldssp = ssp; /* on to next try */
52158f0484fSRodney W. Grimes ssp = sep;
52258f0484fSRodney W. Grimes }
52358f0484fSRodney W. Grimes if (sep == NULL) {
52458f0484fSRodney W. Grimes /* last successful match */
52558f0484fSRodney W. Grimes sep = ssp;
52658f0484fSRodney W. Grimes ssp = oldssp;
52758f0484fSRodney W. Grimes }
52858f0484fSRodney W. Grimes assert(sep == rest); /* must exhaust substring */
529a0bf5d8aSKyle Evans assert(walk(m, ssp, sep, ssub, esub, false) == rest);
53058f0484fSRodney W. Grimes dp = dissect(m, ssp, sep, ssub, esub);
53158f0484fSRodney W. Grimes assert(dp == sep);
53258f0484fSRodney W. Grimes sp = rest;
53358f0484fSRodney W. Grimes break;
53458f0484fSRodney W. Grimes case OCH_:
53558f0484fSRodney W. Grimes stp = stop;
53658f0484fSRodney W. Grimes for (;;) {
53758f0484fSRodney W. Grimes /* how long could this one be? */
538a0bf5d8aSKyle Evans rest = walk(m, sp, stp, ss, es, false);
53958f0484fSRodney W. Grimes assert(rest != NULL); /* it did match */
54058f0484fSRodney W. Grimes /* could the rest match the rest? */
541a0bf5d8aSKyle Evans tail = walk(m, rest, stop, es, stopst, false);
54258f0484fSRodney W. Grimes if (tail == stop)
54358f0484fSRodney W. Grimes break; /* yes! */
54458f0484fSRodney W. Grimes /* no -- try a shorter match for this one */
54558f0484fSRodney W. Grimes stp = rest - 1;
54658f0484fSRodney W. Grimes assert(stp >= sp); /* it did work */
54758f0484fSRodney W. Grimes }
54858f0484fSRodney W. Grimes ssub = ss + 1;
54958f0484fSRodney W. Grimes esub = ss + OPND(m->g->strip[ss]) - 1;
55058f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == OOR1);
55158f0484fSRodney W. Grimes for (;;) { /* find first matching branch */
552a0bf5d8aSKyle Evans if (walk(m, sp, rest, ssub, esub, false) == rest)
55358f0484fSRodney W. Grimes break; /* it matched all of it */
55458f0484fSRodney W. Grimes /* that one missed, try next one */
55558f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == OOR1);
55658f0484fSRodney W. Grimes esub++;
55758f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == OOR2);
55858f0484fSRodney W. Grimes ssub = esub + 1;
55958f0484fSRodney W. Grimes esub += OPND(m->g->strip[esub]);
5604f8f1c79SKyle Evans if (OP(m->g->strip[esub]) == (sop)OOR2)
56158f0484fSRodney W. Grimes esub--;
56258f0484fSRodney W. Grimes else
56358f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == O_CH);
56458f0484fSRodney W. Grimes }
56558f0484fSRodney W. Grimes dp = dissect(m, sp, rest, ssub, esub);
56658f0484fSRodney W. Grimes assert(dp == rest);
56758f0484fSRodney W. Grimes sp = rest;
56858f0484fSRodney W. Grimes break;
56958f0484fSRodney W. Grimes case O_PLUS:
57058f0484fSRodney W. Grimes case O_QUEST:
57158f0484fSRodney W. Grimes case OOR1:
57258f0484fSRodney W. Grimes case OOR2:
57358f0484fSRodney W. Grimes case O_CH:
57458f0484fSRodney W. Grimes assert(nope);
57558f0484fSRodney W. Grimes break;
57658f0484fSRodney W. Grimes case OLPAREN:
57758f0484fSRodney W. Grimes i = OPND(m->g->strip[ss]);
57858f0484fSRodney W. Grimes assert(0 < i && i <= m->g->nsub);
57958f0484fSRodney W. Grimes m->pmatch[i].rm_so = sp - m->offp;
58058f0484fSRodney W. Grimes break;
58158f0484fSRodney W. Grimes case ORPAREN:
58258f0484fSRodney W. Grimes i = OPND(m->g->strip[ss]);
58358f0484fSRodney W. Grimes assert(0 < i && i <= m->g->nsub);
58458f0484fSRodney W. Grimes m->pmatch[i].rm_eo = sp - m->offp;
58558f0484fSRodney W. Grimes break;
58658f0484fSRodney W. Grimes default: /* uh oh */
58758f0484fSRodney W. Grimes assert(nope);
58858f0484fSRodney W. Grimes break;
58958f0484fSRodney W. Grimes }
59058f0484fSRodney W. Grimes }
59158f0484fSRodney W. Grimes
59258f0484fSRodney W. Grimes assert(sp == stop);
59358f0484fSRodney W. Grimes return(sp);
59458f0484fSRodney W. Grimes }
59558f0484fSRodney W. Grimes
5967518fb34SKyle Evans #define ISBOW(m, sp) \
5977518fb34SKyle Evans (sp < m->endp && ISWORD(*sp) && \
5987518fb34SKyle Evans ((sp == m->beginp && !(m->eflags®_NOTBOL)) || \
5997518fb34SKyle Evans (sp > m->offp && !ISWORD(*(sp-1)))))
6007518fb34SKyle Evans #define ISEOW(m, sp) \
6017518fb34SKyle Evans (((sp == m->endp && !(m->eflags®_NOTEOL)) || \
6027518fb34SKyle Evans (sp < m->endp && *sp == '\n' && \
6037518fb34SKyle Evans (m->g->cflags®_NEWLINE)) || \
6047518fb34SKyle Evans (sp < m->endp && !ISWORD(*sp)) ) && \
6057518fb34SKyle Evans (sp > m->beginp && ISWORD(*(sp-1)))) \
6067518fb34SKyle Evans
60758f0484fSRodney W. Grimes /*
60858f0484fSRodney W. Grimes - backref - figure out what matched what, figuring in back references
609eb2b3d10SXin LI == static const char *backref(struct match *m, const char *start, \
610eb2b3d10SXin LI == const char *stop, sopno startst, sopno stopst, sopno lev);
61158f0484fSRodney W. Grimes */
612eb2b3d10SXin LI 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)613eb2b3d10SXin LI backref(struct match *m,
614eb2b3d10SXin LI const char *start,
615eb2b3d10SXin LI const char *stop,
616eb2b3d10SXin LI sopno startst,
617eb2b3d10SXin LI sopno stopst,
618eb2b3d10SXin LI sopno lev, /* PLUS nesting level */
619eb2b3d10SXin LI int rec)
62058f0484fSRodney W. Grimes {
6218fb3f3f6SDavid E. O'Brien int i;
6228fb3f3f6SDavid E. O'Brien sopno ss; /* start sop of current subRE */
623eb2b3d10SXin LI const char *sp; /* start of string matched by it */
6248fb3f3f6SDavid E. O'Brien sopno ssub; /* start sop of subsubRE */
6258fb3f3f6SDavid E. O'Brien sopno esub; /* end sop of subsubRE */
626eb2b3d10SXin LI const char *ssp; /* start of string matched by subsubRE */
627eb2b3d10SXin LI const char *dp;
6288fb3f3f6SDavid E. O'Brien size_t len;
6298fb3f3f6SDavid E. O'Brien int hard;
6308fb3f3f6SDavid E. O'Brien sop s;
6318fb3f3f6SDavid E. O'Brien regoff_t offsave;
6328fb3f3f6SDavid E. O'Brien cset *cs;
633e5996857STim J. Robbins wint_t wc;
63458f0484fSRodney W. Grimes
63558f0484fSRodney W. Grimes AT("back", start, stop, startst, stopst);
63658f0484fSRodney W. Grimes sp = start;
63758f0484fSRodney W. Grimes
63858f0484fSRodney W. Grimes /* get as far as we can with easy stuff */
63958f0484fSRodney W. Grimes hard = 0;
64058f0484fSRodney W. Grimes for (ss = startst; !hard && ss < stopst; ss++)
64158f0484fSRodney W. Grimes switch (OP(s = m->g->strip[ss])) {
64258f0484fSRodney W. Grimes case OCHAR:
643e5996857STim J. Robbins if (sp == stop)
644e5996857STim J. Robbins return(NULL);
645e5996857STim J. Robbins sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
646e5996857STim J. Robbins if (wc != OPND(s))
64758f0484fSRodney W. Grimes return(NULL);
64858f0484fSRodney W. Grimes break;
64958f0484fSRodney W. Grimes case OANY:
65058f0484fSRodney W. Grimes if (sp == stop)
65158f0484fSRodney W. Grimes return(NULL);
652e5996857STim J. Robbins sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
653e5996857STim J. Robbins if (wc == BADCHAR)
654e5996857STim J. Robbins return (NULL);
65558f0484fSRodney W. Grimes break;
65658f0484fSRodney W. Grimes case OANYOF:
657e5996857STim J. Robbins if (sp == stop)
658e5996857STim J. Robbins return (NULL);
65958f0484fSRodney W. Grimes cs = &m->g->sets[OPND(s)];
660e5996857STim J. Robbins sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
661e5996857STim J. Robbins if (wc == BADCHAR || !CHIN(cs, wc))
66258f0484fSRodney W. Grimes return(NULL);
66358f0484fSRodney W. Grimes break;
664ca53e5aeSKyle Evans case OBOS:
665ca53e5aeSKyle Evans if (sp == m->beginp && (m->eflags & REG_NOTBOL) == 0)
666ca53e5aeSKyle Evans { /* yes */ }
667ca53e5aeSKyle Evans else
668ca53e5aeSKyle Evans return(NULL);
669ca53e5aeSKyle Evans break;
670ca53e5aeSKyle Evans case OEOS:
671ca53e5aeSKyle Evans if (sp == m->endp && (m->eflags & REG_NOTEOL) == 0)
672ca53e5aeSKyle Evans { /* yes */ }
673ca53e5aeSKyle Evans else
674ca53e5aeSKyle Evans return(NULL);
675ca53e5aeSKyle Evans break;
67658f0484fSRodney W. Grimes case OBOL:
67758f0484fSRodney W. Grimes if ((sp == m->beginp && !(m->eflags®_NOTBOL)) ||
678e9fe9eddSPedro F. Giffuni (sp > m->offp && sp < m->endp &&
679e9fe9eddSPedro F. Giffuni *(sp-1) == '\n' && (m->g->cflags®_NEWLINE)))
68058f0484fSRodney W. Grimes { /* yes */ }
68158f0484fSRodney W. Grimes else
68258f0484fSRodney W. Grimes return(NULL);
68358f0484fSRodney W. Grimes break;
68458f0484fSRodney W. Grimes case OEOL:
68558f0484fSRodney W. Grimes if ( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
68658f0484fSRodney W. Grimes (sp < m->endp && *sp == '\n' &&
68758f0484fSRodney W. Grimes (m->g->cflags®_NEWLINE)) )
68858f0484fSRodney W. Grimes { /* yes */ }
68958f0484fSRodney W. Grimes else
69058f0484fSRodney W. Grimes return(NULL);
69158f0484fSRodney W. Grimes break;
692*6b986646SKyle Evans case OWBND:
693*6b986646SKyle Evans if (ISBOW(m, sp) || ISEOW(m, sp))
694*6b986646SKyle Evans { /* yes */ }
695*6b986646SKyle Evans else
696*6b986646SKyle Evans return(NULL);
697*6b986646SKyle Evans break;
698*6b986646SKyle Evans case ONWBND:
699*6b986646SKyle Evans if (((sp == m->beginp) && !ISWORD(*sp)) ||
700*6b986646SKyle Evans (sp == m->endp && !ISWORD(*(sp - 1))))
701*6b986646SKyle Evans { /* yes, beginning/end of subject */ }
702*6b986646SKyle Evans else if (ISWORD(*(sp - 1)) == ISWORD(*sp))
703*6b986646SKyle Evans { /* yes, beginning/end of subject */ }
704*6b986646SKyle Evans else
705*6b986646SKyle Evans return(NULL);
706*6b986646SKyle Evans break;
70758f0484fSRodney W. Grimes case OBOW:
7087518fb34SKyle Evans if (ISBOW(m, sp))
70958f0484fSRodney W. Grimes { /* yes */ }
71058f0484fSRodney W. Grimes else
71158f0484fSRodney W. Grimes return(NULL);
71258f0484fSRodney W. Grimes break;
71358f0484fSRodney W. Grimes case OEOW:
7147518fb34SKyle Evans if (ISEOW(m, sp))
71558f0484fSRodney W. Grimes { /* yes */ }
71658f0484fSRodney W. Grimes else
71758f0484fSRodney W. Grimes return(NULL);
71858f0484fSRodney W. Grimes break;
71958f0484fSRodney W. Grimes case O_QUEST:
72058f0484fSRodney W. Grimes break;
72158f0484fSRodney W. Grimes case OOR1: /* matches null but needs to skip */
72258f0484fSRodney W. Grimes ss++;
72358f0484fSRodney W. Grimes s = m->g->strip[ss];
72458f0484fSRodney W. Grimes do {
72558f0484fSRodney W. Grimes assert(OP(s) == OOR2);
72658f0484fSRodney W. Grimes ss += OPND(s);
7274f8f1c79SKyle Evans } while (OP(s = m->g->strip[ss]) != (sop)O_CH);
72858f0484fSRodney W. Grimes /* note that the ss++ gets us past the O_CH */
72958f0484fSRodney W. Grimes break;
73058f0484fSRodney W. Grimes default: /* have to make a choice */
73158f0484fSRodney W. Grimes hard = 1;
73258f0484fSRodney W. Grimes break;
73358f0484fSRodney W. Grimes }
73458f0484fSRodney W. Grimes if (!hard) { /* that was it! */
73558f0484fSRodney W. Grimes if (sp != stop)
73658f0484fSRodney W. Grimes return(NULL);
73758f0484fSRodney W. Grimes return(sp);
73858f0484fSRodney W. Grimes }
73958f0484fSRodney W. Grimes ss--; /* adjust for the for's final increment */
74058f0484fSRodney W. Grimes
74158f0484fSRodney W. Grimes /* the hard stuff */
74258f0484fSRodney W. Grimes AT("hard", sp, stop, ss, stopst);
74358f0484fSRodney W. Grimes s = m->g->strip[ss];
74458f0484fSRodney W. Grimes switch (OP(s)) {
74558f0484fSRodney W. Grimes case OBACK_: /* the vilest depths */
74658f0484fSRodney W. Grimes i = OPND(s);
74758f0484fSRodney W. Grimes assert(0 < i && i <= m->g->nsub);
74858f0484fSRodney W. Grimes if (m->pmatch[i].rm_eo == -1)
74958f0484fSRodney W. Grimes return(NULL);
75058f0484fSRodney W. Grimes assert(m->pmatch[i].rm_so != -1);
75158f0484fSRodney W. Grimes len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
752082063a0SXin LI if (len == 0 && rec++ > MAX_RECURSION)
7530f4481c5SXin LI return(NULL);
75458f0484fSRodney W. Grimes assert(stop - m->beginp >= len);
75558f0484fSRodney W. Grimes if (sp > stop - len)
75658f0484fSRodney W. Grimes return(NULL); /* not enough left to match */
75758f0484fSRodney W. Grimes ssp = m->offp + m->pmatch[i].rm_so;
75858f0484fSRodney W. Grimes if (memcmp(sp, ssp, len) != 0)
75958f0484fSRodney W. Grimes return(NULL);
7604f8f1c79SKyle Evans while (m->g->strip[ss] != (sop)SOP(O_BACK, i))
76158f0484fSRodney W. Grimes ss++;
762082063a0SXin LI return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
76358f0484fSRodney W. Grimes case OQUEST_: /* to null or not */
764082063a0SXin LI dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
76558f0484fSRodney W. Grimes if (dp != NULL)
76658f0484fSRodney W. Grimes return(dp); /* not */
767082063a0SXin LI return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
76858f0484fSRodney W. Grimes case OPLUS_:
76958f0484fSRodney W. Grimes assert(m->lastpos != NULL);
77058f0484fSRodney W. Grimes assert(lev+1 <= m->g->nplus);
77158f0484fSRodney W. Grimes m->lastpos[lev+1] = sp;
772082063a0SXin LI return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
77358f0484fSRodney W. Grimes case O_PLUS:
77458f0484fSRodney W. Grimes if (sp == m->lastpos[lev]) /* last pass matched null */
775082063a0SXin LI return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
77658f0484fSRodney W. Grimes /* try another pass */
77758f0484fSRodney W. Grimes m->lastpos[lev] = sp;
778082063a0SXin LI dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
77958f0484fSRodney W. Grimes if (dp == NULL)
780082063a0SXin LI return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
78158f0484fSRodney W. Grimes else
78258f0484fSRodney W. Grimes return(dp);
78358f0484fSRodney W. Grimes case OCH_: /* find the right one, if any */
78458f0484fSRodney W. Grimes ssub = ss + 1;
78558f0484fSRodney W. Grimes esub = ss + OPND(s) - 1;
78658f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == OOR1);
78758f0484fSRodney W. Grimes for (;;) { /* find first matching branch */
788082063a0SXin LI dp = backref(m, sp, stop, ssub, esub, lev, rec);
78958f0484fSRodney W. Grimes if (dp != NULL)
79058f0484fSRodney W. Grimes return(dp);
79158f0484fSRodney W. Grimes /* that one missed, try next one */
7924f8f1c79SKyle Evans if (OP(m->g->strip[esub]) == (sop)O_CH)
79358f0484fSRodney W. Grimes return(NULL); /* there is none */
79458f0484fSRodney W. Grimes esub++;
7954f8f1c79SKyle Evans assert(OP(m->g->strip[esub]) == (sop)OOR2);
79658f0484fSRodney W. Grimes ssub = esub + 1;
79758f0484fSRodney W. Grimes esub += OPND(m->g->strip[esub]);
7984f8f1c79SKyle Evans if (OP(m->g->strip[esub]) == (sop)OOR2)
79958f0484fSRodney W. Grimes esub--;
80058f0484fSRodney W. Grimes else
80158f0484fSRodney W. Grimes assert(OP(m->g->strip[esub]) == O_CH);
80258f0484fSRodney W. Grimes }
803eab20bceSPedro F. Giffuni /* NOTREACHED */
80458f0484fSRodney W. Grimes break;
80558f0484fSRodney W. Grimes case OLPAREN: /* must undo assignment if rest fails */
80658f0484fSRodney W. Grimes i = OPND(s);
80758f0484fSRodney W. Grimes assert(0 < i && i <= m->g->nsub);
80858f0484fSRodney W. Grimes offsave = m->pmatch[i].rm_so;
80958f0484fSRodney W. Grimes m->pmatch[i].rm_so = sp - m->offp;
810082063a0SXin LI dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
81158f0484fSRodney W. Grimes if (dp != NULL)
81258f0484fSRodney W. Grimes return(dp);
81358f0484fSRodney W. Grimes m->pmatch[i].rm_so = offsave;
81458f0484fSRodney W. Grimes return(NULL);
81558f0484fSRodney W. Grimes case ORPAREN: /* must undo assignment if rest fails */
81658f0484fSRodney W. Grimes i = OPND(s);
81758f0484fSRodney W. Grimes assert(0 < i && i <= m->g->nsub);
81858f0484fSRodney W. Grimes offsave = m->pmatch[i].rm_eo;
81958f0484fSRodney W. Grimes m->pmatch[i].rm_eo = sp - m->offp;
820082063a0SXin LI dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
82158f0484fSRodney W. Grimes if (dp != NULL)
82258f0484fSRodney W. Grimes return(dp);
82358f0484fSRodney W. Grimes m->pmatch[i].rm_eo = offsave;
82458f0484fSRodney W. Grimes return(NULL);
82558f0484fSRodney W. Grimes default: /* uh oh */
82658f0484fSRodney W. Grimes assert(nope);
82758f0484fSRodney W. Grimes break;
82858f0484fSRodney W. Grimes }
82958f0484fSRodney W. Grimes
83058f0484fSRodney W. Grimes /* "can't happen" */
83158f0484fSRodney W. Grimes assert(nope);
83258f0484fSRodney W. Grimes /* NOTREACHED */
83316252f11SPoul-Henning Kamp return "shut up gcc";
83458f0484fSRodney W. Grimes }
83558f0484fSRodney W. Grimes
83658f0484fSRodney W. Grimes /*
837a0bf5d8aSKyle Evans - walk - step through the string either quickly or slowly
838a0bf5d8aSKyle Evans == static const char *walk(struct match *m, const char *start, \
839a0bf5d8aSKyle Evans == const char *stop, sopno startst, sopno stopst, bool fast);
84058f0484fSRodney W. Grimes */
841a0bf5d8aSKyle Evans static const char * /* where it ended, or NULL */
walk(struct match * m,const char * start,const char * stop,sopno startst,sopno stopst,bool fast)842a0bf5d8aSKyle Evans walk(struct match *m, const char *start, const char *stop, sopno startst,
843a0bf5d8aSKyle Evans sopno stopst, bool fast)
84458f0484fSRodney W. Grimes {
8458fb3f3f6SDavid E. O'Brien states st = m->st;
8468fb3f3f6SDavid E. O'Brien states fresh = m->fresh;
8478fb3f3f6SDavid E. O'Brien states empty = m->empty;
8488fb3f3f6SDavid E. O'Brien states tmp = m->tmp;
849eb2b3d10SXin LI const char *p = start;
850e5996857STim J. Robbins wint_t c;
851e5996857STim J. Robbins wint_t lastc; /* previous c */
852e5996857STim J. Robbins wint_t flagch;
853ca53e5aeSKyle Evans int i, sflags;
854eb2b3d10SXin LI const char *matchp; /* last p at which a match ended */
855e5996857STim J. Robbins size_t clen;
85658f0484fSRodney W. Grimes
857ca53e5aeSKyle Evans sflags = 0;
85858f0484fSRodney W. Grimes AT("slow", start, stop, startst, stopst);
85958f0484fSRodney W. Grimes CLEAR(st);
86058f0484fSRodney W. Grimes SET1(st, startst);
86158f0484fSRodney W. Grimes SP("sstart", st, *p);
862ca53e5aeSKyle Evans st = step(m->g, startst, stopst, st, NOTHING, st, sflags);
863a0bf5d8aSKyle Evans if (fast)
864a0bf5d8aSKyle Evans ASSIGN(fresh, st);
86558f0484fSRodney W. Grimes matchp = NULL;
86693ea9f9fSPedro F. Giffuni if (start == m->offp || (start == m->beginp && !(m->eflags®_NOTBOL)))
867e5996857STim J. Robbins c = OUT;
868e5996857STim J. Robbins else {
869e5996857STim J. Robbins /*
870e5996857STim J. Robbins * XXX Wrong if the previous character was multi-byte.
871e5996857STim J. Robbins * Newline never is (in encodings supported by FreeBSD),
872e5996857STim J. Robbins * so this only breaks the ISWORD tests below.
873e5996857STim J. Robbins */
874e5996857STim J. Robbins c = (uch)*(start - 1);
875e5996857STim J. Robbins }
87658f0484fSRodney W. Grimes for (;;) {
87758f0484fSRodney W. Grimes /* next character */
87858f0484fSRodney W. Grimes lastc = c;
879ca53e5aeSKyle Evans sflags = 0;
880e5996857STim J. Robbins if (p == m->endp) {
881e5996857STim J. Robbins c = OUT;
882e5996857STim J. Robbins clen = 0;
883e5996857STim J. Robbins } else
8841ee0dbeeSTim J. Robbins clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
88558f0484fSRodney W. Grimes
886a0bf5d8aSKyle Evans if (fast && EQ(st, fresh))
887a0bf5d8aSKyle Evans matchp = p;
888a0bf5d8aSKyle Evans
88958f0484fSRodney W. Grimes /* is there an EOL and/or BOL between lastc and c? */
89058f0484fSRodney W. Grimes flagch = '\0';
89158f0484fSRodney W. Grimes i = 0;
89258f0484fSRodney W. Grimes if ( (lastc == '\n' && m->g->cflags®_NEWLINE) ||
89358f0484fSRodney W. Grimes (lastc == OUT && !(m->eflags®_NOTBOL)) ) {
89458f0484fSRodney W. Grimes flagch = BOL;
89558f0484fSRodney W. Grimes i = m->g->nbol;
89658f0484fSRodney W. Grimes }
89758f0484fSRodney W. Grimes if ( (c == '\n' && m->g->cflags®_NEWLINE) ||
89858f0484fSRodney W. Grimes (c == OUT && !(m->eflags®_NOTEOL)) ) {
89958f0484fSRodney W. Grimes flagch = (flagch == BOL) ? BOLEOL : EOL;
90058f0484fSRodney W. Grimes i += m->g->neol;
90158f0484fSRodney W. Grimes }
902ca53e5aeSKyle Evans if (lastc == OUT && (m->eflags & REG_NOTBOL) == 0) {
903ca53e5aeSKyle Evans sflags |= SBOS;
904ca53e5aeSKyle Evans /* Step one more for BOS. */
905ca53e5aeSKyle Evans i++;
906ca53e5aeSKyle Evans }
907ca53e5aeSKyle Evans if (c == OUT && (m->eflags & REG_NOTEOL) == 0) {
908ca53e5aeSKyle Evans sflags |= SEOS;
909ca53e5aeSKyle Evans /* Step one more for EOS. */
910ca53e5aeSKyle Evans i++;
911ca53e5aeSKyle Evans }
91258f0484fSRodney W. Grimes if (i != 0) {
91358f0484fSRodney W. Grimes for (; i > 0; i--)
914ca53e5aeSKyle Evans st = step(m->g, startst, stopst, st, flagch, st,
915ca53e5aeSKyle Evans sflags);
91658f0484fSRodney W. Grimes SP("sboleol", st, c);
91758f0484fSRodney W. Grimes }
91858f0484fSRodney W. Grimes
91958f0484fSRodney W. Grimes /* how about a word boundary? */
92058f0484fSRodney W. Grimes if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
92158f0484fSRodney W. Grimes (c != OUT && ISWORD(c)) ) {
92258f0484fSRodney W. Grimes flagch = BOW;
92358f0484fSRodney W. Grimes }
92458f0484fSRodney W. Grimes if ( (lastc != OUT && ISWORD(lastc)) &&
92558f0484fSRodney W. Grimes (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
92658f0484fSRodney W. Grimes flagch = EOW;
92758f0484fSRodney W. Grimes }
92858f0484fSRodney W. Grimes if (flagch == BOW || flagch == EOW) {
929ca53e5aeSKyle Evans st = step(m->g, startst, stopst, st, flagch, st, sflags);
93058f0484fSRodney W. Grimes SP("sboweow", st, c);
93158f0484fSRodney W. Grimes }
932*6b986646SKyle Evans if (lastc != OUT && c != OUT &&
933*6b986646SKyle Evans ISWORD(lastc) == ISWORD(c)) {
934*6b986646SKyle Evans flagch = NWBND;
935*6b986646SKyle Evans } else if ((lastc == OUT && !ISWORD(c)) ||
936*6b986646SKyle Evans (c == OUT && !ISWORD(lastc))) {
937*6b986646SKyle Evans flagch = NWBND;
938*6b986646SKyle Evans }
939*6b986646SKyle Evans if (flagch == NWBND) {
940*6b986646SKyle Evans st = step(m->g, startst, stopst, st, flagch, st, sflags);
941*6b986646SKyle Evans SP("snwbnd", st, c);
942*6b986646SKyle Evans }
94358f0484fSRodney W. Grimes
94458f0484fSRodney W. Grimes /* are we done? */
945a0bf5d8aSKyle Evans if (ISSET(st, stopst)) {
946a0bf5d8aSKyle Evans if (fast)
947a0bf5d8aSKyle Evans break;
948a0bf5d8aSKyle Evans else
94958f0484fSRodney W. Grimes matchp = p;
950a0bf5d8aSKyle Evans }
9514f8f1c79SKyle Evans if (EQ(st, empty) || p == stop || clen > (size_t)(stop - p))
95258f0484fSRodney W. Grimes break; /* NOTE BREAK OUT */
95358f0484fSRodney W. Grimes
95458f0484fSRodney W. Grimes /* no, we must deal with this character */
95558f0484fSRodney W. Grimes ASSIGN(tmp, st);
956a0bf5d8aSKyle Evans if (fast)
957a0bf5d8aSKyle Evans ASSIGN(st, fresh);
958a0bf5d8aSKyle Evans else
95958f0484fSRodney W. Grimes ASSIGN(st, empty);
96058f0484fSRodney W. Grimes assert(c != OUT);
961ca53e5aeSKyle Evans st = step(m->g, startst, stopst, tmp, c, st, sflags);
96258f0484fSRodney W. Grimes SP("saft", st, c);
963ca53e5aeSKyle Evans assert(EQ(step(m->g, startst, stopst, st, NOTHING, st, sflags),
964ca53e5aeSKyle Evans st));
965e5996857STim J. Robbins p += clen;
96658f0484fSRodney W. Grimes }
96758f0484fSRodney W. Grimes
968a0bf5d8aSKyle Evans if (fast) {
969a0bf5d8aSKyle Evans assert(matchp != NULL);
970a0bf5d8aSKyle Evans m->coldp = matchp;
971a0bf5d8aSKyle Evans if (ISSET(st, stopst))
972a0bf5d8aSKyle Evans return (p + XMBRTOWC(NULL, p, stop - p, &m->mbs, 0));
973a0bf5d8aSKyle Evans else
974a0bf5d8aSKyle Evans return (NULL);
975a0bf5d8aSKyle Evans } else
97658f0484fSRodney W. Grimes return (matchp);
97758f0484fSRodney W. Grimes }
97858f0484fSRodney W. Grimes
97958f0484fSRodney W. Grimes /*
98058f0484fSRodney W. Grimes - step - map set of states reachable before char to set reachable after
9818fb3f3f6SDavid E. O'Brien == static states step(struct re_guts *g, sopno start, sopno stop, \
9828fb3f3f6SDavid E. O'Brien == states bef, int ch, states aft);
983e5996857STim J. Robbins == #define BOL (OUT-1)
984e5996857STim J. Robbins == #define EOL (BOL-1)
985e5996857STim J. Robbins == #define BOLEOL (BOL-2)
986e5996857STim J. Robbins == #define NOTHING (BOL-3)
987e5996857STim J. Robbins == #define BOW (BOL-4)
988e5996857STim J. Robbins == #define EOW (BOL-5)
989e5996857STim J. Robbins == #define BADCHAR (BOL-6)
990e5996857STim J. Robbins == #define NONCHAR(c) ((c) <= OUT)
99158f0484fSRodney W. Grimes */
99258f0484fSRodney W. Grimes static states
step(struct re_guts * g,sopno start,sopno stop,states bef,wint_t ch,states aft,int sflags)993eb2b3d10SXin LI step(struct re_guts *g,
994eb2b3d10SXin LI sopno start, /* start state within strip */
995eb2b3d10SXin LI sopno stop, /* state after stop state within strip */
996eb2b3d10SXin LI states bef, /* states reachable before */
997eb2b3d10SXin LI wint_t ch, /* character or NONCHAR code */
998ca53e5aeSKyle Evans states aft, /* states already known reachable after */
999ca53e5aeSKyle Evans int sflags) /* state flags */
100058f0484fSRodney W. Grimes {
10018fb3f3f6SDavid E. O'Brien cset *cs;
10028fb3f3f6SDavid E. O'Brien sop s;
10038fb3f3f6SDavid E. O'Brien sopno pc;
10048fb3f3f6SDavid E. O'Brien onestate here; /* note, macros know this name */
10058fb3f3f6SDavid E. O'Brien sopno look;
10068fb3f3f6SDavid E. O'Brien int i;
100758f0484fSRodney W. Grimes
100858f0484fSRodney W. Grimes for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
100958f0484fSRodney W. Grimes s = g->strip[pc];
101058f0484fSRodney W. Grimes switch (OP(s)) {
101158f0484fSRodney W. Grimes case OEND:
101258f0484fSRodney W. Grimes assert(pc == stop-1);
101358f0484fSRodney W. Grimes break;
101458f0484fSRodney W. Grimes case OCHAR:
101558f0484fSRodney W. Grimes /* only characters can match */
1016e5996857STim J. Robbins assert(!NONCHAR(ch) || ch != OPND(s));
1017e5996857STim J. Robbins if (ch == OPND(s))
101858f0484fSRodney W. Grimes FWD(aft, bef, 1);
101958f0484fSRodney W. Grimes break;
1020ca53e5aeSKyle Evans case OBOS:
1021ca53e5aeSKyle Evans if ((ch == BOL || ch == BOLEOL) && (sflags & SBOS) != 0)
1022ca53e5aeSKyle Evans FWD(aft, bef, 1);
1023ca53e5aeSKyle Evans break;
1024ca53e5aeSKyle Evans case OEOS:
1025ca53e5aeSKyle Evans if ((ch == EOL || ch == BOLEOL) && (sflags & SEOS) != 0)
1026ca53e5aeSKyle Evans FWD(aft, bef, 1);
1027ca53e5aeSKyle Evans break;
102858f0484fSRodney W. Grimes case OBOL:
102958f0484fSRodney W. Grimes if (ch == BOL || ch == BOLEOL)
103058f0484fSRodney W. Grimes FWD(aft, bef, 1);
103158f0484fSRodney W. Grimes break;
103258f0484fSRodney W. Grimes case OEOL:
103358f0484fSRodney W. Grimes if (ch == EOL || ch == BOLEOL)
103458f0484fSRodney W. Grimes FWD(aft, bef, 1);
103558f0484fSRodney W. Grimes break;
103658f0484fSRodney W. Grimes case OBOW:
103758f0484fSRodney W. Grimes if (ch == BOW)
103858f0484fSRodney W. Grimes FWD(aft, bef, 1);
103958f0484fSRodney W. Grimes break;
104058f0484fSRodney W. Grimes case OEOW:
104158f0484fSRodney W. Grimes if (ch == EOW)
104258f0484fSRodney W. Grimes FWD(aft, bef, 1);
104358f0484fSRodney W. Grimes break;
1044*6b986646SKyle Evans case OWBND:
1045*6b986646SKyle Evans if (ch == BOW || ch == EOW)
1046*6b986646SKyle Evans FWD(aft, bef, 1);
1047*6b986646SKyle Evans break;
1048*6b986646SKyle Evans case ONWBND:
1049*6b986646SKyle Evans if (ch == NWBND)
1050*6b986646SKyle Evans FWD(aft, aft, 1);
1051*6b986646SKyle Evans break;
105258f0484fSRodney W. Grimes case OANY:
105358f0484fSRodney W. Grimes if (!NONCHAR(ch))
105458f0484fSRodney W. Grimes FWD(aft, bef, 1);
105558f0484fSRodney W. Grimes break;
105658f0484fSRodney W. Grimes case OANYOF:
105758f0484fSRodney W. Grimes cs = &g->sets[OPND(s)];
105858f0484fSRodney W. Grimes if (!NONCHAR(ch) && CHIN(cs, ch))
105958f0484fSRodney W. Grimes FWD(aft, bef, 1);
106058f0484fSRodney W. Grimes break;
106158f0484fSRodney W. Grimes case OBACK_: /* ignored here */
106258f0484fSRodney W. Grimes case O_BACK:
106358f0484fSRodney W. Grimes FWD(aft, aft, 1);
106458f0484fSRodney W. Grimes break;
106558f0484fSRodney W. Grimes case OPLUS_: /* forward, this is just an empty */
106658f0484fSRodney W. Grimes FWD(aft, aft, 1);
106758f0484fSRodney W. Grimes break;
106858f0484fSRodney W. Grimes case O_PLUS: /* both forward and back */
106958f0484fSRodney W. Grimes FWD(aft, aft, 1);
107058f0484fSRodney W. Grimes i = ISSETBACK(aft, OPND(s));
107158f0484fSRodney W. Grimes BACK(aft, aft, OPND(s));
107258f0484fSRodney W. Grimes if (!i && ISSETBACK(aft, OPND(s))) {
107358f0484fSRodney W. Grimes /* oho, must reconsider loop body */
107458f0484fSRodney W. Grimes pc -= OPND(s) + 1;
107558f0484fSRodney W. Grimes INIT(here, pc);
107658f0484fSRodney W. Grimes }
107758f0484fSRodney W. Grimes break;
107858f0484fSRodney W. Grimes case OQUEST_: /* two branches, both forward */
107958f0484fSRodney W. Grimes FWD(aft, aft, 1);
108058f0484fSRodney W. Grimes FWD(aft, aft, OPND(s));
108158f0484fSRodney W. Grimes break;
108258f0484fSRodney W. Grimes case O_QUEST: /* just an empty */
108358f0484fSRodney W. Grimes FWD(aft, aft, 1);
108458f0484fSRodney W. Grimes break;
108558f0484fSRodney W. Grimes case OLPAREN: /* not significant here */
108658f0484fSRodney W. Grimes case ORPAREN:
108758f0484fSRodney W. Grimes FWD(aft, aft, 1);
108858f0484fSRodney W. Grimes break;
108958f0484fSRodney W. Grimes case OCH_: /* mark the first two branches */
109058f0484fSRodney W. Grimes FWD(aft, aft, 1);
10914f8f1c79SKyle Evans assert(OP(g->strip[pc+OPND(s)]) == (sop)OOR2);
109258f0484fSRodney W. Grimes FWD(aft, aft, OPND(s));
109358f0484fSRodney W. Grimes break;
109458f0484fSRodney W. Grimes case OOR1: /* done a branch, find the O_CH */
109558f0484fSRodney W. Grimes if (ISSTATEIN(aft, here)) {
109658f0484fSRodney W. Grimes for (look = 1;
10974f8f1c79SKyle Evans OP(s = g->strip[pc+look]) != (sop)O_CH;
109858f0484fSRodney W. Grimes look += OPND(s))
10994f8f1c79SKyle Evans assert(OP(s) == (sop)OOR2);
1100e7cbc6eeSDiomidis Spinellis FWD(aft, aft, look + 1);
110158f0484fSRodney W. Grimes }
110258f0484fSRodney W. Grimes break;
110358f0484fSRodney W. Grimes case OOR2: /* propagate OCH_'s marking */
110458f0484fSRodney W. Grimes FWD(aft, aft, 1);
11054f8f1c79SKyle Evans if (OP(g->strip[pc+OPND(s)]) != (sop)O_CH) {
11064f8f1c79SKyle Evans assert(OP(g->strip[pc+OPND(s)]) == (sop)OOR2);
110758f0484fSRodney W. Grimes FWD(aft, aft, OPND(s));
110858f0484fSRodney W. Grimes }
110958f0484fSRodney W. Grimes break;
111058f0484fSRodney W. Grimes case O_CH: /* just empty */
111158f0484fSRodney W. Grimes FWD(aft, aft, 1);
111258f0484fSRodney W. Grimes break;
111358f0484fSRodney W. Grimes default: /* ooooops... */
111458f0484fSRodney W. Grimes assert(nope);
111558f0484fSRodney W. Grimes break;
111658f0484fSRodney W. Grimes }
111758f0484fSRodney W. Grimes }
111858f0484fSRodney W. Grimes
111958f0484fSRodney W. Grimes return(aft);
112058f0484fSRodney W. Grimes }
112158f0484fSRodney W. Grimes
112258f0484fSRodney W. Grimes #ifdef REDEBUG
112358f0484fSRodney W. Grimes /*
112458f0484fSRodney W. Grimes - print - print a set of states
112558f0484fSRodney W. Grimes == #ifdef REDEBUG
1126eb2b3d10SXin LI == static void print(struct match *m, const char *caption, states st, \
112758f0484fSRodney W. Grimes == int ch, FILE *d);
112858f0484fSRodney W. Grimes == #endif
112958f0484fSRodney W. Grimes */
113058f0484fSRodney W. Grimes static void
print(struct match * m,const char * caption,states st,int ch,FILE * d)1131eb2b3d10SXin LI print(struct match *m,
1132eb2b3d10SXin LI const char *caption,
1133eb2b3d10SXin LI states st,
1134eb2b3d10SXin LI int ch,
1135eb2b3d10SXin LI FILE *d)
113658f0484fSRodney W. Grimes {
11378fb3f3f6SDavid E. O'Brien struct re_guts *g = m->g;
1138039b877eSPedro F. Giffuni sopno i;
11398fb3f3f6SDavid E. O'Brien int first = 1;
114058f0484fSRodney W. Grimes
114158f0484fSRodney W. Grimes if (!(m->eflags®_TRACE))
114258f0484fSRodney W. Grimes return;
114358f0484fSRodney W. Grimes
114458f0484fSRodney W. Grimes fprintf(d, "%s", caption);
114558f0484fSRodney W. Grimes if (ch != '\0')
114658f0484fSRodney W. Grimes fprintf(d, " %s", pchar(ch));
114758f0484fSRodney W. Grimes for (i = 0; i < g->nstates; i++)
114858f0484fSRodney W. Grimes if (ISSET(st, i)) {
11493c787714SYuri Pankov fprintf(d, "%s%lu", (first) ? "\t" : ", ", i);
115058f0484fSRodney W. Grimes first = 0;
115158f0484fSRodney W. Grimes }
115258f0484fSRodney W. Grimes fprintf(d, "\n");
115358f0484fSRodney W. Grimes }
115458f0484fSRodney W. Grimes
115558f0484fSRodney W. Grimes /*
115658f0484fSRodney W. Grimes - at - print current situation
115758f0484fSRodney W. Grimes == #ifdef REDEBUG
1158eb2b3d10SXin LI == static void at(struct match *m, const char *title, const char *start, \
1159eb2b3d10SXin LI == const char *stop, sopno startst, sopno stopst);
116058f0484fSRodney W. Grimes == #endif
116158f0484fSRodney W. Grimes */
116258f0484fSRodney W. Grimes static void
at(struct match * m,const char * title,const char * start,const char * stop,sopno startst,sopno stopst)1163eb2b3d10SXin LI at( struct match *m,
1164eb2b3d10SXin LI const char *title,
1165eb2b3d10SXin LI const char *start,
1166eb2b3d10SXin LI const char *stop,
1167eb2b3d10SXin LI sopno startst,
1168eb2b3d10SXin LI sopno stopst)
116958f0484fSRodney W. Grimes {
117058f0484fSRodney W. Grimes if (!(m->eflags®_TRACE))
117158f0484fSRodney W. Grimes return;
117258f0484fSRodney W. Grimes
117358f0484fSRodney W. Grimes printf("%s %s-", title, pchar(*start));
117458f0484fSRodney W. Grimes printf("%s ", pchar(*stop));
117558f0484fSRodney W. Grimes printf("%ld-%ld\n", (long)startst, (long)stopst);
117658f0484fSRodney W. Grimes }
117758f0484fSRodney W. Grimes
117858f0484fSRodney W. Grimes #ifndef PCHARDONE
117958f0484fSRodney W. Grimes #define PCHARDONE /* never again */
118058f0484fSRodney W. Grimes /*
118158f0484fSRodney W. Grimes - pchar - make a character printable
118258f0484fSRodney W. Grimes == #ifdef REDEBUG
1183eb2b3d10SXin LI == static const char *pchar(int ch);
118458f0484fSRodney W. Grimes == #endif
118558f0484fSRodney W. Grimes *
118658f0484fSRodney W. Grimes * Is this identical to regchar() over in debug.c? Well, yes. But a
118758f0484fSRodney W. Grimes * duplicate here avoids having a debugging-capable regexec.o tied to
118858f0484fSRodney W. Grimes * a matching debug.o, and this is convenient. It all disappears in
118958f0484fSRodney W. Grimes * the non-debug compilation anyway, so it doesn't matter much.
119058f0484fSRodney W. Grimes */
1191eb2b3d10SXin LI static const char * /* -> representation */
pchar(int ch)1192eb2b3d10SXin LI pchar(int ch)
119358f0484fSRodney W. Grimes {
119458f0484fSRodney W. Grimes static char pbuf[10];
119558f0484fSRodney W. Grimes
1196b5363c4aSAndrey A. Chernov if (isprint((uch)ch) || ch == ' ')
119758f0484fSRodney W. Grimes sprintf(pbuf, "%c", ch);
119858f0484fSRodney W. Grimes else
119958f0484fSRodney W. Grimes sprintf(pbuf, "\\%o", ch);
120058f0484fSRodney W. Grimes return(pbuf);
120158f0484fSRodney W. Grimes }
120258f0484fSRodney W. Grimes #endif
120358f0484fSRodney W. Grimes #endif
120458f0484fSRodney W. Grimes
120563cbe8d1SYuri Pankov #undef stepback
120658f0484fSRodney W. Grimes #undef matcher
1207a0bf5d8aSKyle Evans #undef walk
120858f0484fSRodney W. Grimes #undef dissect
120958f0484fSRodney W. Grimes #undef backref
121058f0484fSRodney W. Grimes #undef step
121158f0484fSRodney W. Grimes #undef print
121258f0484fSRodney W. Grimes #undef at
121358f0484fSRodney W. Grimes #undef match
1214