]> git.saurik.com Git - wxWidgets.git/blame - src/regex/regexec.c
reduce black background flicker a bit - there is still some left sometimes initially...
[wxWidgets.git] / src / regex / regexec.c
CommitLineData
34275176 1/*
c0a7edde 2 * re_*exec and friends - match REs
34275176 3 *
3ca4086b
VS
4 * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
5 *
c0a7edde
RN
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
3ca4086b
VS
9 * thanks all of them.
10 *
c0a7edde
RN
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.
3ca4086b 15 *
c0a7edde
RN
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.
3ca4086b 18 *
c0a7edde
RN
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 *
c0a7edde
RN
30 */
31
32#include "regguts.h"
33
34
35
36/* lazy-DFA representation */
3ca4086b 37struct arcp { /* "pointer" to an outarc */
c0a7edde 38 struct sset *ss;
3ca4086b 39 color co;
c0a7edde
RN
40};
41
3ca4086b
VS
42struct sset { /* state set */
43 unsigned *states; /* pointer to bitvector */
44 unsigned hash; /* hash of bitvector */
45# define HASH(bv, nw) (((nw) == 1) ? *(bv) : hash(bv, nw))
46# define HIT(h,bv,ss,nw) ((ss)->hash == (h) && ((nw) == 1 || \
c0a7edde 47 memcmp(VS(bv), VS((ss)->states), (nw)*sizeof(unsigned)) == 0))
3ca4086b
VS
48 int flags;
49# define STARTER 01 /* the initial state set */
50# define POSTSTATE 02 /* includes the goal state */
51# define LOCKED 04 /* locked in cache */
52# define NOPROGRESS 010 /* zero-progress state set */
53 struct arcp ins; /* chain of inarcs pointing here */
54 chr *lastseen; /* last entered on arrival here */
55 struct sset **outs; /* outarc vector indexed by color */
56 struct arcp *inchain; /* chain-pointer vector for outarcs */
c0a7edde
RN
57};
58
3ca4086b
VS
59struct dfa {
60 int nssets; /* size of cache */
61 int nssused; /* how many entries occupied yet */
62 int nstates; /* number of states */
63 int ncolors; /* length of outarc and inchain vectors */
64 int wordsper; /* length of state-set bitvectors */
65 struct sset *ssets; /* state-set cache */
66 unsigned *statesarea; /* bitvector storage */
67 unsigned *work; /* pointer to work area within statesarea */
68 struct sset **outsarea; /* outarc-vector storage */
69 struct arcp *incarea; /* inchain storage */
c0a7edde
RN
70 struct cnfa *cnfa;
71 struct colormap *cm;
3ca4086b
VS
72 chr *lastpost; /* location of last cache-flushed success */
73 chr *lastnopr; /* location of last cache-flushed NOPROGRESS */
74 struct sset *search; /* replacement-search-pointer memory */
75 int cptsmalloced; /* were the areas individually malloced? */
76 char *mallocarea; /* self, or master malloced area, or NULL */
c0a7edde
RN
77};
78
3ca4086b 79#define WORK 1 /* number of work bitvectors needed */
c0a7edde
RN
80
81/* setup for non-malloc allocation for small cases */
3ca4086b
VS
82#define FEWSTATES 20 /* must be less than UBITS */
83#define FEWCOLORS 15
84struct smalldfa {
85 struct dfa dfa;
86 struct sset ssets[FEWSTATES*2];
87 unsigned statesarea[FEWSTATES*2 + WORK];
88 struct sset *outsarea[FEWSTATES*2 * FEWCOLORS];
89 struct arcp incarea[FEWSTATES*2 * FEWCOLORS];
c0a7edde 90};
3ca4086b 91#define DOMALLOC ((struct smalldfa *)NULL) /* force malloc */
c0a7edde
RN
92
93
94
95/* internal variables, bundled for easy passing around */
3ca4086b
VS
96struct vars {
97 regex_t *re;
c0a7edde 98 struct guts *g;
3ca4086b
VS
99 int eflags; /* copies of arguments */
100 size_t nmatch;
c0a7edde
RN
101 regmatch_t *pmatch;
102 rm_detail_t *details;
3ca4086b
VS
103 chr *start; /* start of string */
104 chr *stop; /* just past end of string */
105 int err; /* error code if any (0 none) */
106 regoff_t *mem; /* memory vector for backtracking */
c0a7edde
RN
107 struct smalldfa dfa1;
108 struct smalldfa dfa2;
109};
3ca4086b
VS
110#define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */
111#define ISERR() VISERR(v)
112#define VERR(vv,e) (((vv)->err) ? (vv)->err : ((vv)->err = (e)))
113#define ERR(e) VERR(v, e) /* record an error */
114#define NOERR() {if (ISERR()) return v->err;} /* if error seen, return it */
115#define OFF(p) ((p) - v->start)
116#define LOFF(p) ((long)OFF(p))
c0a7edde
RN
117
118
119
120/*
121 * forward declarations
122 */
3ca4086b
VS
123/* =====^!^===== begin forwards =====^!^===== */
124/* automatically gathered by fwd; do not hand-edit */
c0a7edde 125/* === regexec.c === */
3ca4086b
VS
126int exec _ANSI_ARGS_((regex_t *, CONST chr *, size_t, rm_detail_t *, size_t, regmatch_t [], int));
127static int find _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *));
128static int cfind _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *));
129static int cfindloop _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *, struct dfa *, struct dfa *, chr **));
130static VOID zapsubs _ANSI_ARGS_((regmatch_t *, size_t));
131static VOID zapmem _ANSI_ARGS_((struct vars *, struct subre *));
132static VOID subset _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
133static int dissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
134static int condissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
135static int altdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
136static int cdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
137static int ccondissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
138static int crevdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
139static int cbrdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
140static int caltdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *));
c0a7edde 141/* === rege_dfa.c === */
3ca4086b
VS
142static chr *longest _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *, int *));
143static chr *shortest _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *, chr *, chr **, int *));
144static chr *lastcold _ANSI_ARGS_((struct vars *, struct dfa *));
145static struct dfa *newdfa _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *, struct smalldfa *));
146static VOID freedfa _ANSI_ARGS_((struct dfa *));
147static unsigned hash _ANSI_ARGS_((unsigned *, int));
148static struct sset *initialize _ANSI_ARGS_((struct vars *, struct dfa *, chr *));
149static struct sset *miss _ANSI_ARGS_((struct vars *, struct dfa *, struct sset *, pcolor, chr *, chr *));
150static int lacon _ANSI_ARGS_((struct vars *, struct cnfa *, chr *, pcolor));
151static struct sset *getvacant _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *));
152static struct sset *pickss _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *));
153/* automatically gathered by fwd; do not hand-edit */
154/* =====^!^===== end forwards =====^!^===== */
155
c0a7edde
RN
156
157
158/*
3ca4086b
VS
159 - exec - match regular expression
160 ^ int exec(regex_t *, CONST chr *, size_t, rm_detail_t *,
161 ^ size_t, regmatch_t [], int);
c0a7edde
RN
162 */
163int
3ca4086b
VS
164exec(re, string, len, details, nmatch, pmatch, flags)
165regex_t *re;
166CONST chr *string;
167size_t len;
168rm_detail_t *details;
169size_t nmatch;
170regmatch_t pmatch[];
171int flags;
c0a7edde
RN
172{
173 struct vars var;
174 register struct vars *v = &var;
3ca4086b
VS
175 int st;
176 size_t n;
177 int backref;
178# define LOCALMAT 20
179 regmatch_t mat[LOCALMAT];
180# define LOCALMEM 40
181 regoff_t mem[LOCALMEM];
c0a7edde
RN
182
183 /* sanity checks */
184 if (re == NULL || string == NULL || re->re_magic != REMAGIC)
185 return REG_INVARG;
186 if (re->re_csize != sizeof(chr))
187 return REG_MIXED;
188
189 /* setup */
190 v->re = re;
3ca4086b
VS
191 v->g = (struct guts *)re->re_guts;
192 if ((v->g->cflags&REG_EXPECT) && details == NULL)
c0a7edde 193 return REG_INVARG;
3ca4086b 194 if (v->g->info&REG_UIMPOSSIBLE)
c0a7edde 195 return REG_NOMATCH;
3ca4086b 196 backref = (v->g->info&REG_UBACKREF) ? 1 : 0;
c0a7edde 197 v->eflags = flags;
3ca4086b
VS
198 if (v->g->cflags&REG_NOSUB)
199 nmatch = 0; /* override client */
c0a7edde 200 v->nmatch = nmatch;
3ca4086b 201 if (backref) {
c0a7edde
RN
202 /* need work area */
203 if (v->g->nsub + 1 <= LOCALMAT)
204 v->pmatch = mat;
205 else
3ca4086b
VS
206 v->pmatch = (regmatch_t *)MALLOC((v->g->nsub + 1) *
207 sizeof(regmatch_t));
c0a7edde
RN
208 if (v->pmatch == NULL)
209 return REG_ESPACE;
210 v->nmatch = v->g->nsub + 1;
3ca4086b 211 } else
c0a7edde
RN
212 v->pmatch = pmatch;
213 v->details = details;
3ca4086b
VS
214 v->start = (chr *)string;
215 v->stop = (chr *)string + len;
c0a7edde 216 v->err = 0;
3ca4086b 217 if (backref) {
c0a7edde
RN
218 /* need retry memory */
219 assert(v->g->ntree >= 0);
3ca4086b 220 n = (size_t)v->g->ntree;
c0a7edde
RN
221 if (n <= LOCALMEM)
222 v->mem = mem;
223 else
3ca4086b
VS
224 v->mem = (regoff_t *)MALLOC(n*sizeof(regoff_t));
225 if (v->mem == NULL) {
c0a7edde
RN
226 if (v->pmatch != pmatch && v->pmatch != mat)
227 FREE(v->pmatch);
228 return REG_ESPACE;
229 }
3ca4086b 230 } else
c0a7edde
RN
231 v->mem = NULL;
232
233 /* do it */
234 assert(v->g->tree != NULL);
235 if (backref)
236 st = cfind(v, &v->g->tree->cnfa, &v->g->cmap);
237 else
238 st = find(v, &v->g->tree->cnfa, &v->g->cmap);
239
240 /* copy (portion of) match vector over if necessary */
3ca4086b 241 if (st == REG_OKAY && v->pmatch != pmatch && nmatch > 0) {
c0a7edde
RN
242 zapsubs(pmatch, nmatch);
243 n = (nmatch < v->nmatch) ? nmatch : v->nmatch;
3ca4086b 244 memcpy(VS(pmatch), VS(v->pmatch), n*sizeof(regmatch_t));
c0a7edde
RN
245 }
246
247 /* clean up */
248 if (v->pmatch != pmatch && v->pmatch != mat)
249 FREE(v->pmatch);
250 if (v->mem != NULL && v->mem != mem)
251 FREE(v->mem);
252 return st;
253}
254
255/*
3ca4086b
VS
256 - find - find a match for the main NFA (no-complications case)
257 ^ static int find(struct vars *, struct cnfa *, struct colormap *);
c0a7edde
RN
258 */
259static int
3ca4086b
VS
260find(v, cnfa, cm)
261struct vars *v;
262struct cnfa *cnfa;
263struct colormap *cm;
c0a7edde
RN
264{
265 struct dfa *s;
266 struct dfa *d;
3ca4086b
VS
267 chr *begin;
268 chr *end = NULL;
269 chr *cold;
270 chr *open; /* open and close of range of possible starts */
271 chr *close;
272 int hitend;
273 int shorter = (v->g->tree->flags&SHORTER) ? 1 : 0;
c0a7edde
RN
274
275 /* first, a shot with the search RE */
276 s = newdfa(v, &v->g->search, cm, &v->dfa1);
277 assert(!(ISERR() && s != NULL));
278 NOERR();
279 MDEBUG(("\nsearch at %ld\n", LOFF(v->start)));
280 cold = NULL;
3ca4086b 281 close = shortest(v, s, v->start, v->start, v->stop, &cold, (int *)NULL);
c0a7edde
RN
282 freedfa(s);
283 NOERR();
3ca4086b 284 if (v->g->cflags&REG_EXPECT) {
c0a7edde
RN
285 assert(v->details != NULL);
286 if (cold != NULL)
287 v->details->rm_extend.rm_so = OFF(cold);
288 else
289 v->details->rm_extend.rm_so = OFF(v->stop);
3ca4086b 290 v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
c0a7edde 291 }
3ca4086b 292 if (close == NULL) /* not found */
c0a7edde 293 return REG_NOMATCH;
3ca4086b 294 if (v->nmatch == 0) /* found, don't need exact location */
c0a7edde
RN
295 return REG_OKAY;
296
297 /* find starting point and match */
298 assert(cold != NULL);
299 open = cold;
300 cold = NULL;
301 MDEBUG(("between %ld and %ld\n", LOFF(open), LOFF(close)));
302 d = newdfa(v, cnfa, cm, &v->dfa1);
303 assert(!(ISERR() && d != NULL));
304 NOERR();
3ca4086b 305 for (begin = open; begin <= close; begin++) {
c0a7edde
RN
306 MDEBUG(("\nfind trying at %ld\n", LOFF(begin)));
307 if (shorter)
308 end = shortest(v, d, begin, begin, v->stop,
3ca4086b 309 (chr **)NULL, &hitend);
c0a7edde
RN
310 else
311 end = longest(v, d, begin, v->stop, &hitend);
312 NOERR();
313 if (hitend && cold == NULL)
314 cold = begin;
315 if (end != NULL)
3ca4086b 316 break; /* NOTE BREAK OUT */
c0a7edde
RN
317 }
318 assert(end != NULL); /* search RE succeeded so loop should */
319 freedfa(d);
320
321 /* and pin down details */
322 assert(v->nmatch > 0);
323 v->pmatch[0].rm_so = OFF(begin);
324 v->pmatch[0].rm_eo = OFF(end);
3ca4086b 325 if (v->g->cflags&REG_EXPECT) {
c0a7edde
RN
326 if (cold != NULL)
327 v->details->rm_extend.rm_so = OFF(cold);
328 else
329 v->details->rm_extend.rm_so = OFF(v->stop);
3ca4086b 330 v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
c0a7edde 331 }
3ca4086b 332 if (v->nmatch == 1) /* no need for submatches */
c0a7edde
RN
333 return REG_OKAY;
334
335 /* submatches */
336 zapsubs(v->pmatch, v->nmatch);
337 return dissect(v, v->g->tree, begin, end);
338}
339
340/*
3ca4086b
VS
341 - cfind - find a match for the main NFA (with complications)
342 ^ static int cfind(struct vars *, struct cnfa *, struct colormap *);
c0a7edde
RN
343 */
344static int
3ca4086b
VS
345cfind(v, cnfa, cm)
346struct vars *v;
347struct cnfa *cnfa;
348struct colormap *cm;
c0a7edde
RN
349{
350 struct dfa *s;
351 struct dfa *d;
3ca4086b
VS
352 chr *cold;
353 int ret;
c0a7edde
RN
354
355 s = newdfa(v, &v->g->search, cm, &v->dfa1);
356 NOERR();
357 d = newdfa(v, cnfa, cm, &v->dfa2);
3ca4086b 358 if (ISERR()) {
c0a7edde
RN
359 assert(d == NULL);
360 freedfa(s);
361 return v->err;
362 }
363
364 ret = cfindloop(v, cnfa, cm, d, s, &cold);
365
366 freedfa(d);
367 freedfa(s);
368 NOERR();
3ca4086b 369 if (v->g->cflags&REG_EXPECT) {
c0a7edde
RN
370 assert(v->details != NULL);
371 if (cold != NULL)
372 v->details->rm_extend.rm_so = OFF(cold);
373 else
374 v->details->rm_extend.rm_so = OFF(v->stop);
3ca4086b 375 v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */
c0a7edde
RN
376 }
377 return ret;
378}
379
380/*
3ca4086b
VS
381 - cfindloop - the heart of cfind
382 ^ static int cfindloop(struct vars *, struct cnfa *, struct colormap *,
383 ^ struct dfa *, struct dfa *, chr **);
c0a7edde
RN
384 */
385static int
3ca4086b
VS
386cfindloop(v, cnfa, cm, d, s, coldp)
387struct vars *v;
388struct cnfa *cnfa;
389struct colormap *cm;
390struct dfa *d;
391struct dfa *s;
392chr **coldp; /* where to put coldstart pointer */
c0a7edde 393{
3ca4086b
VS
394 chr *begin;
395 chr *end;
396 chr *cold;
397 chr *open; /* open and close of range of possible starts */
398 chr *close;
399 chr *estart;
400 chr *estop;
401 int er;
402 int shorter = v->g->tree->flags&SHORTER;
403 int hitend;
c0a7edde
RN
404
405 assert(d != NULL && s != NULL);
406 cold = NULL;
407 close = v->start;
3ca4086b 408 do {
c0a7edde 409 MDEBUG(("\ncsearch at %ld\n", LOFF(close)));
3ca4086b 410 close = shortest(v, s, close, close, v->stop, &cold, (int *)NULL);
c0a7edde
RN
411 if (close == NULL)
412 break; /* NOTE BREAK */
413 assert(cold != NULL);
414 open = cold;
415 cold = NULL;
416 MDEBUG(("cbetween %ld and %ld\n", LOFF(open), LOFF(close)));
3ca4086b 417 for (begin = open; begin <= close; begin++) {
c0a7edde
RN
418 MDEBUG(("\ncfind trying at %ld\n", LOFF(begin)));
419 estart = begin;
420 estop = v->stop;
3ca4086b 421 for (;;) {
c0a7edde
RN
422 if (shorter)
423 end = shortest(v, d, begin, estart,
3ca4086b 424 estop, (chr **)NULL, &hitend);
c0a7edde
RN
425 else
426 end = longest(v, d, begin, estop,
3ca4086b 427 &hitend);
c0a7edde
RN
428 if (hitend && cold == NULL)
429 cold = begin;
430 if (end == NULL)
431 break; /* NOTE BREAK OUT */
432 MDEBUG(("tentative end %ld\n", LOFF(end)));
433 zapsubs(v->pmatch, v->nmatch);
434 zapmem(v, v->g->tree);
435 er = cdissect(v, v->g->tree, begin, end);
3ca4086b
VS
436 if (er == REG_OKAY) {
437 if (v->nmatch > 0) {
c0a7edde
RN
438 v->pmatch[0].rm_so = OFF(begin);
439 v->pmatch[0].rm_eo = OFF(end);
440 }
441 *coldp = cold;
442 return REG_OKAY;
443 }
3ca4086b 444 if (er != REG_NOMATCH) {
c0a7edde
RN
445 ERR(er);
446 return er;
447 }
3ca4086b 448 if ((shorter) ? end == estop : end == begin) {
c0a7edde
RN
449 /* no point in trying again */
450 *coldp = cold;
451 return REG_NOMATCH;
452 }
453 /* go around and try again */
454 if (shorter)
455 estart = end + 1;
456 else
457 estop = end - 1;
458 }
459 }
460 } while (close < v->stop);
461
462 *coldp = cold;
463 return REG_NOMATCH;
464}
465
466/*
3ca4086b
VS
467 - zapsubs - initialize the subexpression matches to "no match"
468 ^ static VOID zapsubs(regmatch_t *, size_t);
c0a7edde 469 */
3ca4086b
VS
470static VOID
471zapsubs(p, n)
472regmatch_t *p;
473size_t n;
c0a7edde 474{
3ca4086b 475 size_t i;
c0a7edde 476
3ca4086b 477 for (i = n-1; i > 0; i--) {
c0a7edde
RN
478 p[i].rm_so = -1;
479 p[i].rm_eo = -1;
480 }
481}
482
483/*
3ca4086b
VS
484 - zapmem - initialize the retry memory of a subtree to zeros
485 ^ static VOID zapmem(struct vars *, struct subre *);
c0a7edde 486 */
3ca4086b
VS
487static VOID
488zapmem(v, t)
489struct vars *v;
490struct subre *t;
c0a7edde
RN
491{
492 if (t == NULL)
493 return;
494
495 assert(v->mem != NULL);
496 v->mem[t->retry] = 0;
3ca4086b 497 if (t->op == '(') {
c0a7edde
RN
498 assert(t->subno > 0);
499 v->pmatch[t->subno].rm_so = -1;
500 v->pmatch[t->subno].rm_eo = -1;
501 }
502
503 if (t->left != NULL)
504 zapmem(v, t->left);
505 if (t->right != NULL)
506 zapmem(v, t->right);
507}
508
509/*
3ca4086b
VS
510 - subset - set any subexpression relevant to a successful subre
511 ^ static VOID subset(struct vars *, struct subre *, chr *, chr *);
c0a7edde 512 */
3ca4086b
VS
513static VOID
514subset(v, sub, begin, end)
515struct vars *v;
516struct subre *sub;
517chr *begin;
518chr *end;
c0a7edde 519{
3ca4086b 520 int n = sub->subno;
c0a7edde
RN
521
522 assert(n > 0);
3ca4086b 523 if ((size_t)n >= v->nmatch)
c0a7edde
RN
524 return;
525
526 MDEBUG(("setting %d\n", n));
527 v->pmatch[n].rm_so = OFF(begin);
528 v->pmatch[n].rm_eo = OFF(end);
529}
530
531/*
3ca4086b
VS
532 - dissect - determine subexpression matches (uncomplicated case)
533 ^ static int dissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 534 */
3ca4086b
VS
535static int /* regexec return code */
536dissect(v, t, begin, end)
537struct vars *v;
538struct subre *t;
539chr *begin; /* beginning of relevant substring */
540chr *end; /* end of same */
c0a7edde
RN
541{
542 assert(t != NULL);
543 MDEBUG(("dissect %ld-%ld\n", LOFF(begin), LOFF(end)));
544
3ca4086b
VS
545 switch (t->op) {
546 case '=': /* terminal node */
547 assert(t->left == NULL && t->right == NULL);
548 return REG_OKAY; /* no action, parent did the work */
549 break;
550 case '|': /* alternation */
551 assert(t->left != NULL);
552 return altdissect(v, t, begin, end);
553 break;
554 case 'b': /* back ref -- shouldn't be calling us! */
555 return REG_ASSERT;
556 break;
557 case '.': /* concatenation */
558 assert(t->left != NULL && t->right != NULL);
559 return condissect(v, t, begin, end);
560 break;
561 case '(': /* capturing */
562 assert(t->left != NULL && t->right == NULL);
563 assert(t->subno > 0);
564 subset(v, t, begin, end);
565 return dissect(v, t->left, begin, end);
566 break;
567 default:
568 return REG_ASSERT;
569 break;
c0a7edde
RN
570 }
571}
572
573/*
3ca4086b
VS
574 - condissect - determine concatenation subexpression matches (uncomplicated)
575 ^ static int condissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 576 */
3ca4086b
VS
577static int /* regexec return code */
578condissect(v, t, begin, end)
579struct vars *v;
580struct subre *t;
581chr *begin; /* beginning of relevant substring */
582chr *end; /* end of same */
c0a7edde
RN
583{
584 struct dfa *d;
585 struct dfa *d2;
3ca4086b
VS
586 chr *mid;
587 int i;
588 int shorter = (t->left->flags&SHORTER) ? 1 : 0;
589 chr *stop = (shorter) ? end : begin;
c0a7edde
RN
590
591 assert(t->op == '.');
592 assert(t->left != NULL && t->left->cnfa.nstates > 0);
593 assert(t->right != NULL && t->right->cnfa.nstates > 0);
594
595 d = newdfa(v, &t->left->cnfa, &v->g->cmap, &v->dfa1);
596 NOERR();
597 d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, &v->dfa2);
3ca4086b 598 if (ISERR()) {
c0a7edde
RN
599 assert(d2 == NULL);
600 freedfa(d);
601 return v->err;
602 }
603
604 /* pick a tentative midpoint */
605 if (shorter)
3ca4086b
VS
606 mid = shortest(v, d, begin, begin, end, (chr **)NULL,
607 (int *)NULL);
34275176 608 else
3ca4086b
VS
609 mid = longest(v, d, begin, end, (int *)NULL);
610 if (mid == NULL) {
c0a7edde
RN
611 freedfa(d);
612 freedfa(d2);
613 return REG_ASSERT;
614 }
615 MDEBUG(("tentative midpoint %ld\n", LOFF(mid)));
616
617 /* iterate until satisfaction or failure */
3ca4086b 618 while (longest(v, d2, mid, end, (int *)NULL) != end) {
c0a7edde 619 /* that midpoint didn't work, find a new one */
3ca4086b 620 if (mid == stop) {
c0a7edde
RN
621 /* all possibilities exhausted! */
622 MDEBUG(("no midpoint!\n"));
623 freedfa(d);
624 freedfa(d2);
625 return REG_ASSERT;
626 }
627 if (shorter)
3ca4086b
VS
628 mid = shortest(v, d, begin, mid+1, end, (chr **)NULL,
629 (int *)NULL);
c0a7edde 630 else
3ca4086b
VS
631 mid = longest(v, d, begin, mid-1, (int *)NULL);
632 if (mid == NULL) {
c0a7edde
RN
633 /* failed to find a new one! */
634 MDEBUG(("failed midpoint!\n"));
635 freedfa(d);
636 freedfa(d2);
637 return REG_ASSERT;
638 }
639 MDEBUG(("new midpoint %ld\n", LOFF(mid)));
640 }
641
642 /* satisfaction */
643 MDEBUG(("successful\n"));
644 freedfa(d);
645 freedfa(d2);
646 i = dissect(v, t->left, begin, mid);
647 if (i != REG_OKAY)
648 return i;
649 return dissect(v, t->right, mid, end);
650}
651
652/*
3ca4086b
VS
653 - altdissect - determine alternative subexpression matches (uncomplicated)
654 ^ static int altdissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 655 */
3ca4086b
VS
656static int /* regexec return code */
657altdissect(v, t, begin, end)
658struct vars *v;
659struct subre *t;
660chr *begin; /* beginning of relevant substring */
661chr *end; /* end of same */
c0a7edde
RN
662{
663 struct dfa *d;
3ca4086b 664 int i;
c0a7edde
RN
665
666 assert(t != NULL);
667 assert(t->op == '|');
668
3ca4086b 669 for (i = 0; t != NULL; t = t->right, i++) {
c0a7edde
RN
670 MDEBUG(("trying %dth\n", i));
671 assert(t->left != NULL && t->left->cnfa.nstates > 0);
672 d = newdfa(v, &t->left->cnfa, &v->g->cmap, &v->dfa1);
673 if (ISERR())
674 return v->err;
3ca4086b 675 if (longest(v, d, begin, end, (int *)NULL) == end) {
c0a7edde
RN
676 MDEBUG(("success\n"));
677 freedfa(d);
678 return dissect(v, t->left, begin, end);
679 }
680 freedfa(d);
681 }
3ca4086b 682 return REG_ASSERT; /* none of them matched?!? */
c0a7edde
RN
683}
684
685/*
3ca4086b
VS
686 - cdissect - determine subexpression matches (with complications)
687 * The retry memory stores the offset of the trial midpoint from begin,
c0a7edde 688 * plus 1 so that 0 uniquely means "clean slate".
3ca4086b 689 ^ static int cdissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 690 */
3ca4086b
VS
691static int /* regexec return code */
692cdissect(v, t, begin, end)
693struct vars *v;
694struct subre *t;
695chr *begin; /* beginning of relevant substring */
696chr *end; /* end of same */
c0a7edde 697{
3ca4086b 698 int er;
c0a7edde
RN
699
700 assert(t != NULL);
701 MDEBUG(("cdissect %ld-%ld %c\n", LOFF(begin), LOFF(end), t->op));
702
3ca4086b
VS
703 switch (t->op) {
704 case '=': /* terminal node */
705 assert(t->left == NULL && t->right == NULL);
706 return REG_OKAY; /* no action, parent did the work */
707 break;
708 case '|': /* alternation */
709 assert(t->left != NULL);
710 return caltdissect(v, t, begin, end);
711 break;
712 case 'b': /* back ref -- shouldn't be calling us! */
713 assert(t->left == NULL && t->right == NULL);
714 return cbrdissect(v, t, begin, end);
715 break;
716 case '.': /* concatenation */
717 assert(t->left != NULL && t->right != NULL);
718 return ccondissect(v, t, begin, end);
719 break;
720 case '(': /* capturing */
721 assert(t->left != NULL && t->right == NULL);
722 assert(t->subno > 0);
723 er = cdissect(v, t->left, begin, end);
724 if (er == REG_OKAY)
725 subset(v, t, begin, end);
726 return er;
727 break;
728 default:
729 return REG_ASSERT;
730 break;
c0a7edde 731 }
34275176 732}
c0a7edde
RN
733
734/*
3ca4086b
VS
735 - ccondissect - concatenation subexpression matches (with complications)
736 * The retry memory stores the offset of the trial midpoint from begin,
c0a7edde 737 * plus 1 so that 0 uniquely means "clean slate".
3ca4086b 738 ^ static int ccondissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 739 */
3ca4086b
VS
740static int /* regexec return code */
741ccondissect(v, t, begin, end)
742struct vars *v;
743struct subre *t;
744chr *begin; /* beginning of relevant substring */
745chr *end; /* end of same */
c0a7edde
RN
746{
747 struct dfa *d;
748 struct dfa *d2;
3ca4086b
VS
749 chr *mid;
750 int er;
c0a7edde
RN
751
752 assert(t->op == '.');
753 assert(t->left != NULL && t->left->cnfa.nstates > 0);
754 assert(t->right != NULL && t->right->cnfa.nstates > 0);
755
3ca4086b 756 if (t->left->flags&SHORTER) /* reverse scan */
c0a7edde
RN
757 return crevdissect(v, t, begin, end);
758
759 d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
760 if (ISERR())
761 return v->err;
762 d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, DOMALLOC);
3ca4086b 763 if (ISERR()) {
c0a7edde
RN
764 freedfa(d);
765 return v->err;
766 }
767 MDEBUG(("cconcat %d\n", t->retry));
768
769 /* pick a tentative midpoint */
3ca4086b
VS
770 if (v->mem[t->retry] == 0) {
771 mid = longest(v, d, begin, end, (int *)NULL);
772 if (mid == NULL) {
c0a7edde
RN
773 freedfa(d);
774 freedfa(d2);
775 return REG_NOMATCH;
776 }
777 MDEBUG(("tentative midpoint %ld\n", LOFF(mid)));
778 v->mem[t->retry] = (mid - begin) + 1;
3ca4086b 779 } else {
c0a7edde
RN
780 mid = begin + (v->mem[t->retry] - 1);
781 MDEBUG(("working midpoint %ld\n", LOFF(mid)));
782 }
783
784 /* iterate until satisfaction or failure */
3ca4086b 785 for (;;) {
c0a7edde
RN
786 /* try this midpoint on for size */
787 er = cdissect(v, t->left, begin, mid);
788 if (er == REG_OKAY &&
3ca4086b
VS
789 longest(v, d2, mid, end, (int *)NULL) == end &&
790 (er = cdissect(v, t->right, mid, end)) ==
791 REG_OKAY)
792 break; /* NOTE BREAK OUT */
793 if (er != REG_OKAY && er != REG_NOMATCH) {
c0a7edde
RN
794 freedfa(d);
795 freedfa(d2);
796 return er;
797 }
798
799 /* that midpoint didn't work, find a new one */
3ca4086b 800 if (mid == begin) {
c0a7edde
RN
801 /* all possibilities exhausted */
802 MDEBUG(("%d no midpoint\n", t->retry));
803 freedfa(d);
804 freedfa(d2);
805 return REG_NOMATCH;
806 }
3ca4086b
VS
807 mid = longest(v, d, begin, mid-1, (int *)NULL);
808 if (mid == NULL) {
c0a7edde
RN
809 /* failed to find a new one */
810 MDEBUG(("%d failed midpoint\n", t->retry));
811 freedfa(d);
812 freedfa(d2);
813 return REG_NOMATCH;
814 }
815 MDEBUG(("%d: new midpoint %ld\n", t->retry, LOFF(mid)));
816 v->mem[t->retry] = (mid - begin) + 1;
817 zapmem(v, t->left);
818 zapmem(v, t->right);
819 }
820
821 /* satisfaction */
822 MDEBUG(("successful\n"));
823 freedfa(d);
824 freedfa(d2);
825 return REG_OKAY;
826}
827
828/*
3ca4086b
VS
829 - crevdissect - determine backref shortest-first subexpression matches
830 * The retry memory stores the offset of the trial midpoint from begin,
c0a7edde 831 * plus 1 so that 0 uniquely means "clean slate".
3ca4086b 832 ^ static int crevdissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 833 */
3ca4086b
VS
834static int /* regexec return code */
835crevdissect(v, t, begin, end)
836struct vars *v;
837struct subre *t;
838chr *begin; /* beginning of relevant substring */
839chr *end; /* end of same */
c0a7edde
RN
840{
841 struct dfa *d;
842 struct dfa *d2;
3ca4086b
VS
843 chr *mid;
844 int er;
c0a7edde
RN
845
846 assert(t->op == '.');
847 assert(t->left != NULL && t->left->cnfa.nstates > 0);
848 assert(t->right != NULL && t->right->cnfa.nstates > 0);
3ca4086b 849 assert(t->left->flags&SHORTER);
c0a7edde
RN
850
851 /* concatenation -- need to split the substring between parts */
852 d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
853 if (ISERR())
854 return v->err;
855 d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, DOMALLOC);
3ca4086b 856 if (ISERR()) {
c0a7edde
RN
857 freedfa(d);
858 return v->err;
859 }
860 MDEBUG(("crev %d\n", t->retry));
861
862 /* pick a tentative midpoint */
3ca4086b
VS
863 if (v->mem[t->retry] == 0) {
864 mid = shortest(v, d, begin, begin, end, (chr **)NULL, (int *)NULL);
865 if (mid == NULL) {
c0a7edde
RN
866 freedfa(d);
867 freedfa(d2);
868 return REG_NOMATCH;
869 }
870 MDEBUG(("tentative midpoint %ld\n", LOFF(mid)));
871 v->mem[t->retry] = (mid - begin) + 1;
3ca4086b 872 } else {
c0a7edde
RN
873 mid = begin + (v->mem[t->retry] - 1);
874 MDEBUG(("working midpoint %ld\n", LOFF(mid)));
875 }
876
877 /* iterate until satisfaction or failure */
3ca4086b 878 for (;;) {
c0a7edde
RN
879 /* try this midpoint on for size */
880 er = cdissect(v, t->left, begin, mid);
881 if (er == REG_OKAY &&
3ca4086b
VS
882 longest(v, d2, mid, end, (int *)NULL) == end &&
883 (er = cdissect(v, t->right, mid, end)) ==
884 REG_OKAY)
885 break; /* NOTE BREAK OUT */
886 if (er != REG_OKAY && er != REG_NOMATCH) {
c0a7edde
RN
887 freedfa(d);
888 freedfa(d2);
889 return er;
890 }
891
892 /* that midpoint didn't work, find a new one */
3ca4086b 893 if (mid == end) {
c0a7edde
RN
894 /* all possibilities exhausted */
895 MDEBUG(("%d no midpoint\n", t->retry));
896 freedfa(d);
897 freedfa(d2);
898 return REG_NOMATCH;
899 }
3ca4086b
VS
900 mid = shortest(v, d, begin, mid+1, end, (chr **)NULL, (int *)NULL);
901 if (mid == NULL) {
c0a7edde
RN
902 /* failed to find a new one */
903 MDEBUG(("%d failed midpoint\n", t->retry));
904 freedfa(d);
905 freedfa(d2);
906 return REG_NOMATCH;
907 }
908 MDEBUG(("%d: new midpoint %ld\n", t->retry, LOFF(mid)));
909 v->mem[t->retry] = (mid - begin) + 1;
910 zapmem(v, t->left);
911 zapmem(v, t->right);
912 }
913
914 /* satisfaction */
915 MDEBUG(("successful\n"));
916 freedfa(d);
917 freedfa(d2);
918 return REG_OKAY;
919}
920
921/*
3ca4086b
VS
922 - cbrdissect - determine backref subexpression matches
923 ^ static int cbrdissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 924 */
3ca4086b
VS
925static int /* regexec return code */
926cbrdissect(v, t, begin, end)
927struct vars *v;
928struct subre *t;
929chr *begin; /* beginning of relevant substring */
930chr *end; /* end of same */
c0a7edde 931{
3ca4086b
VS
932 int i;
933 int n = t->subno;
934 size_t len;
935 chr *paren;
936 chr *p;
937 chr *stop;
938 int min = t->min;
939 int max = t->max;
c0a7edde
RN
940
941 assert(t != NULL);
942 assert(t->op == 'b');
943 assert(n >= 0);
3ca4086b 944 assert((size_t)n < v->nmatch);
c0a7edde
RN
945
946 MDEBUG(("cbackref n%d %d{%d-%d}\n", t->retry, n, min, max));
947
948 if (v->pmatch[n].rm_so == -1)
949 return REG_NOMATCH;
950 paren = v->start + v->pmatch[n].rm_so;
951 len = v->pmatch[n].rm_eo - v->pmatch[n].rm_so;
952
953 /* no room to maneuver -- retries are pointless */
954 if (v->mem[t->retry])
955 return REG_NOMATCH;
956 v->mem[t->retry] = 1;
957
958 /* special-case zero-length string */
3ca4086b 959 if (len == 0) {
c0a7edde
RN
960 if (begin == end)
961 return REG_OKAY;
962 return REG_NOMATCH;
963 }
964
965 /* and too-short string */
966 assert(end >= begin);
3ca4086b 967 if ((size_t)(end - begin) < len)
c0a7edde
RN
968 return REG_NOMATCH;
969 stop = end - len;
970
971 /* count occurrences */
972 i = 0;
3ca4086b
VS
973 for (p = begin; p <= stop && (i < max || max == INFINITY); p += len) {
974 if ((*v->g->compare)(paren, p, len) != 0)
975 break;
c0a7edde
RN
976 i++;
977 }
978 MDEBUG(("cbackref found %d\n", i));
979
980 /* and sort it out */
3ca4086b 981 if (p != end) /* didn't consume all of it */
c0a7edde
RN
982 return REG_NOMATCH;
983 if (min <= i && (i <= max || max == INFINITY))
984 return REG_OKAY;
3ca4086b 985 return REG_NOMATCH; /* out of range */
c0a7edde
RN
986}
987
988/*
3ca4086b
VS
989 - caltdissect - determine alternative subexpression matches (w. complications)
990 ^ static int caltdissect(struct vars *, struct subre *, chr *, chr *);
c0a7edde 991 */
3ca4086b
VS
992static int /* regexec return code */
993caltdissect(v, t, begin, end)
994struct vars *v;
995struct subre *t;
996chr *begin; /* beginning of relevant substring */
997chr *end; /* end of same */
c0a7edde
RN
998{
999 struct dfa *d;
3ca4086b
VS
1000 int er;
1001# define UNTRIED 0 /* not yet tried at all */
1002# define TRYING 1 /* top matched, trying submatches */
1003# define TRIED 2 /* top didn't match or submatches exhausted */
c0a7edde
RN
1004
1005 if (t == NULL)
1006 return REG_NOMATCH;
1007 assert(t->op == '|');
1008 if (v->mem[t->retry] == TRIED)
1009 return caltdissect(v, t->right, begin, end);
1010
1011 MDEBUG(("calt n%d\n", t->retry));
1012 assert(t->left != NULL);
1013
3ca4086b 1014 if (v->mem[t->retry] == UNTRIED) {
c0a7edde
RN
1015 d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
1016 if (ISERR())
1017 return v->err;
3ca4086b 1018 if (longest(v, d, begin, end, (int *)NULL) != end) {
c0a7edde
RN
1019 freedfa(d);
1020 v->mem[t->retry] = TRIED;
1021 return caltdissect(v, t->right, begin, end);
1022 }
1023 freedfa(d);
1024 MDEBUG(("calt matched\n"));
1025 v->mem[t->retry] = TRYING;
1026 }
1027
1028 er = cdissect(v, t->left, begin, end);
1029 if (er != REG_NOMATCH)
1030 return er;
1031
1032 v->mem[t->retry] = TRIED;
1033 return caltdissect(v, t->right, begin, end);
1034}
1035
1036
1037
1038#include "rege_dfa.c"