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