+int flags;
+{
+       struct vars var;
+       register struct vars *v = &var;
+       int st;
+       size_t n;
+       int backref;
+#      define  LOCALMAT        20
+       regmatch_t mat[LOCALMAT];
+#      define  LOCALMEM        40
+       regoff_t mem[LOCALMEM];
+
+       /* sanity checks */
+       if (re == NULL || string == NULL || re->re_magic != REMAGIC)
+               return REG_INVARG;
+       if (re->re_csize != sizeof(chr))
+               return REG_MIXED;
+
+       /* setup */
+       v->re = re;
+       v->g = (struct guts *)re->re_guts;
+       if ((v->g->cflags®_EXPECT) && details == NULL)
+               return REG_INVARG;
+       if (v->g->info®_UIMPOSSIBLE)
+               return REG_NOMATCH;
+       backref = (v->g->info®_UBACKREF) ? 1 : 0;
+       v->eflags = flags;
+       if (v->g->cflags®_NOSUB)
+               nmatch = 0;             /* override client */
+       v->nmatch = nmatch;
+       if (backref) {
+               /* need work area */
+               if (v->g->nsub + 1 <= LOCALMAT)
+                       v->pmatch = mat;
+               else
+                       v->pmatch = (regmatch_t *)MALLOC((v->g->nsub + 1) *
+                                                       sizeof(regmatch_t));
+               if (v->pmatch == NULL)
+                       return REG_ESPACE;
+               v->nmatch = v->g->nsub + 1;
+       } else
+               v->pmatch = pmatch;
+       v->details = details;
+       v->start = (chr *)string;
+       v->stop = (chr *)string + len;
+       v->err = 0;
+       if (backref) {
+               /* need retry memory */
+               assert(v->g->ntree >= 0);
+               n = (size_t)v->g->ntree;
+               if (n <= LOCALMEM)
+                       v->mem = mem;
+               else
+                       v->mem = (regoff_t *)MALLOC(n*sizeof(regoff_t));
+               if (v->mem == NULL) {
+                       if (v->pmatch != pmatch && v->pmatch != mat)
+                               FREE(v->pmatch);
+                       return REG_ESPACE;
+               }
+       } else
+               v->mem = NULL;
+
+       /* do it */
+       assert(v->g->tree != NULL);
+       if (backref)
+               st = cfind(v, &v->g->tree->cnfa, &v->g->cmap);
+       else
+               st = find(v, &v->g->tree->cnfa, &v->g->cmap);
+
+       /* copy (portion of) match vector over if necessary */
+       if (st == REG_OKAY && v->pmatch != pmatch && nmatch > 0) {
+               zapsubs(pmatch, nmatch);
+               n = (nmatch < v->nmatch) ? nmatch : v->nmatch;
+               memcpy(VS(pmatch), VS(v->pmatch), n*sizeof(regmatch_t));
+       }
+
+       /* clean up */
+       if (v->pmatch != pmatch && v->pmatch != mat)
+               FREE(v->pmatch);
+       if (v->mem != NULL && v->mem != mem)
+               FREE(v->mem);
+       return st;
+}
+
+/*
+ - find - find a match for the main NFA (no-complications case)
+ ^ static int find(struct vars *, struct cnfa *, struct colormap *);
+ */
+static int
+find(v, cnfa, cm)
+struct vars *v;
+struct cnfa *cnfa;
+struct colormap *cm;
+{
+       struct dfa *s;
+       struct dfa *d;
+       chr *begin;
+       chr *end = NULL;
+       chr *cold;
+       chr *open;              /* open and close of range of possible starts */
+       chr *close;
+       int hitend;
+       int shorter = (v->g->tree->flags&SHORTER) ? 1 : 0;
+
+       /* first, a shot with the search RE */
+       s = newdfa(v, &v->g->search, cm, &v->dfa1);
+       assert(!(ISERR() && s != NULL));
+       NOERR();
+       MDEBUG(("\nsearch at %ld\n", LOFF(v->start)));
+       cold = NULL;
+       close = shortest(v, s, v->start, v->start, v->stop, &cold, (int *)NULL);
+       freedfa(s);
+       NOERR();
+       if (v->g->cflags®_EXPECT) {
+               assert(v->details != NULL);
+               if (cold != NULL)
+                       v->details->rm_extend.rm_so = OFF(cold);
+               else
+                       v->details->rm_extend.rm_so = OFF(v->stop);
+               v->details->rm_extend.rm_eo = OFF(v->stop);     /* unknown */
+       }
+       if (close == NULL)              /* not found */
+               return REG_NOMATCH;
+       if (v->nmatch == 0)             /* found, don't need exact location */
+               return REG_OKAY;
+
+       /* find starting point and match */
+       assert(cold != NULL);
+       open = cold;
+       cold = NULL;
+       MDEBUG(("between %ld and %ld\n", LOFF(open), LOFF(close)));
+       d = newdfa(v, cnfa, cm, &v->dfa1);
+       assert(!(ISERR() && d != NULL));
+       NOERR();
+       for (begin = open; begin <= close; begin++) {
+               MDEBUG(("\nfind trying at %ld\n", LOFF(begin)));
+               if (shorter)
+                       end = shortest(v, d, begin, begin, v->stop,
+                                                       (chr **)NULL, &hitend);
+               else
+                       end = longest(v, d, begin, v->stop, &hitend);
+               NOERR();
+               if (hitend && cold == NULL)
+                       cold = begin;
+               if (end != NULL)
+                       break;          /* NOTE BREAK OUT */
+       }
+       assert(end != NULL);            /* search RE succeeded so loop should */
+       freedfa(d);
+
+       /* and pin down details */
+       assert(v->nmatch > 0);
+       v->pmatch[0].rm_so = OFF(begin);
+       v->pmatch[0].rm_eo = OFF(end);
+       if (v->g->cflags®_EXPECT) {
+               if (cold != NULL)
+                       v->details->rm_extend.rm_so = OFF(cold);
+               else
+                       v->details->rm_extend.rm_so = OFF(v->stop);
+               v->details->rm_extend.rm_eo = OFF(v->stop);     /* unknown */
+       }
+       if (v->nmatch == 1)             /* no need for submatches */
+               return REG_OKAY;
+
+       /* submatches */
+       zapsubs(v->pmatch, v->nmatch);
+       return dissect(v, v->g->tree, begin, end);
+}
+
+/*
+ - cfind - find a match for the main NFA (with complications)
+ ^ static int cfind(struct vars *, struct cnfa *, struct colormap *);
+ */
+static int
+cfind(v, cnfa, cm)
+struct vars *v;
+struct cnfa *cnfa;
+struct colormap *cm;
+{
+       struct dfa *s;
+       struct dfa *d;
+       chr *cold;
+       int ret;
+
+       s = newdfa(v, &v->g->search, cm, &v->dfa1);
+       NOERR();
+       d = newdfa(v, cnfa, cm, &v->dfa2);
+       if (ISERR()) {
+               assert(d == NULL);
+               freedfa(s);
+               return v->err;
+       }
+    cold = NULL;// WX: fix gcc warnings about cold being possibly uninitialized
+       ret = cfindloop(v, cnfa, cm, d, s, &cold);
+
+       freedfa(d);
+       freedfa(s);
+       NOERR();
+       if (v->g->cflags®_EXPECT) {
+               assert(v->details != NULL);
+               if (cold != NULL)
+                       v->details->rm_extend.rm_so = OFF(cold);
+               else
+                       v->details->rm_extend.rm_so = OFF(v->stop);
+               v->details->rm_extend.rm_eo = OFF(v->stop);     /* unknown */
+       }
+       return ret;
+}
+
+/*
+ - cfindloop - the heart of cfind
+ ^ static int cfindloop(struct vars *, struct cnfa *, struct colormap *,
+ ^     struct dfa *, struct dfa *, chr **);
+ */
+static int
+cfindloop(v, cnfa, cm, d, s, coldp)
+struct vars *v;
+struct cnfa *cnfa;
+struct colormap *cm;
+struct dfa *d;
+struct dfa *s;
+chr **coldp;                   /* where to put coldstart pointer */
+{
+       chr *begin;
+       chr *end;
+       chr *cold;
+       chr *open;              /* open and close of range of possible starts */
+       chr *close;
+       chr *estart;
+       chr *estop;
+       int er;
+       int shorter = v->g->tree->flags&SHORTER;
+       int hitend;
+
+       assert(d != NULL && s != NULL);
+       cold = NULL;
+       close = v->start;
+       do {
+               MDEBUG(("\ncsearch at %ld\n", LOFF(close)));
+               close = shortest(v, s, close, close, v->stop, &cold, (int *)NULL);
+               if (close == NULL)
+                       break;                          /* NOTE BREAK */
+               assert(cold != NULL);
+               open = cold;
+               cold = NULL;
+               MDEBUG(("cbetween %ld and %ld\n", LOFF(open), LOFF(close)));
+               for (begin = open; begin <= close; begin++) {
+                       MDEBUG(("\ncfind trying at %ld\n", LOFF(begin)));
+                       estart = begin;
+                       estop = v->stop;
+                       for (;;) {
+                               if (shorter)
+                                       end = shortest(v, d, begin, estart,
+                                               estop, (chr **)NULL, &hitend);
+                               else
+                                       end = longest(v, d, begin, estop,
+                                                               &hitend);
+                               if (hitend && cold == NULL)
+                                       cold = begin;
+                               if (end == NULL)
+                                       break;          /* NOTE BREAK OUT */
+                               MDEBUG(("tentative end %ld\n", LOFF(end)));
+                               zapsubs(v->pmatch, v->nmatch);
+                               zapmem(v, v->g->tree);
+                               er = cdissect(v, v->g->tree, begin, end);
+                               if (er == REG_OKAY) {
+                                       if (v->nmatch > 0) {
+                                               v->pmatch[0].rm_so = OFF(begin);
+                                               v->pmatch[0].rm_eo = OFF(end);
+                                       }
+                                       *coldp = cold;
+                                       return REG_OKAY;
+                               }
+                               if (er != REG_NOMATCH) {
+                                       ERR(er);
+                                       return er;
+                               }
+                               if ((shorter) ? end == estop : end == begin) {
+                                       /* no point in trying again */
+                                       *coldp = cold;
+                                       return REG_NOMATCH;
+                               }
+                               /* go around and try again */
+                               if (shorter)
+                                       estart = end + 1;
+                               else
+                                       estop = end - 1;
+                       }
+               }
+       } while (close < v->stop);
+
+       *coldp = cold;
+       return REG_NOMATCH;
+}
+
+/*
+ - zapsubs - initialize the subexpression matches to "no match"
+ ^ static VOID zapsubs(regmatch_t *, size_t);
+ */
+static VOID
+zapsubs(p, n)
+regmatch_t *p;
+size_t n;
+{
+       size_t i;
+
+       for (i = n-1; i > 0; i--) {
+               p[i].rm_so = -1;
+               p[i].rm_eo = -1;
+       }
+}
+
+/*
+ - zapmem - initialize the retry memory of a subtree to zeros
+ ^ static VOID zapmem(struct vars *, struct subre *);
+ */
+static VOID
+zapmem(v, t)
+struct vars *v;
+struct subre *t;
+{
+       if (t == NULL)
+               return;
+
+       assert(v->mem != NULL);
+       v->mem[t->retry] = 0;
+       if (t->op == '(') {
+               assert(t->subno > 0);
+               v->pmatch[t->subno].rm_so = -1;
+               v->pmatch[t->subno].rm_eo = -1;
+       }
+
+       if (t->left != NULL)
+               zapmem(v, t->left);
+       if (t->right != NULL)
+               zapmem(v, t->right);
+}
+
+/*
+ - subset - set any subexpression relevant to a successful subre
+ ^ static VOID subset(struct vars *, struct subre *, chr *, chr *);
+ */
+static VOID
+subset(v, sub, begin, end)
+struct vars *v;
+struct subre *sub;
+chr *begin;
+chr *end;
+{
+       int n = sub->subno;
+
+       assert(n > 0);
+       if ((size_t)n >= v->nmatch)
+               return;
+
+       MDEBUG(("setting %d\n", n));
+       v->pmatch[n].rm_so = OFF(begin);
+       v->pmatch[n].rm_eo = OFF(end);
+}
+
+/*
+ - dissect - determine subexpression matches (uncomplicated case)
+ ^ static int dissect(struct vars *, struct subre *, chr *, chr *);
+ */
+static int                     /* regexec return code */
+dissect(v, t, begin, end)
+struct vars *v;
+struct subre *t;
+chr *begin;                    /* beginning of relevant substring */
+chr *end;                      /* end of same */
+{
+       assert(t != NULL);
+       MDEBUG(("dissect %ld-%ld\n", LOFF(begin), LOFF(end)));
+
+       switch (t->op) {
+       case '=':               /* terminal node */
+               assert(t->left == NULL && t->right == NULL);
+               return REG_OKAY;        /* no action, parent did the work */
+               break;
+       case '|':               /* alternation */
+               assert(t->left != NULL);
+               return altdissect(v, t, begin, end);
+               break;
+       case 'b':               /* back ref -- shouldn't be calling us! */
+               return REG_ASSERT;
+               break;
+       case '.':               /* concatenation */
+               assert(t->left != NULL && t->right != NULL);
+               return condissect(v, t, begin, end);
+               break;
+       case '(':               /* capturing */
+               assert(t->left != NULL && t->right == NULL);
+               assert(t->subno > 0);
+               subset(v, t, begin, end);
+               return dissect(v, t->left, begin, end);
+               break;
+       default:
+               return REG_ASSERT;
+               break;
+       }
+}
+
+/*
+ - condissect - determine concatenation subexpression matches (uncomplicated)
+ ^ static int condissect(struct vars *, struct subre *, chr *, chr *);
+ */
+static int                     /* regexec return code */
+condissect(v, t, begin, end)
+struct vars *v;
+struct subre *t;
+chr *begin;                    /* beginning of relevant substring */
+chr *end;                      /* end of same */