Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * re_*exec and friends - match REs
3 : : *
4 : : * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
5 : : *
6 : : * Development of this software was funded, in part, by Cray Research Inc.,
7 : : * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
8 : : * Corporation, none of whom are responsible for the results. The author
9 : : * thanks all of them.
10 : : *
11 : : * Redistribution and use in source and binary forms -- with or without
12 : : * modification -- are permitted for any purpose, provided that
13 : : * redistributions in source form retain this entire copyright notice and
14 : : * indicate the origin and nature of any modifications.
15 : : *
16 : : * I'd appreciate being given credit for this package in the documentation
17 : : * of software which uses it, but that is not a requirement.
18 : : *
19 : : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 : : * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21 : : * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 : : * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 : : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 : : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 : : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 : : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : *
30 : : * src/backend/regex/regexec.c
31 : : *
32 : : */
33 : :
34 : : #include "regex/regguts.h"
35 : :
36 : :
37 : :
38 : : /* lazy-DFA representation */
39 : : struct arcp
40 : : { /* "pointer" to an outarc */
41 : : struct sset *ss;
42 : : color co;
43 : : };
44 : :
45 : : struct sset
46 : : { /* state set */
47 : : unsigned *states; /* pointer to bitvector */
48 : : unsigned hash; /* hash of bitvector */
49 : : #define HASH(bv, nw) (((nw) == 1) ? *(bv) : hash(bv, nw))
50 : : #define HIT(h,bv,ss,nw) ((ss)->hash == (h) && ((nw) == 1 || \
51 : : memcmp(VS(bv), VS((ss)->states), (nw)*sizeof(unsigned)) == 0))
52 : : int flags;
53 : : #define STARTER 01 /* the initial state set */
54 : : #define POSTSTATE 02 /* includes the goal state */
55 : : #define LOCKED 04 /* locked in cache */
56 : : #define NOPROGRESS 010 /* zero-progress state set */
57 : : struct arcp ins; /* chain of inarcs pointing here */
58 : : chr *lastseen; /* last entered on arrival here */
59 : : struct sset **outs; /* outarc vector indexed by color */
60 : : struct arcp *inchain; /* chain-pointer vector for outarcs */
61 : : };
62 : :
63 : : struct dfa
64 : : {
65 : : int nssets; /* size of cache */
66 : : int nssused; /* how many entries occupied yet */
67 : : int nstates; /* number of states */
68 : : int ncolors; /* length of outarc and inchain vectors */
69 : : int wordsper; /* length of state-set bitvectors */
70 : : struct sset *ssets; /* state-set cache */
71 : : unsigned *statesarea; /* bitvector storage */
72 : : unsigned *work; /* pointer to work area within statesarea */
73 : : struct sset **outsarea; /* outarc-vector storage */
74 : : struct arcp *incarea; /* inchain storage */
75 : : struct cnfa *cnfa;
76 : : struct colormap *cm;
77 : : chr *lastpost; /* location of last cache-flushed success */
78 : : chr *lastnopr; /* location of last cache-flushed NOPROGRESS */
79 : : struct sset *search; /* replacement-search-pointer memory */
80 : : int backno; /* if DFA for a backref, subno it refers to */
81 : : short backmin; /* min repetitions for backref */
82 : : short backmax; /* max repetitions for backref */
83 : : bool ismalloced; /* should this struct dfa be freed? */
84 : : bool arraysmalloced; /* should its subsidiary arrays be freed? */
85 : : };
86 : :
87 : : #define WORK 1 /* number of work bitvectors needed */
88 : :
89 : : /* setup for non-malloc allocation for small cases */
90 : : #define FEWSTATES 20 /* must be less than UBITS */
91 : : #define FEWCOLORS 15
92 : : struct smalldfa
93 : : {
94 : : struct dfa dfa; /* must be first */
95 : : struct sset ssets[FEWSTATES * 2];
96 : : unsigned statesarea[FEWSTATES * 2 + WORK];
97 : : struct sset *outsarea[FEWSTATES * 2 * FEWCOLORS];
98 : : struct arcp incarea[FEWSTATES * 2 * FEWCOLORS];
99 : : };
100 : :
101 : : #define DOMALLOC ((struct smalldfa *)NULL) /* force malloc */
102 : :
103 : :
104 : :
105 : : /* internal variables, bundled for easy passing around */
106 : : struct vars
107 : : {
108 : : regex_t *re;
109 : : struct guts *g;
110 : : int eflags; /* copies of arguments */
111 : : size_t nmatch;
112 : : regmatch_t *pmatch;
113 : : rm_detail_t *details;
114 : : chr *start; /* start of string */
115 : : chr *search_start; /* search start of string */
116 : : chr *stop; /* just past end of string */
117 : : int err; /* error code if any (0 none) */
118 : : struct dfa **subdfas; /* per-tree-subre DFAs */
119 : : struct dfa **ladfas; /* per-lacon-subre DFAs */
120 : : struct sset **lblastcss; /* per-lacon-subre lookbehind restart data */
121 : : chr **lblastcp; /* per-lacon-subre lookbehind restart data */
122 : : struct smalldfa dfa1;
123 : : struct smalldfa dfa2;
124 : : };
125 : :
126 : : #define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */
127 : : #define ISERR() VISERR(v)
128 : : #define VERR(vv,e) ((vv)->err = ((vv)->err ? (vv)->err : (e)))
129 : : #define ERR(e) VERR(v, e) /* record an error */
130 : : #define NOERR() {if (ISERR()) return v->err;} /* if error seen, return it */
131 : : #define OFF(p) ((p) - v->start)
132 : : #define LOFF(p) ((long)OFF(p))
133 : :
134 : :
135 : :
136 : : /*
137 : : * forward declarations
138 : : */
139 : : /* === regexec.c === */
140 : : static struct dfa *getsubdfa(struct vars *v, struct subre *t);
141 : : static struct dfa *getladfa(struct vars *v, int n);
142 : : static int find(struct vars *v, struct cnfa *cnfa, struct colormap *cm);
143 : : static int cfind(struct vars *v, struct cnfa *cnfa, struct colormap *cm);
144 : : static int cfindloop(struct vars *v, struct cnfa *cnfa, struct colormap *cm,
145 : : struct dfa *d, struct dfa *s, chr **coldp);
146 : : static void zapallsubs(regmatch_t *p, size_t n);
147 : : static void zaptreesubs(struct vars *v, struct subre *t);
148 : : static void subset(struct vars *v, struct subre *sub, chr *begin, chr *end);
149 : : static int cdissect(struct vars *v, struct subre *t, chr *begin, chr *end);
150 : : static int ccondissect(struct vars *v, struct subre *t, chr *begin, chr *end);
151 : : static int crevcondissect(struct vars *v, struct subre *t, chr *begin, chr *end);
152 : : static int cbrdissect(struct vars *v, struct subre *t, chr *begin, chr *end);
153 : : static int caltdissect(struct vars *v, struct subre *t, chr *begin, chr *end);
154 : : static int citerdissect(struct vars *v, struct subre *t, chr *begin, chr *end);
155 : : static int creviterdissect(struct vars *v, struct subre *t, chr *begin, chr *end);
156 : :
157 : : /* === rege_dfa.c === */
158 : : static chr *longest(struct vars *v, struct dfa *d,
159 : : chr *start, chr *stop, int *hitstopp);
160 : : static chr *shortest(struct vars *v, struct dfa *d, chr *start, chr *min,
161 : : chr *max, chr **coldp, int *hitstopp);
162 : : static int matchuntil(struct vars *v, struct dfa *d, chr *probe,
163 : : struct sset **lastcss, chr **lastcp);
164 : : static chr *dfa_backref(struct vars *v, struct dfa *d, chr *start,
165 : : chr *min, chr *max, bool shortest);
166 : : static chr *lastcold(struct vars *v, struct dfa *d);
167 : : static struct dfa *newdfa(struct vars *v, struct cnfa *cnfa,
168 : : struct colormap *cm, struct smalldfa *sml);
169 : : static void freedfa(struct dfa *d);
170 : : static unsigned hash(unsigned *uv, int n);
171 : : static struct sset *initialize(struct vars *v, struct dfa *d, chr *start);
172 : : static struct sset *miss(struct vars *v, struct dfa *d, struct sset *css,
173 : : color co, chr *cp, chr *start);
174 : : static int lacon(struct vars *v, struct cnfa *pcnfa, chr *cp, color co);
175 : : static struct sset *getvacant(struct vars *v, struct dfa *d, chr *cp,
176 : : chr *start);
177 : : static struct sset *pickss(struct vars *v, struct dfa *d, chr *cp,
178 : : chr *start);
179 : :
180 : :
181 : : /*
182 : : * pg_regexec - match regular expression
183 : : */
184 : : int
8515 tgl@sss.pgh.pa.us 185 :CBC 5786948 : pg_regexec(regex_t *re,
186 : : const chr *string,
187 : : size_t len,
188 : : size_t search_start,
189 : : rm_detail_t *details,
190 : : size_t nmatch,
191 : : regmatch_t pmatch[],
192 : : int flags)
193 : : {
194 : : struct vars var;
1344 andres@anarazel.de 195 : 5786948 : struct vars *v = &var;
196 : : int st;
197 : : size_t n;
198 : : size_t i;
199 : : int backref;
200 : :
201 : : #define LOCALMAT 20
202 : : regmatch_t mat[LOCALMAT];
203 : :
204 : : #define LOCALDFAS 40
205 : : struct dfa *subdfas[LOCALDFAS];
206 : :
207 : : /* sanity checks */
8515 tgl@sss.pgh.pa.us 208 [ + - + - : 5786948 : if (re == NULL || string == NULL || re->re_magic != REMAGIC)
- + ]
8515 tgl@sss.pgh.pa.us 209 :UBC 0 : return REG_INVARG;
8515 tgl@sss.pgh.pa.us 210 [ - + ]:CBC 5786948 : if (re->re_csize != sizeof(chr))
8515 tgl@sss.pgh.pa.us 211 :UBC 0 : return REG_MIXED;
1722 tgl@sss.pgh.pa.us 212 [ + + ]:CBC 5786948 : if (search_start > len)
213 : 5 : return REG_NOMATCH;
214 : :
215 : : /* Initialize locale-dependent support */
5529 216 : 5786943 : pg_set_regex_collation(re->re_collation);
217 : :
218 : : /* setup */
8515 219 : 5786943 : v->re = re;
8335 bruce@momjian.us 220 : 5786943 : v->g = (struct guts *) re->re_guts;
221 [ + + - + ]: 5786943 : if ((v->g->cflags & REG_EXPECT) && details == NULL)
8515 tgl@sss.pgh.pa.us 222 :UBC 0 : return REG_INVARG;
8335 bruce@momjian.us 223 [ + + ]:CBC 5786943 : if (v->g->info & REG_UIMPOSSIBLE)
8515 tgl@sss.pgh.pa.us 224 : 721 : return REG_NOMATCH;
8335 bruce@momjian.us 225 : 5786222 : backref = (v->g->info & REG_UBACKREF) ? 1 : 0;
8515 tgl@sss.pgh.pa.us 226 : 5786222 : v->eflags = flags;
1755 227 [ + + + + ]: 5786222 : if (backref && nmatch <= v->g->nsub)
228 : : {
229 : : /* need larger work area */
1741 230 : 149 : v->nmatch = v->g->nsub + 1;
231 [ + + ]: 149 : if (v->nmatch <= LOCALMAT)
8515 232 : 148 : v->pmatch = mat;
233 : : else
19 234 : 1 : v->pmatch = MALLOC_ARRAY(regmatch_t, v->nmatch);
8515 235 [ - + ]: 149 : if (v->pmatch == NULL)
8515 tgl@sss.pgh.pa.us 236 :UBC 0 : return REG_ESPACE;
1741 tgl@sss.pgh.pa.us 237 :CBC 149 : zapallsubs(v->pmatch, v->nmatch);
238 : : }
239 : : else
240 : : {
241 : : /* we can store results directly in caller's array */
8515 242 : 5786073 : v->pmatch = pmatch;
243 : : /* ensure any extra entries in caller's array are filled with -1 */
1755 244 [ + + ]: 5786073 : if (nmatch > 0)
245 : 583338 : zapallsubs(pmatch, nmatch);
246 : : /* then forget about extra entries, to avoid useless work in find() */
247 [ + + ]: 5786073 : if (nmatch > v->g->nsub + 1)
248 : 670 : nmatch = v->g->nsub + 1;
249 : 5786073 : v->nmatch = nmatch;
250 : : }
8515 251 : 5786222 : v->details = details;
8335 bruce@momjian.us 252 : 5786222 : v->start = (chr *) string;
7629 253 : 5786222 : v->search_start = (chr *) string + search_start;
8335 254 : 5786222 : v->stop = (chr *) string + len;
8515 tgl@sss.pgh.pa.us 255 : 5786222 : v->err = 0;
3865 256 : 5786222 : v->subdfas = NULL;
257 : 5786222 : v->ladfas = NULL;
258 : 5786222 : v->lblastcss = NULL;
259 : 5786222 : v->lblastcp = NULL;
260 : : /* below this point, "goto cleanup" will behave sanely */
261 : :
5209 262 [ - + ]: 5786222 : assert(v->g->ntree >= 0);
263 : 5786222 : n = (size_t) v->g->ntree;
264 [ + + ]: 5786222 : if (n <= LOCALDFAS)
265 : 5786220 : v->subdfas = subdfas;
266 : : else
267 : : {
268 : : /* ntree is surely less than the number of states, so this is safe: */
3865 269 : 2 : v->subdfas = (struct dfa **) MALLOC(n * sizeof(struct dfa *));
270 [ - + ]: 2 : if (v->subdfas == NULL)
271 : : {
3865 tgl@sss.pgh.pa.us 272 :UBC 0 : st = REG_ESPACE;
273 : 0 : goto cleanup;
274 : : }
275 : : }
5209 tgl@sss.pgh.pa.us 276 [ + + ]:CBC 17380532 : for (i = 0; i < n; i++)
277 : 11594310 : v->subdfas[i] = NULL;
278 : :
3865 279 [ - + ]: 5786222 : assert(v->g->nlacons >= 0);
280 : 5786222 : n = (size_t) v->g->nlacons;
281 [ + + ]: 5786222 : if (n > 0)
282 : : {
283 : : /* nlacons is surely less than the number of arcs, so this is safe: */
284 : 1040 : v->ladfas = (struct dfa **) MALLOC(n * sizeof(struct dfa *));
285 [ - + ]: 1040 : if (v->ladfas == NULL)
286 : : {
3865 tgl@sss.pgh.pa.us 287 :UBC 0 : st = REG_ESPACE;
288 : 0 : goto cleanup;
289 : : }
3865 tgl@sss.pgh.pa.us 290 [ + + ]:CBC 3168 : for (i = 0; i < n; i++)
291 : 2128 : v->ladfas[i] = NULL;
292 : 1040 : v->lblastcss = (struct sset **) MALLOC(n * sizeof(struct sset *));
293 : 1040 : v->lblastcp = (chr **) MALLOC(n * sizeof(chr *));
294 [ + - - + ]: 1040 : if (v->lblastcss == NULL || v->lblastcp == NULL)
295 : : {
3865 tgl@sss.pgh.pa.us 296 :UBC 0 : st = REG_ESPACE;
297 : 0 : goto cleanup;
298 : : }
3865 tgl@sss.pgh.pa.us 299 [ + + ]:CBC 3168 : for (i = 0; i < n; i++)
300 : : {
301 : 2128 : v->lblastcss[i] = NULL;
302 : 2128 : v->lblastcp[i] = NULL;
303 : : }
304 : : }
305 : :
306 : : /* do it */
8515 307 [ - + ]: 5786222 : assert(v->g->tree != NULL);
308 [ + + ]: 5786222 : if (backref)
309 : 208 : st = cfind(v, &v->g->tree->cnfa, &v->g->cmap);
310 : : else
311 : 5786014 : st = find(v, &v->g->tree->cnfa, &v->g->cmap);
312 : :
313 : : /* on success, ensure caller's match vector is filled correctly */
1755 314 [ + + + + ]: 5786222 : if (st == REG_OKAY && nmatch > 0)
315 : : {
316 [ + + ]: 470764 : if (v->pmatch != pmatch)
317 : : {
318 : : /* copy portion of match vector over from (larger) work area */
319 [ - + ]: 33 : assert(nmatch <= v->nmatch);
320 : 33 : memcpy(VS(pmatch), VS(v->pmatch), nmatch * sizeof(regmatch_t));
321 : : }
322 [ + + ]: 470764 : if (v->g->cflags & REG_NOSUB)
323 : : {
324 : : /* don't expose possibly-partial sub-match results to caller */
325 : 466862 : zapallsubs(pmatch, nmatch);
326 : : }
327 : : }
328 : :
329 : : /* clean up */
3865 330 : 5319360 : cleanup:
8515 331 [ + + + + ]: 5786222 : if (v->pmatch != pmatch && v->pmatch != mat)
332 : 1 : FREE(v->pmatch);
3865 333 [ + - ]: 5786222 : if (v->subdfas != NULL)
334 : : {
335 : 5786222 : n = (size_t) v->g->ntree;
336 [ + + ]: 17380532 : for (i = 0; i < n; i++)
337 : : {
338 [ + + ]: 11594310 : if (v->subdfas[i] != NULL)
339 : 17012 : freedfa(v->subdfas[i]);
340 : : }
341 [ + + ]: 5786222 : if (v->subdfas != subdfas)
342 : 2 : FREE(v->subdfas);
343 : : }
344 [ + + ]: 5786222 : if (v->ladfas != NULL)
345 : : {
346 : 1040 : n = (size_t) v->g->nlacons;
347 [ + + ]: 3168 : for (i = 0; i < n; i++)
348 : : {
349 [ + + ]: 2128 : if (v->ladfas[i] != NULL)
350 : 75 : freedfa(v->ladfas[i]);
351 : : }
352 : 1040 : FREE(v->ladfas);
353 : : }
354 [ + + ]: 5786222 : if (v->lblastcss != NULL)
355 : 1040 : FREE(v->lblastcss);
356 [ + + ]: 5786222 : if (v->lblastcp != NULL)
357 : 1040 : FREE(v->lblastcp);
358 : :
359 : : #ifdef REG_DEBUG
360 : : if (v->eflags & (REG_FTRACE | REG_MTRACE))
361 : : fflush(stdout);
362 : : #endif
363 : :
8515 364 : 5786222 : return st;
365 : : }
366 : :
367 : : /*
368 : : * getsubdfa - create or re-fetch the DFA for a tree subre node
369 : : *
370 : : * We only need to create the DFA once per overall regex execution.
371 : : * The DFA will be freed by the cleanup step in pg_regexec().
372 : : */
373 : : static struct dfa *
3265 374 : 17996 : getsubdfa(struct vars *v,
375 : : struct subre *t)
376 : : {
1915 377 : 17996 : struct dfa *d = v->subdfas[t->id];
378 : :
379 [ + + ]: 17996 : if (d == NULL)
380 : : {
381 : 17012 : d = newdfa(v, &t->cnfa, &v->g->cmap, DOMALLOC);
1909 382 [ - + ]: 17012 : if (d == NULL)
5209 tgl@sss.pgh.pa.us 383 :UBC 0 : return NULL;
384 : : /* set up additional info if this is a backref node */
1915 tgl@sss.pgh.pa.us 385 [ + + ]:CBC 17012 : if (t->op == 'b')
386 : : {
387 : 199 : d->backno = t->backno;
388 : 199 : d->backmin = t->min;
389 : 199 : d->backmax = t->max;
390 : : }
391 : 17012 : v->subdfas[t->id] = d;
392 : : }
393 : 17996 : return d;
394 : : }
395 : :
396 : : /*
397 : : * getladfa - create or re-fetch the DFA for a LACON subre node
398 : : *
399 : : * Same as above, but for LACONs.
400 : : */
401 : : static struct dfa *
3265 402 : 158 : getladfa(struct vars *v,
403 : : int n)
404 : : {
3865 405 [ + - + - : 158 : assert(n > 0 && n < v->g->nlacons && v->g->lacons != NULL);
- + ]
406 : :
407 [ + + ]: 158 : if (v->ladfas[n] == NULL)
408 : : {
409 : 75 : struct subre *sub = &v->g->lacons[n];
410 : :
411 : 75 : v->ladfas[n] = newdfa(v, &sub->cnfa, &v->g->cmap, DOMALLOC);
412 : : /* a LACON can't contain a backref, so nothing else to do */
413 : : }
414 : 158 : return v->ladfas[n];
415 : : }
416 : :
417 : : /*
418 : : * find - find a match for the main NFA (no-complications case)
419 : : */
420 : : static int
3265 421 : 5786014 : find(struct vars *v,
422 : : struct cnfa *cnfa,
423 : : struct colormap *cm)
424 : : {
425 : : struct dfa *s;
426 : : struct dfa *d;
427 : : chr *begin;
8335 bruce@momjian.us 428 : 5786014 : chr *end = NULL;
429 : : chr *cold;
430 : : chr *open; /* open and close of range of possible starts */
431 : : chr *close;
432 : : int hitend;
433 : 5786014 : int shorter = (v->g->tree->flags & SHORTER) ? 1 : 0;
434 : :
435 : : /* first, a shot with the search RE */
8515 tgl@sss.pgh.pa.us 436 : 5786014 : s = newdfa(v, &v->g->search, cm, &v->dfa1);
1909 437 [ - + ]: 5786014 : if (s == NULL)
1909 tgl@sss.pgh.pa.us 438 :UBC 0 : return v->err;
439 : : MDEBUG(("\nsearch at %ld\n", LOFF(v->start)));
8515 tgl@sss.pgh.pa.us 440 :CBC 5786014 : cold = NULL;
7629 bruce@momjian.us 441 : 5786014 : close = shortest(v, s, v->search_start, v->search_start, v->stop,
442 : : &cold, (int *) NULL);
8515 tgl@sss.pgh.pa.us 443 : 5786014 : freedfa(s);
444 [ - + ]: 5786014 : NOERR();
8335 bruce@momjian.us 445 [ + + ]: 5786014 : if (v->g->cflags & REG_EXPECT)
446 : : {
8515 tgl@sss.pgh.pa.us 447 [ - + ]: 27 : assert(v->details != NULL);
448 [ + - ]: 27 : if (cold != NULL)
449 : 27 : v->details->rm_extend.rm_so = OFF(cold);
450 : : else
8515 tgl@sss.pgh.pa.us 451 :UBC 0 : v->details->rm_extend.rm_so = OFF(v->stop);
3265 tgl@sss.pgh.pa.us 452 :CBC 27 : v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
453 : : }
8335 bruce@momjian.us 454 [ + + ]: 5786014 : if (close == NULL) /* not found */
8515 tgl@sss.pgh.pa.us 455 : 5182266 : return REG_NOMATCH;
8335 bruce@momjian.us 456 [ + + ]: 603748 : if (v->nmatch == 0) /* found, don't need exact location */
8515 tgl@sss.pgh.pa.us 457 : 133058 : return REG_OKAY;
458 : :
459 : : /* find starting point and match */
460 [ - + ]: 470690 : assert(cold != NULL);
461 : 470690 : open = cold;
462 : 470690 : cold = NULL;
463 : : MDEBUG(("between %ld and %ld\n", LOFF(open), LOFF(close)));
464 : 470690 : d = newdfa(v, cnfa, cm, &v->dfa1);
1909 465 [ - + ]: 470690 : if (d == NULL)
1909 tgl@sss.pgh.pa.us 466 :UBC 0 : return v->err;
8335 bruce@momjian.us 467 [ + - ]:CBC 470721 : for (begin = open; begin <= close; begin++)
468 : : {
469 : : MDEBUG(("\nfind trying at %ld\n", LOFF(begin)));
8515 tgl@sss.pgh.pa.us 470 [ + + ]: 470721 : if (shorter)
471 : 86 : end = shortest(v, d, begin, begin, v->stop,
472 : : (chr **) NULL, &hitend);
473 : : else
474 : 470635 : end = longest(v, d, begin, v->stop, &hitend);
3907 475 [ - + ]: 470721 : if (ISERR())
476 : : {
3907 tgl@sss.pgh.pa.us 477 :UBC 0 : freedfa(d);
478 : 0 : return v->err;
479 : : }
8515 tgl@sss.pgh.pa.us 480 [ + + + + ]:CBC 470721 : if (hitend && cold == NULL)
481 : 4818 : cold = begin;
482 [ + + ]: 470721 : if (end != NULL)
8335 bruce@momjian.us 483 : 470690 : break; /* NOTE BREAK OUT */
484 : : }
8515 tgl@sss.pgh.pa.us 485 [ - + ]: 470690 : assert(end != NULL); /* search RE succeeded so loop should */
486 : 470690 : freedfa(d);
487 : :
488 : : /* and pin down details */
489 [ - + ]: 470690 : assert(v->nmatch > 0);
490 : 470690 : v->pmatch[0].rm_so = OFF(begin);
491 : 470690 : v->pmatch[0].rm_eo = OFF(end);
8335 bruce@momjian.us 492 [ + + ]: 470690 : if (v->g->cflags & REG_EXPECT)
493 : : {
8515 tgl@sss.pgh.pa.us 494 [ + + ]: 10 : if (cold != NULL)
495 : 5 : v->details->rm_extend.rm_so = OFF(cold);
496 : : else
497 : 5 : v->details->rm_extend.rm_so = OFF(v->stop);
3265 498 : 10 : v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
499 : : }
8335 bruce@momjian.us 500 [ + + ]: 470690 : if (v->nmatch == 1) /* no need for submatches */
8515 tgl@sss.pgh.pa.us 501 : 467663 : return REG_OKAY;
502 : :
503 : : /* find submatches */
5209 504 : 3027 : return cdissect(v, v->g->tree, begin, end);
505 : : }
506 : :
507 : : /*
508 : : * cfind - find a match for the main NFA (with complications)
509 : : */
510 : : static int
3265 511 : 208 : cfind(struct vars *v,
512 : : struct cnfa *cnfa,
513 : : struct colormap *cm)
514 : : {
515 : : struct dfa *s;
516 : : struct dfa *d;
517 : : chr *cold;
518 : : int ret;
519 : :
8515 520 : 208 : s = newdfa(v, &v->g->search, cm, &v->dfa1);
1909 521 [ - + ]: 208 : if (s == NULL)
1909 tgl@sss.pgh.pa.us 522 :UBC 0 : return v->err;
8515 tgl@sss.pgh.pa.us 523 :CBC 208 : d = newdfa(v, cnfa, cm, &v->dfa2);
1909 524 [ - + ]: 208 : if (d == NULL)
525 : : {
8515 tgl@sss.pgh.pa.us 526 :UBC 0 : freedfa(s);
527 : 0 : return v->err;
528 : : }
529 : :
8515 tgl@sss.pgh.pa.us 530 :CBC 208 : ret = cfindloop(v, cnfa, cm, d, s, &cold);
531 : :
532 : 208 : freedfa(d);
533 : 208 : freedfa(s);
534 [ - + ]: 208 : NOERR();
8335 bruce@momjian.us 535 [ - + ]: 208 : if (v->g->cflags & REG_EXPECT)
536 : : {
8515 tgl@sss.pgh.pa.us 537 [ # # ]:UBC 0 : assert(v->details != NULL);
538 [ # # ]: 0 : if (cold != NULL)
539 : 0 : v->details->rm_extend.rm_so = OFF(cold);
540 : : else
541 : 0 : v->details->rm_extend.rm_so = OFF(v->stop);
3265 542 : 0 : v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
543 : : }
8515 tgl@sss.pgh.pa.us 544 :CBC 208 : return ret;
545 : : }
546 : :
547 : : /*
548 : : * cfindloop - the heart of cfind
549 : : */
550 : : static int
3265 551 : 208 : cfindloop(struct vars *v,
552 : : struct cnfa *cnfa,
553 : : struct colormap *cm,
554 : : struct dfa *d,
555 : : struct dfa *s,
556 : : chr **coldp) /* where to put coldstart pointer */
557 : : {
558 : : chr *begin;
559 : : chr *end;
560 : : chr *cold;
561 : : chr *open; /* open and close of range of possible starts */
562 : : chr *close;
563 : : chr *estart;
564 : : chr *estop;
565 : : int er;
8335 bruce@momjian.us 566 : 208 : int shorter = v->g->tree->flags & SHORTER;
567 : : int hitend;
568 : :
8515 tgl@sss.pgh.pa.us 569 [ + - - + ]: 208 : assert(d != NULL && s != NULL);
570 : 208 : cold = NULL;
7629 bruce@momjian.us 571 : 208 : close = v->search_start;
572 : : do
573 : : {
574 : : /* Search with the search RE for match range at/beyond "close" */
575 : : MDEBUG(("\ncsearch at %ld\n", LOFF(close)));
8335 576 : 232 : close = shortest(v, s, close, close, v->stop, &cold, (int *) NULL);
3893 tgl@sss.pgh.pa.us 577 [ - + ]: 232 : if (ISERR())
578 : : {
3893 tgl@sss.pgh.pa.us 579 :UBC 0 : *coldp = cold;
580 : 0 : return v->err;
581 : : }
8515 tgl@sss.pgh.pa.us 582 [ + + ]:CBC 232 : if (close == NULL)
3893 583 : 23 : break; /* no more possible match anywhere */
8515 584 [ - + ]: 209 : assert(cold != NULL);
585 : 209 : open = cold;
586 : 209 : cold = NULL;
587 : : /* Search for matches starting between "open" and "close" inclusive */
588 : : MDEBUG(("cbetween %ld and %ld\n", LOFF(open), LOFF(close)));
8335 bruce@momjian.us 589 [ + + ]: 749 : for (begin = open; begin <= close; begin++)
590 : : {
591 : : MDEBUG(("\ncfind trying at %ld\n", LOFF(begin)));
8515 tgl@sss.pgh.pa.us 592 : 659 : estart = begin;
593 : 659 : estop = v->stop;
594 : : for (;;)
595 : : {
596 : : /* Here we use the top node's detailed RE */
597 [ + + ]: 942 : if (shorter)
598 : 141 : end = shortest(v, d, begin, estart,
599 : : estop, (chr **) NULL, &hitend);
600 : : else
601 : 801 : end = longest(v, d, begin, estop,
602 : : &hitend);
3893 603 [ - + ]: 942 : if (ISERR())
604 : : {
3893 tgl@sss.pgh.pa.us 605 :UBC 0 : *coldp = cold;
606 : 0 : return v->err;
607 : : }
8515 tgl@sss.pgh.pa.us 608 [ + + + + ]:CBC 942 : if (hitend && cold == NULL)
609 : 147 : cold = begin;
610 [ + + ]: 942 : if (end == NULL)
3893 611 : 513 : break; /* no match with this begin point, try next */
612 : : MDEBUG(("tentative end %ld\n", LOFF(end)));
613 : : /* Dissect the potential match to see if it really matches */
8515 614 : 429 : er = cdissect(v, v->g->tree, begin, end);
8335 bruce@momjian.us 615 [ + + ]: 429 : if (er == REG_OKAY)
616 : : {
617 [ + - ]: 119 : if (v->nmatch > 0)
618 : : {
8515 tgl@sss.pgh.pa.us 619 : 119 : v->pmatch[0].rm_so = OFF(begin);
620 : 119 : v->pmatch[0].rm_eo = OFF(end);
621 : : }
622 : 119 : *coldp = cold;
623 : 119 : return REG_OKAY;
624 : : }
8335 bruce@momjian.us 625 [ - + ]: 310 : if (er != REG_NOMATCH)
626 : : {
8515 tgl@sss.pgh.pa.us 627 [ # # ]:UBC 0 : ERR(er);
7553 628 : 0 : *coldp = cold;
8515 629 : 0 : return er;
630 : : }
631 : : /* Try next longer/shorter match with same begin point */
8515 tgl@sss.pgh.pa.us 632 [ + + ]:CBC 310 : if (shorter)
633 : : {
4699 634 [ + + ]: 119 : if (end == estop)
3893 635 : 17 : break; /* no more, so try next begin point */
8515 636 : 102 : estart = end + 1;
637 : : }
638 : : else
639 : : {
4699 640 [ + + ]: 191 : if (end == begin)
3893 641 : 10 : break; /* no more, so try next begin point */
8515 642 : 181 : estop = end - 1;
643 : : }
644 : : } /* end loop over endpoint positions */
645 : : } /* end loop over beginning positions */
646 : :
647 : : /*
648 : : * If we get here, there is no possible match starting at or before
649 : : * "close", so consider matches beyond that. We'll do a fresh search
650 : : * with the search RE to find a new promising match range.
651 : : */
3893 652 : 90 : close++;
8515 653 [ + + ]: 90 : } while (close < v->stop);
654 : :
655 : 89 : *coldp = cold;
656 : 89 : return REG_NOMATCH;
657 : : }
658 : :
659 : : /*
660 : : * zapallsubs - initialize all subexpression matches to "no match"
661 : : *
662 : : * Note that p[0], the overall-match location, is not touched.
663 : : */
664 : : static void
5209 665 : 1050349 : zapallsubs(regmatch_t *p,
666 : : size_t n)
667 : : {
668 : : size_t i;
669 : :
8335 bruce@momjian.us 670 [ + + ]: 1061438 : for (i = n - 1; i > 0; i--)
671 : : {
8515 tgl@sss.pgh.pa.us 672 : 11089 : p[i].rm_so = -1;
673 : 11089 : p[i].rm_eo = -1;
674 : : }
675 : 1050349 : }
676 : :
677 : : /*
678 : : * zaptreesubs - initialize subexpressions within subtree to "no match"
679 : : */
680 : : static void
3265 681 : 739 : zaptreesubs(struct vars *v,
682 : : struct subre *t)
683 : : {
1925 684 : 739 : int n = t->capno;
685 : : struct subre *t2;
686 : :
687 [ + + ]: 739 : if (n > 0)
688 : : {
5119 689 [ + - ]: 328 : if ((size_t) n < v->nmatch)
690 : : {
691 : 328 : v->pmatch[n].rm_so = -1;
692 : 328 : v->pmatch[n].rm_eo = -1;
693 : : }
694 : : }
695 : :
1925 696 [ + + ]: 988 : for (t2 = t->child; t2 != NULL; t2 = t2->sibling)
697 : 249 : zaptreesubs(v, t2);
8515 698 : 739 : }
699 : :
700 : : /*
701 : : * subset - set subexpression match data for a successful subre
702 : : */
703 : : static void
3265 704 : 5572 : subset(struct vars *v,
705 : : struct subre *sub,
706 : : chr *begin,
707 : : chr *end)
708 : : {
1925 709 : 5572 : int n = sub->capno;
710 : :
8515 711 [ - + ]: 5572 : assert(n > 0);
8335 bruce@momjian.us 712 [ + + ]: 5572 : if ((size_t) n >= v->nmatch)
8515 tgl@sss.pgh.pa.us 713 : 15 : return;
714 : :
715 : : MDEBUG(("%d: setting %d = %ld-%ld\n", sub->id, n, LOFF(begin), LOFF(end)));
716 : 5557 : v->pmatch[n].rm_so = OFF(begin);
717 : 5557 : v->pmatch[n].rm_eo = OFF(end);
718 : : }
719 : :
720 : : /*
721 : : * cdissect - check backrefs and determine subexpression matches
722 : : *
723 : : * cdissect recursively processes a subre tree to check matching of backrefs
724 : : * and/or identify submatch boundaries for capture nodes. The proposed match
725 : : * runs from "begin" to "end" (not including "end"), and we are basically
726 : : * "dissecting" it to see where the submatches are.
727 : : *
728 : : * Before calling any level of cdissect, the caller must have run the node's
729 : : * DFA and found that the proposed substring satisfies the DFA. (We make
730 : : * the caller do that because in concatenation and iteration nodes, it's
731 : : * much faster to check all the substrings against the child DFAs before we
732 : : * recurse.)
733 : : *
734 : : * A side-effect of a successful match is to save match locations for
735 : : * capturing subexpressions in v->pmatch[]. This is a little bit tricky,
736 : : * so we make the following rules:
737 : : * 1. Before initial entry to cdissect, all match data must have been
738 : : * cleared (this is seen to by zapallsubs).
739 : : * 2. Before any recursive entry to cdissect, the match data for that
740 : : * subexpression tree must be guaranteed clear (see zaptreesubs).
741 : : * 3. When returning REG_OKAY, each level of cdissect will have saved
742 : : * any relevant match locations.
743 : : * 4. When returning REG_NOMATCH, each level of cdissect will guarantee
744 : : * that its subexpression match locations are again clear.
745 : : * 5. No guarantees are made for error cases (i.e., other result codes).
746 : : * 6. When a level of cdissect abandons a successful sub-match, it will
747 : : * clear that subtree's match locations with zaptreesubs before trying
748 : : * any new DFA match or cdissect call for that subtree or any subtree
749 : : * to its right (that is, any subtree that could have a backref into the
750 : : * abandoned match).
751 : : * This may seem overly complicated, but it's difficult to simplify it
752 : : * because of the provision that match locations must be reset before
753 : : * any fresh DFA match (a rule that is needed to make dfa_backref safe).
754 : : * That means it won't work to just reset relevant match locations at the
755 : : * start of each cdissect level.
756 : : */
757 : : static int /* regexec return code */
3265 758 : 20981 : cdissect(struct vars *v,
759 : : struct subre *t,
760 : : chr *begin, /* beginning of relevant substring */
761 : : chr *end) /* end of same */
762 : : {
763 : : int er;
764 : :
8515 765 [ - + ]: 20981 : assert(t != NULL);
766 : : MDEBUG(("%d: cdissect %c %ld-%ld\n", t->id, t->op, LOFF(begin), LOFF(end)));
767 : :
768 : : /* handy place to check for operation cancel */
1148 tmunro@postgresql.or 769 [ - + ]: 20981 : INTERRUPT(v->re);
770 : : /* ... and stack overrun */
3893 tgl@sss.pgh.pa.us 771 [ - + ]: 20981 : if (STACK_TOO_DEEP(v->re))
3893 tgl@sss.pgh.pa.us 772 :UBC 0 : return REG_ETOOBIG;
773 : :
8335 bruce@momjian.us 774 [ + + + + :CBC 20981 : switch (t->op)
+ + - ]
775 : : {
776 : 11531 : case '=': /* terminal node */
1925 tgl@sss.pgh.pa.us 777 [ - + ]: 11531 : assert(t->child == NULL);
5209 778 : 11531 : er = REG_OKAY; /* no action, parent did the work */
779 : 11531 : break;
5213 780 : 303 : case 'b': /* back reference */
1925 781 [ - + ]: 303 : assert(t->child == NULL);
5209 782 : 303 : er = cbrdissect(v, t, begin, end);
783 : 303 : break;
8335 bruce@momjian.us 784 : 8835 : case '.': /* concatenation */
1925 tgl@sss.pgh.pa.us 785 [ - + ]: 8835 : assert(t->child != NULL);
786 [ + + ]: 8835 : if (t->child->flags & SHORTER) /* reverse scan */
5209 787 : 237 : er = crevcondissect(v, t, begin, end);
788 : : else
789 : 8598 : er = ccondissect(v, t, begin, end);
790 : 8835 : break;
791 : 113 : case '|': /* alternation */
1925 792 [ - + ]: 113 : assert(t->child != NULL);
5209 793 : 113 : er = caltdissect(v, t, begin, end);
794 : 113 : break;
795 : 167 : case '*': /* iteration */
1925 796 [ - + ]: 167 : assert(t->child != NULL);
797 [ + + ]: 167 : if (t->child->flags & SHORTER) /* reverse scan */
5209 798 : 8 : er = creviterdissect(v, t, begin, end);
799 : : else
800 : 159 : er = citerdissect(v, t, begin, end);
801 : 167 : break;
1925 802 : 32 : case '(': /* no-op capture node */
803 [ - + ]: 32 : assert(t->child != NULL);
804 : 32 : er = cdissect(v, t->child, begin, end);
5209 805 : 32 : break;
8335 bruce@momjian.us 806 :UBC 0 : default:
5209 tgl@sss.pgh.pa.us 807 : 0 : er = REG_ASSERT;
808 : 0 : break;
809 : : }
810 : :
811 : : /*
812 : : * We should never have a match failure unless backrefs lurk below;
813 : : * otherwise, either caller failed to check the DFA, or there's some
814 : : * inconsistency between the DFA and the node's innards.
815 : : */
5209 tgl@sss.pgh.pa.us 816 [ + + - + ]:CBC 20981 : assert(er != REG_NOMATCH || (t->flags & BACKR));
817 : :
818 : : /*
819 : : * If this node is marked as capturing, save successful match's location.
820 : : */
1925 821 [ + + + + ]: 20981 : if (t->capno > 0 && er == REG_OKAY)
822 : 5572 : subset(v, t, begin, end);
823 : :
5209 824 : 20981 : return er;
825 : : }
826 : :
827 : : /*
828 : : * ccondissect - dissect match for concatenation node
829 : : */
830 : : static int /* regexec return code */
3265 831 : 8598 : ccondissect(struct vars *v,
832 : : struct subre *t,
833 : : chr *begin, /* beginning of relevant substring */
834 : : chr *end) /* end of same */
835 : : {
1925 836 : 8598 : struct subre *left = t->child;
837 : 8598 : struct subre *right = left->sibling;
838 : : struct dfa *d;
839 : : struct dfa *d2;
840 : : chr *mid;
841 : : int er;
842 : :
8515 843 [ - + ]: 8598 : assert(t->op == '.');
1925 844 [ + - - + ]: 8598 : assert(left != NULL && left->cnfa.nstates > 0);
845 [ + - - + ]: 8598 : assert(right != NULL && right->cnfa.nstates > 0);
846 [ - + ]: 8598 : assert(right->sibling == NULL);
847 [ - + ]: 8598 : assert(!(left->flags & SHORTER));
848 : :
849 : 8598 : d = getsubdfa(v, left);
5209 850 [ - + ]: 8598 : NOERR();
1925 851 : 8598 : d2 = getsubdfa(v, right);
5209 852 [ - + ]: 8598 : NOERR();
853 : : MDEBUG(("%d: ccondissect %ld-%ld\n", t->id, LOFF(begin), LOFF(end)));
854 : :
855 : : /* pick a tentative midpoint */
856 : 8598 : mid = longest(v, d, begin, end, (int *) NULL);
3893 857 [ - + ]: 8598 : NOERR();
5209 858 [ + + ]: 8598 : if (mid == NULL)
859 : 8 : return REG_NOMATCH;
860 : : MDEBUG(("%d: tentative midpoint %ld\n", t->id, LOFF(mid)));
861 : :
862 : : /* iterate until satisfaction or failure */
863 : : for (;;)
864 : : {
865 : : /* try this midpoint on for size */
5962 866 [ + + ]: 10590 : if (longest(v, d2, mid, end, (int *) NULL) == end)
867 : : {
1925 868 : 8533 : er = cdissect(v, left, begin, mid);
5962 869 [ + + ]: 8533 : if (er == REG_OKAY)
870 : : {
1925 871 : 8459 : er = cdissect(v, right, mid, end);
5962 872 [ + + ]: 8459 : if (er == REG_OKAY)
873 : : {
874 : : /* satisfaction */
875 : : MDEBUG(("%d: successful\n", t->id));
876 : 8101 : return REG_OKAY;
877 : : }
878 : : /* Reset left's matches (right should have done so itself) */
1741 879 : 358 : zaptreesubs(v, left);
880 : : }
5209 881 [ - + ]: 432 : if (er != REG_NOMATCH)
5962 tgl@sss.pgh.pa.us 882 :UBC 0 : return er;
883 : : }
3893 tgl@sss.pgh.pa.us 884 [ - + ]:CBC 2489 : NOERR();
885 : :
886 : : /* that midpoint didn't work, find a new one */
8335 bruce@momjian.us 887 [ + + ]: 2489 : if (mid == begin)
888 : : {
889 : : /* all possibilities exhausted */
890 : : MDEBUG(("%d: no midpoint\n", t->id));
8515 tgl@sss.pgh.pa.us 891 : 105 : return REG_NOMATCH;
892 : : }
8335 bruce@momjian.us 893 : 2384 : mid = longest(v, d, begin, mid - 1, (int *) NULL);
3893 tgl@sss.pgh.pa.us 894 [ - + ]: 2384 : NOERR();
8335 bruce@momjian.us 895 [ + + ]: 2384 : if (mid == NULL)
896 : : {
897 : : /* failed to find a new one */
898 : : MDEBUG(("%d: failed midpoint\n", t->id));
8515 tgl@sss.pgh.pa.us 899 : 384 : return REG_NOMATCH;
900 : : }
901 : : MDEBUG(("%d: new midpoint %ld\n", t->id, LOFF(mid)));
902 : : }
903 : :
904 : : /* can't get here */
905 : : return REG_ASSERT;
906 : : }
907 : :
908 : : /*
909 : : * crevcondissect - dissect match for concatenation node, shortest-first
910 : : */
911 : : static int /* regexec return code */
3265 912 : 237 : crevcondissect(struct vars *v,
913 : : struct subre *t,
914 : : chr *begin, /* beginning of relevant substring */
915 : : chr *end) /* end of same */
916 : : {
1925 917 : 237 : struct subre *left = t->child;
918 : 237 : struct subre *right = left->sibling;
919 : : struct dfa *d;
920 : : struct dfa *d2;
921 : : chr *mid;
922 : : int er;
923 : :
8515 924 [ - + ]: 237 : assert(t->op == '.');
1925 925 [ + - - + ]: 237 : assert(left != NULL && left->cnfa.nstates > 0);
926 [ + - - + ]: 237 : assert(right != NULL && right->cnfa.nstates > 0);
927 [ - + ]: 237 : assert(right->sibling == NULL);
928 [ - + ]: 237 : assert(left->flags & SHORTER);
929 : :
930 : 237 : d = getsubdfa(v, left);
5209 931 [ - + ]: 237 : NOERR();
1925 932 : 237 : d2 = getsubdfa(v, right);
5209 933 [ - + ]: 237 : NOERR();
934 : : MDEBUG(("%d: crevcondissect %ld-%ld\n", t->id, LOFF(begin), LOFF(end)));
935 : :
936 : : /* pick a tentative midpoint */
937 : 237 : mid = shortest(v, d, begin, begin, end, (chr **) NULL, (int *) NULL);
3893 938 [ - + ]: 237 : NOERR();
5209 939 [ + - ]: 237 : if (mid == NULL)
5209 tgl@sss.pgh.pa.us 940 :UBC 0 : return REG_NOMATCH;
941 : : MDEBUG(("%d: tentative midpoint %ld\n", t->id, LOFF(mid)));
942 : :
943 : : /* iterate until satisfaction or failure */
944 : : for (;;)
945 : : {
946 : : /* try this midpoint on for size */
5962 tgl@sss.pgh.pa.us 947 [ + + ]:CBC 853 : if (longest(v, d2, mid, end, (int *) NULL) == end)
948 : : {
1925 949 : 128 : er = cdissect(v, left, begin, mid);
5962 950 [ + - ]: 128 : if (er == REG_OKAY)
951 : : {
1925 952 : 128 : er = cdissect(v, right, mid, end);
5962 953 [ + + ]: 128 : if (er == REG_OKAY)
954 : : {
955 : : /* satisfaction */
956 : : MDEBUG(("%d: successful\n", t->id));
957 : 116 : return REG_OKAY;
958 : : }
959 : : /* Reset left's matches (right should have done so itself) */
1741 960 : 12 : zaptreesubs(v, left);
961 : : }
5209 962 [ - + ]: 12 : if (er != REG_NOMATCH)
5962 tgl@sss.pgh.pa.us 963 :UBC 0 : return er;
964 : : }
3893 tgl@sss.pgh.pa.us 965 [ - + ]:CBC 737 : NOERR();
966 : :
967 : : /* that midpoint didn't work, find a new one */
8335 bruce@momjian.us 968 [ + + ]: 737 : if (mid == end)
969 : : {
970 : : /* all possibilities exhausted */
971 : : MDEBUG(("%d: no midpoint\n", t->id));
8515 tgl@sss.pgh.pa.us 972 : 121 : return REG_NOMATCH;
973 : : }
8335 bruce@momjian.us 974 : 616 : mid = shortest(v, d, begin, mid + 1, end, (chr **) NULL, (int *) NULL);
3893 tgl@sss.pgh.pa.us 975 [ - + ]: 616 : NOERR();
8335 bruce@momjian.us 976 [ - + ]: 616 : if (mid == NULL)
977 : : {
978 : : /* failed to find a new one */
979 : : MDEBUG(("%d: failed midpoint\n", t->id));
8515 tgl@sss.pgh.pa.us 980 :UBC 0 : return REG_NOMATCH;
981 : : }
982 : : MDEBUG(("%d: new midpoint %ld\n", t->id, LOFF(mid)));
983 : : }
984 : :
985 : : /* can't get here */
986 : : return REG_ASSERT;
987 : : }
988 : :
989 : : /*
990 : : * cbrdissect - dissect match for backref node
991 : : *
992 : : * The backref match might already have been verified by dfa_backref(),
993 : : * but we don't know that for sure so must check it here.
994 : : */
995 : : static int /* regexec return code */
3265 tgl@sss.pgh.pa.us 996 :CBC 303 : cbrdissect(struct vars *v,
997 : : struct subre *t,
998 : : chr *begin, /* beginning of relevant substring */
999 : : chr *end) /* end of same */
1000 : : {
1925 1001 : 303 : int n = t->backno;
1002 : : size_t numreps;
1003 : : size_t tlen;
1004 : : size_t brlen;
1005 : : chr *brstring;
1006 : : chr *p;
8335 bruce@momjian.us 1007 : 303 : int min = t->min;
1008 : 303 : int max = t->max;
1009 : :
8515 tgl@sss.pgh.pa.us 1010 [ - + ]: 303 : assert(t != NULL);
1011 [ - + ]: 303 : assert(t->op == 'b');
1012 [ - + ]: 303 : assert(n >= 0);
8335 bruce@momjian.us 1013 [ - + ]: 303 : assert((size_t) n < v->nmatch);
1014 : :
1015 : : MDEBUG(("%d: cbrdissect %d{%d-%d} %ld-%ld\n", t->id, n, min, max,
1016 : : LOFF(begin), LOFF(end)));
1017 : :
1018 : : /* get the backreferenced string */
8515 tgl@sss.pgh.pa.us 1019 [ + + ]: 303 : if (v->pmatch[n].rm_so == -1)
1020 : 83 : return REG_NOMATCH;
5213 1021 : 220 : brstring = v->start + v->pmatch[n].rm_so;
1022 : 220 : brlen = v->pmatch[n].rm_eo - v->pmatch[n].rm_so;
1023 : :
1024 : : /* special cases for zero-length strings */
1025 [ + + ]: 220 : if (brlen == 0)
1026 : : {
1027 : : /*
1028 : : * matches only if target is zero length, but any number of
1029 : : * repetitions can be considered to be present
1030 : : */
1031 [ + - + - ]: 11 : if (begin == end && min <= max)
1032 : : {
1033 : : MDEBUG(("%d: backref matched trivially\n", t->id));
1034 : 11 : return REG_OKAY;
1035 : : }
5213 tgl@sss.pgh.pa.us 1036 :UBC 0 : return REG_NOMATCH;
1037 : : }
5213 tgl@sss.pgh.pa.us 1038 [ + + ]:CBC 209 : if (begin == end)
1039 : : {
1040 : : /* matches only if zero repetitions are okay */
1041 [ + + ]: 8 : if (min == 0)
1042 : : {
1043 : : MDEBUG(("%d: backref matched trivially\n", t->id));
8515 1044 : 7 : return REG_OKAY;
1045 : : }
1046 : 1 : return REG_NOMATCH;
1047 : : }
1048 : :
1049 : : /*
1050 : : * check target length to see if it could possibly be an allowed number of
1051 : : * repetitions of brstring
1052 : : */
5213 1053 [ - + ]: 201 : assert(end > begin);
1054 : 201 : tlen = end - begin;
1055 [ + + ]: 201 : if (tlen % brlen != 0)
1056 : 5 : return REG_NOMATCH;
1057 : 196 : numreps = tlen / brlen;
3909 1058 [ + - + + : 196 : if (numreps < min || (numreps > max && max != DUPINF))
+ - ]
8515 1059 : 3 : return REG_NOMATCH;
1060 : :
1061 : : /* okay, compare the actual string contents */
5213 1062 : 193 : p = begin;
1063 [ + + ]: 338 : while (numreps-- > 0)
1064 : : {
1065 [ + + ]: 219 : if ((*v->g->compare) (brstring, p, brlen) != 0)
1066 : 74 : return REG_NOMATCH;
1067 : 145 : p += brlen;
1068 : : }
1069 : :
1070 : : MDEBUG(("%d: backref matched\n", t->id));
1071 : 119 : return REG_OKAY;
1072 : : }
1073 : :
1074 : : /*
1075 : : * caltdissect - dissect match for alternation node
1076 : : */
1077 : : static int /* regexec return code */
3265 1078 : 113 : caltdissect(struct vars *v,
1079 : : struct subre *t,
1080 : : chr *begin, /* beginning of relevant substring */
1081 : : chr *end) /* end of same */
1082 : : {
1083 : : struct dfa *d;
1084 : : int er;
1085 : :
1925 1086 [ - + ]: 113 : assert(t->op == '|');
1087 : :
1088 : 113 : t = t->child;
1089 : : /* there should be at least 2 alternatives */
1090 [ + - - + ]: 113 : assert(t != NULL && t->sibling != NULL);
1091 : :
5209 1092 [ + + ]: 200 : while (t != NULL)
1093 : : {
1925 1094 [ - + ]: 160 : assert(t->cnfa.nstates > 0);
1095 : :
1096 : : MDEBUG(("%d: caltdissect %ld-%ld\n", t->id, LOFF(begin), LOFF(end)));
1097 : :
1098 : 160 : d = getsubdfa(v, t);
5209 1099 [ - + ]: 160 : NOERR();
1100 [ + + ]: 160 : if (longest(v, d, begin, end, (int *) NULL) == end)
1101 : : {
1102 : : MDEBUG(("%d: caltdissect matched\n", t->id));
1925 1103 : 125 : er = cdissect(v, t, begin, end);
5209 1104 [ + + ]: 125 : if (er != REG_NOMATCH)
1105 : 73 : return er;
1106 : : }
3893 1107 [ - + ]: 87 : NOERR();
1108 : :
1925 1109 : 87 : t = t->sibling;
1110 : : }
1111 : :
5209 1112 : 40 : return REG_NOMATCH;
1113 : : }
1114 : :
1115 : : /*
1116 : : * citerdissect - dissect match for iteration node
1117 : : */
1118 : : static int /* regexec return code */
3265 1119 : 159 : citerdissect(struct vars *v,
1120 : : struct subre *t,
1121 : : chr *begin, /* beginning of relevant substring */
1122 : : chr *end) /* end of same */
1123 : : {
1124 : : struct dfa *d;
1125 : : chr **endpts;
1126 : : chr *limit;
1127 : : int min_matches;
1128 : : size_t max_matches;
1129 : : int nverified;
1130 : : int k;
1131 : : int i;
1132 : : int er;
1133 : :
5209 1134 [ - + ]: 159 : assert(t->op == '*');
1925 1135 [ + - - + ]: 159 : assert(t->child != NULL && t->child->cnfa.nstates > 0);
1136 [ - + ]: 159 : assert(!(t->child->flags & SHORTER));
5209 1137 [ - + ]: 159 : assert(begin <= end);
1138 : :
1139 : : MDEBUG(("%d: citerdissect %ld-%ld\n", t->id, LOFF(begin), LOFF(end)));
1140 : :
1141 : : /*
1142 : : * For the moment, assume the minimum number of matches is 1. If zero
1143 : : * matches are allowed, and the target string is empty, we are allowed to
1144 : : * match regardless of the contents of the iter node --- but we would
1145 : : * prefer to match once, so that capturing parens get set. (An example of
1146 : : * the concern here is a pattern like "()*\1", which historically this
1147 : : * code has allowed to succeed.) Therefore, we deal with the zero-matches
1148 : : * case at the bottom, after failing to find any other way to match.
1149 : : */
1150 : 159 : min_matches = t->min;
1151 [ + + ]: 159 : if (min_matches <= 0)
1152 : 105 : min_matches = 1;
1153 : :
1154 : : /*
1155 : : * We need workspace to track the endpoints of each sub-match. Normally
1156 : : * we consider only nonzero-length sub-matches, so there can be at most
1157 : : * end-begin of them. However, if min is larger than that, we will also
1158 : : * consider zero-length sub-matches in order to find enough matches.
1159 : : *
1160 : : * For convenience, endpts[0] contains the "begin" pointer and we store
1161 : : * sub-match endpoints in endpts[1..max_matches].
1162 : : */
1163 : 159 : max_matches = end - begin;
3909 1164 [ - + - - ]: 159 : if (max_matches > t->max && t->max != DUPINF)
5209 tgl@sss.pgh.pa.us 1165 :UBC 0 : max_matches = t->max;
5209 tgl@sss.pgh.pa.us 1166 [ + + ]:CBC 159 : if (max_matches < min_matches)
1167 : 97 : max_matches = min_matches;
19 1168 : 159 : endpts = MALLOC_ARRAY(chr *, max_matches + 1);
5209 1169 [ - + ]: 159 : if (endpts == NULL)
5209 tgl@sss.pgh.pa.us 1170 :UBC 0 : return REG_ESPACE;
5209 tgl@sss.pgh.pa.us 1171 :CBC 159 : endpts[0] = begin;
1172 : :
1925 1173 : 159 : d = getsubdfa(v, t->child);
5209 1174 [ - + ]: 159 : if (ISERR())
1175 : : {
5209 tgl@sss.pgh.pa.us 1176 :UBC 0 : FREE(endpts);
1177 : 0 : return v->err;
1178 : : }
1179 : :
1180 : : /*
1181 : : * Our strategy is to first find a set of sub-match endpoints that are
1182 : : * valid according to the child node's DFA, and then recursively dissect
1183 : : * each sub-match to confirm validity. If any validity check fails,
1184 : : * backtrack that sub-match and try again. And, when we next try for a
1185 : : * validity check, we need not recheck any successfully verified
1186 : : * sub-matches that we didn't move the endpoints of. nverified remembers
1187 : : * how many sub-matches are currently known okay.
1188 : : */
1189 : :
1190 : : /* initialize to consider first sub-match */
5209 tgl@sss.pgh.pa.us 1191 :CBC 159 : nverified = 0;
1192 : 159 : k = 1;
1193 : 159 : limit = end;
1194 : :
1195 : : /* iterate until satisfaction or failure */
1196 [ + + ]: 725 : while (k > 0)
1197 : : {
1198 : : /* try to find an endpoint for the k'th sub-match */
1199 : 593 : endpts[k] = longest(v, d, endpts[k - 1], limit, (int *) NULL);
3893 1200 [ - + ]: 593 : if (ISERR())
1201 : : {
3893 tgl@sss.pgh.pa.us 1202 :UBC 0 : FREE(endpts);
1203 : 0 : return v->err;
1204 : : }
5209 tgl@sss.pgh.pa.us 1205 [ + + ]:CBC 593 : if (endpts[k] == NULL)
1206 : : {
1207 : : /* no match possible, so see if we can shorten previous one */
1208 : 306 : k--;
1209 : 306 : goto backtrack;
1210 : : }
1211 : : MDEBUG(("%d: working endpoint %d: %ld\n",
1212 : : t->id, k, LOFF(endpts[k])));
1213 : :
1214 : : /* k'th sub-match can no longer be considered verified */
1215 [ + + ]: 287 : if (nverified >= k)
1216 : 12 : nverified = k - 1;
1217 : :
1218 [ + + ]: 287 : if (endpts[k] != end)
1219 : : {
1220 : : /* haven't reached end yet, try another iteration if allowed */
1221 [ - + ]: 200 : if (k >= max_matches)
1222 : : {
1223 : : /* must try to shorten some previous match */
5209 tgl@sss.pgh.pa.us 1224 :UBC 0 : k--;
1225 : 0 : goto backtrack;
1226 : : }
1227 : :
1228 : : /* reject zero-length match unless necessary to achieve min */
5209 tgl@sss.pgh.pa.us 1229 [ - + - - ]:CBC 200 : if (endpts[k] == endpts[k - 1] &&
5209 tgl@sss.pgh.pa.us 1230 [ # # ]:UBC 0 : (k >= min_matches || min_matches - k < end - endpts[k]))
1231 : 0 : goto backtrack;
1232 : :
5209 tgl@sss.pgh.pa.us 1233 :CBC 200 : k++;
1234 : 200 : limit = end;
1235 : 200 : continue;
1236 : : }
1237 : :
1238 : : /*
1239 : : * We've identified a way to divide the string into k sub-matches that
1240 : : * works so far as the child DFA can tell. If k is an allowed number
1241 : : * of matches, start the slow part: recurse to verify each sub-match.
1242 : : * We always have k <= max_matches, needn't check that.
1243 : : */
1244 [ - + ]: 87 : if (k < min_matches)
5209 tgl@sss.pgh.pa.us 1245 :UBC 0 : goto backtrack;
1246 : :
1247 : : MDEBUG(("%d: verifying %d..%d\n", t->id, nverified + 1, k));
1248 : :
5209 tgl@sss.pgh.pa.us 1249 [ + + ]:CBC 140 : for (i = nverified + 1; i <= k; i++)
1250 : : {
1251 : : /* zap any match data from a non-last iteration */
1925 1252 : 113 : zaptreesubs(v, t->child);
1253 : 113 : er = cdissect(v, t->child, endpts[i - 1], endpts[i]);
5209 1254 [ + + ]: 113 : if (er == REG_OKAY)
1255 : : {
1256 : 53 : nverified = i;
1257 : 53 : continue;
1258 : : }
1259 [ + - ]: 60 : if (er == REG_NOMATCH)
1260 : 60 : break;
1261 : : /* oops, something failed */
5209 tgl@sss.pgh.pa.us 1262 :UBC 0 : FREE(endpts);
1263 : 0 : return er;
1264 : : }
1265 : :
5209 tgl@sss.pgh.pa.us 1266 [ + + ]:CBC 87 : if (i > k)
1267 : : {
1268 : : /* satisfaction */
1269 : : MDEBUG(("%d: successful\n", t->id));
1270 : 27 : FREE(endpts);
1271 : 27 : return REG_OKAY;
1272 : : }
1273 : :
1274 : : /* i'th match failed to verify, so backtrack it */
1744 1275 : 60 : k = i;
1276 : :
5209 1277 : 366 : backtrack:
1278 : :
1279 : : /*
1280 : : * Must consider shorter versions of the k'th sub-match. However,
1281 : : * we'll only ask for a zero-length match if necessary.
1282 : : */
1283 [ + + ]: 366 : while (k > 0)
1284 : : {
5102 bruce@momjian.us 1285 : 234 : chr *prev_end = endpts[k - 1];
1286 : :
5209 tgl@sss.pgh.pa.us 1287 [ + - ]: 234 : if (endpts[k] > prev_end)
1288 : : {
1289 : 234 : limit = endpts[k] - 1;
1290 [ - + - - ]: 234 : if (limit > prev_end ||
5209 tgl@sss.pgh.pa.us 1291 [ # # ]:UBC 0 : (k < min_matches && min_matches - k >= end - prev_end))
1292 : : {
1293 : : /* break out of backtrack loop, continue the outer one */
1294 : : break;
1295 : : }
1296 : : }
1297 : : /* can't shorten k'th sub-match any more, consider previous one */
1298 : 0 : k--;
1299 : : }
1300 : : }
1301 : :
1302 : : /* all possibilities exhausted */
5209 tgl@sss.pgh.pa.us 1303 :CBC 132 : FREE(endpts);
1304 : :
1305 : : /*
1306 : : * Now consider the possibility that we can match to a zero-length string
1307 : : * by using zero repetitions.
1308 : : */
3893 1309 [ + + + - ]: 132 : if (t->min == 0 && begin == end)
1310 : : {
1311 : : MDEBUG(("%d: allowing zero matches\n", t->id));
1312 : 90 : return REG_OKAY;
1313 : : }
1314 : :
1315 : : MDEBUG(("%d: failed\n", t->id));
5209 1316 : 42 : return REG_NOMATCH;
1317 : : }
1318 : :
1319 : : /*
1320 : : * creviterdissect - dissect match for iteration node, shortest-first
1321 : : */
1322 : : static int /* regexec return code */
3265 1323 : 8 : creviterdissect(struct vars *v,
1324 : : struct subre *t,
1325 : : chr *begin, /* beginning of relevant substring */
1326 : : chr *end) /* end of same */
1327 : : {
1328 : : struct dfa *d;
1329 : : chr **endpts;
1330 : : chr *limit;
1331 : : int min_matches;
1332 : : size_t max_matches;
1333 : : int nverified;
1334 : : int k;
1335 : : int i;
1336 : : int er;
1337 : :
5209 1338 [ - + ]: 8 : assert(t->op == '*');
1925 1339 [ + - - + ]: 8 : assert(t->child != NULL && t->child->cnfa.nstates > 0);
1340 [ - + ]: 8 : assert(t->child->flags & SHORTER);
5209 1341 [ - + ]: 8 : assert(begin <= end);
1342 : :
1343 : : MDEBUG(("%d: creviterdissect %ld-%ld\n", t->id, LOFF(begin), LOFF(end)));
1344 : :
1345 : : /*
1346 : : * If zero matches are allowed, and target string is empty, just declare
1347 : : * victory. OTOH, if target string isn't empty, zero matches can't work
1348 : : * so we pretend the min is 1.
1349 : : */
1350 : 8 : min_matches = t->min;
1351 [ + - ]: 8 : if (min_matches <= 0)
1352 : : {
1353 [ + + ]: 8 : if (begin == end)
1354 : : {
1355 : : MDEBUG(("%d: allowing zero matches\n", t->id));
1356 : 1 : return REG_OKAY;
1357 : : }
1358 : 7 : min_matches = 1;
1359 : : }
1360 : :
1361 : : /*
1362 : : * We need workspace to track the endpoints of each sub-match. Normally
1363 : : * we consider only nonzero-length sub-matches, so there can be at most
1364 : : * end-begin of them. However, if min is larger than that, we will also
1365 : : * consider zero-length sub-matches in order to find enough matches.
1366 : : *
1367 : : * For convenience, endpts[0] contains the "begin" pointer and we store
1368 : : * sub-match endpoints in endpts[1..max_matches].
1369 : : */
1370 : 7 : max_matches = end - begin;
3909 1371 [ + - + - ]: 7 : if (max_matches > t->max && t->max != DUPINF)
5209 1372 : 7 : max_matches = t->max;
1373 [ - + ]: 7 : if (max_matches < min_matches)
5209 tgl@sss.pgh.pa.us 1374 :UBC 0 : max_matches = min_matches;
19 tgl@sss.pgh.pa.us 1375 :CBC 7 : endpts = MALLOC_ARRAY(chr *, max_matches + 1);
5209 1376 [ - + ]: 7 : if (endpts == NULL)
5209 tgl@sss.pgh.pa.us 1377 :UBC 0 : return REG_ESPACE;
5209 tgl@sss.pgh.pa.us 1378 :CBC 7 : endpts[0] = begin;
1379 : :
1925 1380 : 7 : d = getsubdfa(v, t->child);
5209 1381 [ - + ]: 7 : if (ISERR())
1382 : : {
5209 tgl@sss.pgh.pa.us 1383 :UBC 0 : FREE(endpts);
1384 : 0 : return v->err;
1385 : : }
1386 : :
1387 : : /*
1388 : : * Our strategy is to first find a set of sub-match endpoints that are
1389 : : * valid according to the child node's DFA, and then recursively dissect
1390 : : * each sub-match to confirm validity. If any validity check fails,
1391 : : * backtrack that sub-match and try again. And, when we next try for a
1392 : : * validity check, we need not recheck any successfully verified
1393 : : * sub-matches that we didn't move the endpoints of. nverified remembers
1394 : : * how many sub-matches are currently known okay.
1395 : : */
1396 : :
1397 : : /* initialize to consider first sub-match */
5209 tgl@sss.pgh.pa.us 1398 :CBC 7 : nverified = 0;
1399 : 7 : k = 1;
1400 : 7 : limit = begin;
1401 : :
1402 : : /* iterate until satisfaction or failure */
1403 [ + + ]: 9 : while (k > 0)
1404 : : {
1405 : : /* disallow zero-length match unless necessary to achieve min */
1406 [ + - + - ]: 7 : if (limit == endpts[k - 1] &&
1407 [ - + ]: 7 : limit != end &&
5209 tgl@sss.pgh.pa.us 1408 [ # # ]:UBC 0 : (k >= min_matches || min_matches - k < end - limit))
5209 tgl@sss.pgh.pa.us 1409 :CBC 7 : limit++;
1410 : :
1411 : : /* if this is the last allowed sub-match, it must reach to the end */
4267 1412 [ + - ]: 7 : if (k >= max_matches)
1413 : 7 : limit = end;
1414 : :
1415 : : /* try to find an endpoint for the k'th sub-match */
5209 1416 : 7 : endpts[k] = shortest(v, d, endpts[k - 1], limit, end,
1417 : : (chr **) NULL, (int *) NULL);
3893 1418 [ - + ]: 7 : if (ISERR())
1419 : : {
3893 tgl@sss.pgh.pa.us 1420 :UBC 0 : FREE(endpts);
1421 : 0 : return v->err;
1422 : : }
5209 tgl@sss.pgh.pa.us 1423 [ - + ]:CBC 7 : if (endpts[k] == NULL)
1424 : : {
1425 : : /* no match possible, so see if we can lengthen previous one */
5209 tgl@sss.pgh.pa.us 1426 :UBC 0 : k--;
1427 : 0 : goto backtrack;
1428 : : }
1429 : : MDEBUG(("%d: working endpoint %d: %ld\n",
1430 : : t->id, k, LOFF(endpts[k])));
1431 : :
1432 : : /* k'th sub-match can no longer be considered verified */
5209 tgl@sss.pgh.pa.us 1433 [ - + ]:CBC 7 : if (nverified >= k)
5209 tgl@sss.pgh.pa.us 1434 :UBC 0 : nverified = k - 1;
1435 : :
5209 tgl@sss.pgh.pa.us 1436 [ - + ]:CBC 7 : if (endpts[k] != end)
1437 : : {
1438 : : /* haven't reached end yet, try another iteration if allowed */
5209 tgl@sss.pgh.pa.us 1439 [ # # ]:UBC 0 : if (k >= max_matches)
1440 : : {
1441 : : /* must try to lengthen some previous match */
1442 : 0 : k--;
1443 : 0 : goto backtrack;
1444 : : }
1445 : :
1446 : 0 : k++;
1447 : 0 : limit = endpts[k - 1];
1448 : 0 : continue;
1449 : : }
1450 : :
1451 : : /*
1452 : : * We've identified a way to divide the string into k sub-matches that
1453 : : * works so far as the child DFA can tell. If k is an allowed number
1454 : : * of matches, start the slow part: recurse to verify each sub-match.
1455 : : * We always have k <= max_matches, needn't check that.
1456 : : */
5209 tgl@sss.pgh.pa.us 1457 [ - + ]:CBC 7 : if (k < min_matches)
5209 tgl@sss.pgh.pa.us 1458 :UBC 0 : goto backtrack;
1459 : :
1460 : : MDEBUG(("%d: verifying %d..%d\n", t->id, nverified + 1, k));
1461 : :
5209 tgl@sss.pgh.pa.us 1462 [ + + ]:CBC 12 : for (i = nverified + 1; i <= k; i++)
1463 : : {
1464 : : /* zap any match data from a non-last iteration */
1925 1465 : 7 : zaptreesubs(v, t->child);
1466 : 7 : er = cdissect(v, t->child, endpts[i - 1], endpts[i]);
5209 1467 [ + + ]: 7 : if (er == REG_OKAY)
1468 : : {
1469 : 5 : nverified = i;
1470 : 5 : continue;
1471 : : }
1472 [ + - ]: 2 : if (er == REG_NOMATCH)
1473 : 2 : break;
1474 : : /* oops, something failed */
5209 tgl@sss.pgh.pa.us 1475 :UBC 0 : FREE(endpts);
1476 : 0 : return er;
1477 : : }
1478 : :
5209 tgl@sss.pgh.pa.us 1479 [ + + ]:CBC 7 : if (i > k)
1480 : : {
1481 : : /* satisfaction */
1482 : : MDEBUG(("%d: successful\n", t->id));
1483 : 5 : FREE(endpts);
1484 : 5 : return REG_OKAY;
1485 : : }
1486 : :
1487 : : /* i'th match failed to verify, so backtrack it */
1744 1488 : 2 : k = i;
1489 : :
5209 1490 : 2 : backtrack:
1491 : :
1492 : : /*
1493 : : * Must consider longer versions of the k'th sub-match.
1494 : : */
1495 [ + + ]: 4 : while (k > 0)
1496 : : {
1497 [ - + ]: 2 : if (endpts[k] < end)
1498 : : {
5209 tgl@sss.pgh.pa.us 1499 :UBC 0 : limit = endpts[k] + 1;
1500 : : /* break out of backtrack loop, continue the outer one */
1501 : 0 : break;
1502 : : }
1503 : : /* can't lengthen k'th sub-match any more, consider previous one */
5209 tgl@sss.pgh.pa.us 1504 :CBC 2 : k--;
1505 : : }
1506 : : }
1507 : :
1508 : : /* all possibilities exhausted */
1509 : : MDEBUG(("%d: failed\n", t->id));
1510 : 2 : FREE(endpts);
1511 : 2 : return REG_NOMATCH;
1512 : : }
1513 : :
1514 : :
1515 : :
1516 : : #include "rege_dfa.c"
|