summaryrefslogtreecommitdiff
path: root/src/vi/ex-070224/libuxre/regnfa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vi/ex-070224/libuxre/regnfa.c')
-rw-r--r--src/vi/ex-070224/libuxre/regnfa.c1070
1 files changed, 0 insertions, 1070 deletions
diff --git a/src/vi/ex-070224/libuxre/regnfa.c b/src/vi/ex-070224/libuxre/regnfa.c
deleted file mode 100644
index 6953f1f..0000000
--- a/src/vi/ex-070224/libuxre/regnfa.c
+++ /dev/null
@@ -1,1070 +0,0 @@
-/*
- * Changes by Gunnar Ritter, Freiburg i. Br., Germany, November 2002.
- *
- * Sccsid @(#)regnfa.c 1.8 (gritter) 2/6/05
- */
-/* UNIX(R) Regular Expresssion Library
- *
- * Note: Code is released under the GNU LGPL
- *
- * Copyright (C) 2001 Caldera International, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to:
- * Free Software Foundation, Inc.
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* #include "synonyms.h" */
-#include <string.h>
-#include <stdlib.h>
-#include "re.h"
-#include <stddef.h>
-#include <ctype.h>
-
-typedef unsigned char Uchar;
-typedef unsigned short Ushort;
-
-/*
-* Nondeterministic Finite Automata.
-*/
-typedef struct t_graph Graph;
-struct t_graph
-{
- union
- {
- Graph *ptr;
- Info info;
- } alt;
- Graph *next;
- w_type op;
-};
-
-typedef struct t_stack Stack;
-struct t_stack
-{
- Stack *link; /* simplifies cleanup */
- Stack *prev; /* covered states */
- Graph *wasgp; /* node associated with this state */
- const Uchar *str; /* saved position in the string */
- Ushort cnt; /* ROP_BRACE: traversal count */
-};
-
- /*
- * A Context holds all the information needed for each
- * potential path through the NFA graph.
- */
-typedef struct t_ctxt Context;
-struct t_ctxt
-{
- Context *link; /* simplifies cleanup */
- Context *next; /* singly linked */
- Stack *sp; /* nested counts */
- Graph *gp; /* starting node */
- Graph *wasgp; /* node associated with this state */
- const Uchar *str; /* saved position in the string */
- Ushort cnt; /* ROP_BRACE: traversal count */
- size_t nset; /* length of rm[] that is currently set */
- regmatch_t rm[1]; /* enough to cover re_nsub+1 (np->rmlen) */
-};
-
-struct re_nfa_ /*Nfa*/
-{
- Graph *gp; /* entire NFA */
- Stack *sp; /* unused Stacks */
- Stack *allsp; /* linked Stacks (for cleanup) */
- Context *allcp; /* linked Contexts (for cleanup) */
- Context *cur; /* Contexts to be continued now */
- Context *step; /* Contexts waiting for a step of the NFA */
- Context *avail; /* unused Contexts */
- Context **ecur; /* ends cur list of Contexts */
- Context **estp; /* ends step list of Contexts */
- size_t rmlen; /* length of rm[] in each Context */
- size_t rmmin; /* minimum length needed */
- size_t used; /* length used for this libuxre_regnfaexec() */
- w_type beg; /* nonzero for fixed char initial node NFAs */
-};
-
-#define ROP_MTOR ROP_CAT /* ROP_OR, except might be empty loop */
-
- /*
- * Depth first traversal.
- * Make a singly linked list (in alt.ptr) of the graph's nodes.
- * Must toss any ROP_BKTs, too, since "alt" is overwritten.
- */
-static void
-deltolist(Graph *gp, Graph **list)
-{
- Graph *ptr;
-
- if ((ptr = gp->next) != 0) /* first time */
- {
- gp->next = 0;
- if (gp->op == ROP_OR || gp->op == ROP_MTOR)
- deltolist(gp->alt.ptr, list);
- deltolist(ptr, list);
- if (gp->op == ROP_BKT)
- {
- libuxre_bktfree(gp->alt.info.bkt);
- free(gp->alt.info.bkt);
- }
- }
- else if (gp->op == ROP_END)
- gp->op = ROP_NOP;
- else
- return;
- gp->alt.ptr = *list;
- *list = gp;
-}
-
- /*
- * After the list is turned into a linked list,
- * walk that list freeing the nodes.
- */
-static void
-delgraph(Graph *gp)
-{
- Graph *gp2, end;
-
- gp2 = &end;
- deltolist(gp, &gp2);
- while ((gp = gp2) != &end)
- {
- gp2 = gp->alt.ptr;
- free(gp);
- }
-}
-
- /*
- * Depth first traversal.
- * Look for ROP_NOPs and prune them from the graph.
- * Chain them all together on *nop's list.
- */
-static Graph *
-nopskip(Graph *gp, Graph **nop)
-{
- Graph *ptr;
-
- if ((ptr = gp->next) != 0) /* might have yet to do this subgraph */
- {
- if (gp->op == ROP_NOP)
- {
- if (gp->alt.ptr != 0) /* touched */
- return gp->next; /* already did it */
- gp->alt.ptr = *nop;
- *nop = gp;
- }
- gp->next = 0; /* this subgraph's pending */
- if (gp->op == ROP_OR || gp->op == ROP_MTOR)
- gp->alt.ptr = nopskip(gp->alt.ptr, nop);
- gp->next = nopskip(ptr, nop);
- if (gp->op == ROP_NOP)
- return gp->next;
- }
- return gp;
-}
-
- /*
- * Postorder traversal of the parse tree.
- * Build a graph using "Thompson's" algorithm.
- * The only significant modification is the
- * ROP_BRACE->ROP_MTOR construction.
- * Returns 1 => graph might match empty
- * 0 => graph cannot match empty
- * -1 => error (in allocation)
- */
-static int
-mkgraph(Tree *tp, Graph **first, Graph **last)
-{
- Graph *new = 0, *nop, *lf, *ll, *rf, *rl;
- int lmt, rmt = 0;
-
- if (tp->op != ROP_CAT)
- {
- if ((new = malloc(sizeof(Graph))) == 0)
- return 0;
- new->op = tp->op; /* usually */
- }
- switch (tp->op)
- {
- case ROP_REF:
- new->alt.info.sub = tp->right.info.sub;
- *first = new;
- *last = new;
- return 1; /* safe--can't really tell */
- case ROP_BKT:
- tp->op = ROP_BKTCOPY; /* now graph owns clean up */
- /*FALLTHROUGH*/
- case ROP_BKTCOPY:
- new->alt.info.bkt = tp->right.info.bkt;
- /*FALLTHROUGH*/
- default:
- *first = new;
- *last = new;
- return 0;
- case ROP_EMPTY:
- new->op = ROP_NOP;
- new->alt.ptr = 0; /* untouched */
- *first = new;
- *last = new;
- return 1;
- case ROP_OR:
- case ROP_CAT:
- lf = 0; /* in case of error */
- if ((rmt = mkgraph(tp->right.ptr, &rf, &rl)) < 0)
- goto err;
- /*FALLTHROUGH*/
- case ROP_STAR:
- case ROP_PLUS:
- case ROP_QUEST:
- case ROP_BRACE:
- case ROP_LP:
- if ((lmt = mkgraph(tp->left.ptr, &lf, &ll)) < 0)
- goto err;
- break;
- }
- /*
- * Note that ROP_NOP only serves as the node that reconnects
- * the two choices of an incoming ROP_OR or ROP_QUEST. To
- * prevent rewalking portions of the graph in nopskip(),
- * this code marks all ROP_NOP nodes as currently untouched.
- */
- switch (tp->op)
- {
- case ROP_OR:
- if ((nop = malloc(sizeof(Graph))) == 0)
- goto err;
- nop->op = ROP_NOP;
- nop->alt.ptr = 0; /* untouched */
- ll->next = nop;
- rl->next = nop;
- new->next = lf;
- new->alt.ptr = rf;
- *first = new;
- *last = nop;
- return lmt | rmt;
- case ROP_CAT: /* no "new" */
- ll->next = rf;
- *first = lf;
- *last = rl;
- return lmt & rmt;
- case ROP_QUEST:
- if ((nop = malloc(sizeof(Graph))) == 0)
- goto err;
- nop->op = ROP_NOP;
- nop->alt.ptr = 0; /* untouched */
- new->op = ROP_OR;
- new->next = lf;
- new->alt.ptr = nop;
- ll->next = nop;
- *first = new;
- *last = nop;
- return 1;
- case ROP_STAR:
- *first = new;
- rmt = 1;
- star:;
- new->op = lmt ? ROP_MTOR : ROP_OR;
- new->alt.ptr = lf;
- ll->next = new;
- *last = new;
- return rmt;
- case ROP_PLUS:
- *first = lf;
- rmt = lmt;
- goto star;
- case ROP_BRACE:
- if ((nop = malloc(sizeof(Graph))) == 0)
- goto err;
- nop->op = ROP_MTOR; /* going to save state anyway... */
- nop->alt.ptr = lf;
- ll->next = new;
- new->next = nop;
- new->alt.info.num[1] = tp->right.info.num[1];
- if ((new->alt.info.num[0] = tp->right.info.num[0]) == 0)
- {
- lmt = 1;
- *first = new;
- }
- else
- {
- new->alt.info.num[0]--; /* already done 1 */
- if (new->alt.info.num[1] != BRACE_INF)
- new->alt.info.num[1]--; /* likewise */
- *first = lf;
- }
- *last = nop;
- return lmt;
- case ROP_LP:
- if ((nop = malloc(sizeof(Graph))) == 0)
- goto err;
- nop->op = ROP_RP;
- nop->alt.info.sub = tp->right.info.sub;
- new->alt.info.sub = tp->right.info.sub;
- new->next = lf;
- ll->next = nop;
- *first = new;
- *last = nop;
- return lmt;
- }
-err:;
- if (KIND_ROP(tp->op) == BINARY_ROP && rf != 0)
- delgraph(rf);
- if (lf != 0)
- delgraph(lf);
- if (tp->op != ROP_CAT)
- free(new);
- return -1;
-}
-
- /*
- * Semi-preorder traversal.
- * Return zero if there's no simple first character
- * (including the operation ROP_BOL) that must always
- * be at the start of a matching string.
- * This code doesn't attempt to get an answer if the
- * first of the tree many be empty.
- */
-static w_type
-firstop(Tree *tp)
-{
- w_type op;
-
- switch (tp->op)
- {
- case ROP_OR:
- if ((op = firstop(tp->left.ptr)) == 0
- || op != firstop(tp->right.ptr))
- {
- return 0;
- }
- return op;
- case ROP_BRACE:
- if (tp->right.info.num[0] == 0)
- return 0;
- /*FALLTHROUGH*/
- case ROP_CAT:
- case ROP_PLUS:
- case ROP_LP:
- return firstop(tp->left.ptr);
- default:
- if (tp->op < 0)
- return 0;
- /*FALLTHROUGH*/
- case ROP_BOL:
- return tp->op;
- }
-}
-
-void
-libuxre_regdelnfa(Nfa *np)
-{
- Context *cp, *cpn;
- Stack *sp, *spn;
-
- if (np->gp != 0)
- delgraph(np->gp);
- for (cp = np->allcp; cp != 0; cp = cpn)
- {
- cpn = cp->link;
- free(cp);
- }
- for (sp = np->allsp; sp != 0; sp = spn)
- {
- spn = sp->link;
- free(sp);
- }
- free(np);
-}
-
-LIBUXRE_STATIC int
-libuxre_regnfacomp(regex_t *ep, Tree *tp, Lex *lxp)
-{
- Graph *gp, end;
- Nfa *np;
-
- if ((np = malloc(sizeof(Nfa))) == 0)
- goto err;
- np->gp = 0; /* in case of error */
- if (mkgraph(tp, &np->gp, &gp) < 0)
- goto err;
- gp->next = 0; /* nothing follows ROP_END */
- np->rmlen = 0;
- if ((ep->re_flags & REG_NOSUB) == 0)
- np->rmlen = ep->re_nsub + 1;
- np->rmmin = 0;
- if (lxp->maxref != 0 && (np->rmmin = lxp->maxref + 1) > np->rmlen)
- np->rmlen = np->rmmin;
- /*
- * Delete all ROP_NOPs from the graph.
- * nopskip() disconnects them from the graph and
- * links them together through their alt.ptr's.
- */
- gp = &end;
- np->gp = nopskip(np->gp, &gp);
- while (gp != &end)
- {
- Graph *gp2 = gp;
-
- gp = gp->alt.ptr;
- free(gp2);
- }
- np->sp = 0;
- np->allsp = 0;
- np->avail = 0;
- np->allcp = 0;
- ep->re_nfa = np;
- np->beg = firstop(tp);
- return 0;
-err:;
- if (np != 0)
- {
- if (np->gp != 0)
- delgraph(np->gp);
- free(np);
- }
- return REG_ESPACE;
-}
-
-static Stack *
-newstck(Nfa *np)
-{
- Stack *sp, **spp;
- int i;
-
- if ((sp = np->sp) == 0) /* get more */
- {
- spp = &np->sp;
- i = 4;
- while ((sp = malloc(sizeof(Stack))) != 0)
- {
- sp->link = np->allsp;
- np->allsp = sp;
- *spp = sp;
- spp = &sp->prev;
- if (--i == 0)
- break;
- }
- *spp = 0;
- if ((sp = np->sp) == 0) /* first malloc failed */
- return 0;
- }
- np->sp = sp->prev;
- return sp;
-}
-
-static int
-mkstck(Nfa *np, Context *cp, Graph *gp)
-{
- Stack *new, *sp;
-
- if (gp == 0) /* copy existing stack tail */
- {
- /*
- * Hoist up top of stack.
- */
- new = cp->sp;
- cp->wasgp = new->wasgp;
- cp->str = new->str;
- cp->cnt = new->cnt;
- cp->sp = new->prev;
- if ((sp = new->prev) == 0) /* only one below */
- {
- new->prev = np->sp;
- np->sp = new;
- cp->sp = 0;
- return 0;
- }
- for (;;) /* copy the rest; reusing the old top */
- {
- new->wasgp = sp->wasgp;
- new->str = sp->str;
- new->cnt = sp->cnt;
- if ((new->prev = sp->prev) == 0)
- break;
- if ((new->prev = newstck(np)) == 0)
- return REG_ESPACE;
- new = new->prev;
- sp = sp->prev;
- }
- return 0;
- }
- if (cp->wasgp != 0) /* push current down */
- {
- if ((new = newstck(np)) == 0)
- return REG_ESPACE;
- new->prev = cp->sp;
- cp->sp = new;
- new->wasgp = cp->wasgp;
- new->str = cp->str;
- new->cnt = cp->cnt;
- }
- cp->wasgp = gp;
- cp->str = 0;
- cp->cnt = 0;
- return 0;
-}
-
- /*
- * Allocate a new Context (from np->avail)
- * and add it to the end of the current list.
- */
-static int
-newctxt(Nfa *np, Context *cp, Graph *gp)
-{
- Context *new;
- size_t n;
-
- if ((new = np->avail) == 0) /* need more */
- {
- Context *ncp, **cpp;
- int i;
-
- /*
- * Can't easily allocate Contexts in one call because
- * the alignments (given the varying length of rm[])
- * are potentially nontrivial.
- */
- n = offsetof(Context, rm) + np->rmlen * sizeof(regmatch_t);
- i = 4;
- cpp = &np->avail;
- while ((ncp = malloc(n)) != 0)
- {
- ncp->link = np->allcp;
- np->allcp = ncp;
- *cpp = ncp;
- cpp = &ncp->next;
- if (--i == 0)
- break;
- }
- *cpp = 0;
- if ((new = np->avail) == 0) /* first malloc failed */
- return REG_ESPACE;
- }
- np->avail = new->next;
- new->next = 0;
- new->gp = gp;
- new->sp = 0;
- new->wasgp = 0;
- new->nset = 0;
- if (cp != 0) /* copy existing context information */
- {
- if (cp->sp != 0) /* copy tail of stack */
- {
- new->sp = cp->sp;
- if (mkstck(np, new, 0) != 0)
- return REG_ESPACE;
- }
- new->wasgp = cp->wasgp;
- new->str = cp->str;
- new->cnt = cp->cnt;
- /*
- * Copy any valid subexpression match information
- * from the existing context.
- */
- if (np->used != 0 && (n = cp->nset) != 0)
- {
- regmatch_t *rmn = new->rm, *rmo = cp->rm;
-
- new->nset = n;
- for (;; ++rmn, ++rmo)
- {
- rmn->rm_so = rmo->rm_so;
- rmn->rm_eo = rmo->rm_eo;
- if (--n == 0)
- break;
- }
- }
- }
- /*
- * Append it to the end of the current Context list.
- */
- *np->ecur = new;
- np->ecur = &new->next;
- return 0;
-}
-
- /*
- * Compare two byte string sequences for equality.
- * If REG_ICASE, walk through the strings doing
- * caseless comparisons of the wide characters.
- */
-static int
-casecmp(const Uchar *s, Exec *xp, ssize_t i, ssize_t n, int mb_cur_max)
-{
- const Uchar *p = &xp->str[i];
- const Uchar *end;
- w_type wc1, wc2;
- int k;
-
- if (strncmp((char *)s, (char *)p, n) == 0) /* try for exact match */
- return 1;
- if ((xp->flags & REG_ICASE) == 0)
- return 0;
- /*
- * Walk through each testing for a match, ignoring case,
- * of the resulting wide characters.
- * Note that only "s" can run out of characters.
- */
- end = &p[n];
- do
- {
- if ((wc1 = *s++) == '\0')
- return 0;
- if (!ISONEBYTE(wc1) && (k = libuxre_mb2wc(&wc1, s)) > 0)
- s += k;
- if (!ISONEBYTE(wc2 = *p++) && (k = libuxre_mb2wc(&wc2, p)) > 0)
- p += k;
- if (wc1 != wc2)
- {
- wc1 = to_lower(wc1);
- wc2 = to_lower(wc2);
- if (wc1 != wc2)
- return 0;
- }
- } while (p < end);
- return 1;
-}
-
-LIBUXRE_STATIC int
-libuxre_regnfaexec(Nfa *np, Exec *xp)
-{
- const Uchar *s, *s1, *s2;
- Context *cp, *cpn;
- Graph *gp, *brace;
- Stack *sp, *spn;
- ssize_t rmso, len;
- int i, ret, mb_cur_max;
- w_type wc;
- size_t n;
-
- ret = 0; /* assume it matches */
- rmso = -1; /* but no match yet */
- np->cur = 0;
- np->step = 0;
- np->ecur = &np->cur;
- np->estp = &np->step;
- if ((np->used = xp->nmatch) < np->rmmin)
- np->used = np->rmmin;
- s1 = 0; /* one char back */
- s = xp->str; /* current high water in string */
- mb_cur_max = xp->mb_cur_max;
- for (;;)
- {
- /*
- * Get next character from string.
- * If the engine proper hasn't started and the engine
- * requires a particular character to start and this
- * character isn't it, try the next one.
- */
- for (;;)
- {
- s2 = s1;
- s1 = s;
- if (!ISONEBYTE(wc = *s++) &&
- (i = libuxre_mb2wc(&wc, s)) > 0)
- s += i;
- if (np->cur != 0 || np->beg == wc || np->beg == 0)
- break;
- if (np->beg == ROP_BOL)
- {
- if (s2 == 0 && (xp->flags & REG_NOTBOL) == 0)
- break;
- if ((xp->flags & REG_NEWLINE) == 0)
- goto nomatch;
- if (s2 != 0 && *s2 == '\n')
- break;
- }
- if (wc == '\0')
- goto nomatch;
- }
- /*
- * Start the engine by inserting a fresh initial context
- * if there's no known match as yet. (Once some match
- * has been found, the end is near.)
- */
- if (rmso < 0 && newctxt(np, 0, np->gp) != 0)
- goto err;
- /*
- * Walk the current Contexts list, trying each.
- * "loop" is when a new Context is to be tried,
- * "again" is when the same Context continues,
- * but wc was not yet matched.
- */
- cp = np->cur;
- loop:;
- gp = cp->gp;
- again:;
- switch (gp->op)
- {
- case ROP_BRACE: /* gp->next->op == ROP_MTOR */
- brace = gp;
- gp = gp->next;
- goto mtor;
- case ROP_MTOR:
- brace = 0;
- mtor:;
- if (cp->wasgp != gp) /* first time */
- {
- if (mkstck(np, cp, gp) != 0)
- goto err;
- }
- else if (cp->str == s) /* spinning */
- goto poptonext;
- cp->str = s;
- if (brace != 0)
- {
- if (cp->cnt >= brace->alt.info.num[1])
- goto poptonext;
- if (++cp->cnt <= brace->alt.info.num[0])
- {
- gp = gp->alt.ptr;
- goto again;
- }
- if (cp->cnt > BRACE_MAX)
- cp->cnt = BRACE_MAX;
- }
- if (newctxt(np, cp, gp->alt.ptr) != 0)
- goto err;
- poptonext:;
- cp->wasgp = 0;
- if ((sp = cp->sp) != 0) /* pop stack */
- {
- cp->sp = sp->prev;
- cp->wasgp = sp->wasgp;
- cp->str = sp->str;
- cp->cnt = sp->cnt;
- sp->prev = np->sp;
- np->sp = sp;
- }
- /*FALLTHROUGH*/
- case ROP_EMPTY:
- tonext:;
- gp = gp->next;
- goto again;
- case ROP_OR:
- if (newctxt(np, cp, gp->alt.ptr) != 0)
- goto err;
- goto tonext;
- case ROP_LP:
- if ((n = gp->alt.info.sub) < np->used)
- {
- size_t k;
-
- cp->rm[n].rm_so = s1 - xp->str;
- cp->rm[n].rm_eo = -1;
- /*
- * Mark any skipped subexpressions as
- * failing to participate in the match.
- */
- if ((k = cp->nset) < n)
- {
- regmatch_t *rmp = &cp->rm[k];
-
- for (;; rmp++)
- {
- rmp->rm_so = -1;
- rmp->rm_eo = -1;
- if (++k >= n)
- break;
- }
- }
- cp->nset = n + 1;
- }
- goto tonext;
- case ROP_RP:
- if ((n = gp->alt.info.sub) < np->used)
- cp->rm[n].rm_eo = s1 - xp->str;
- goto tonext;
- case ROP_BOL:
- if (s2 == 0)
- {
- if (xp->flags & REG_NOTBOL)
- goto failed;
- }
- else if ((xp->flags & REG_NEWLINE) == 0 || *s2 != '\n')
- goto failed;
- goto tonext;
- case ROP_EOL:
- if (wc == '\0')
- {
- if (xp->flags & REG_NOTEOL)
- goto failed;
- }
- else if ((xp->flags & REG_NEWLINE) == 0 || wc != '\n')
- goto failed;
- goto tonext;
- default: /* character match */
- if (gp->op != wc)
- {
- if ((xp->flags & REG_ICASE) == 0
- || gp->op != to_lower(wc))
- {
- goto failed;
- }
- }
- nextwc:;
- cp->gp = gp->next;
- tostep:;
- cpn = cp->next;
- cp->next = 0;
- *np->estp = cp;
- np->estp = &cp->next;
- if ((cp = cpn) == 0)
- break;
- goto loop;
- case ROP_NOTNL:
- if (wc == '\n')
- goto failed;
- /*FALLTHROUGH*/
- case ROP_ANYCH:
- if (wc > '\0')
- goto nextwc;
- /*FALLTHROUGH*/
- case ROP_NONE:
- failed:;
- cpn = cp->next;
- cp->next = np->avail;
- np->avail = cp;
- if ((cp = cpn) == 0)
- break;
- goto loop;
- case ROP_LT:
- if (s2 == 0)
- {
- if (xp->flags & REG_NOTBOL)
- goto failed;
- }
- else
- {
- w_type pwc;
-
- if (wc != '_' &&
- !iswalnum(mb_cur_max == 1 ? btowc(wc) : wc))
- goto failed;
- if (!ISONEBYTE(pwc = *s2))
- libuxre_mb2wc(&pwc, &s2[1]);
- if (pwc == '_' ||
- iswalnum(mb_cur_max== 1 ? btowc(pwc) : pwc))
- goto failed;
- }
- goto tonext;
- case ROP_GT:
- if (wc == '_' ||
- iswalnum(mb_cur_max == 1 ? btowc(wc) : wc))
- goto failed;
- goto tonext;
- case ROP_BKT:
- case ROP_BKTCOPY:
- if (cp->wasgp == gp) /* rest of MCCE */
- {
- checkspin:;
- if (s1 >= cp->str) /* got it all */
- goto poptonext;
- goto tostep;
- }
- if ((i = libuxre_bktmbexec(gp->alt.info.bkt, wc, s,
- mb_cur_max)) < 0)
- goto failed;
- if ((n = i) == 0) /* only matched wc */
- goto nextwc;
- spin:;
- if (mkstck(np, cp, gp) != 0)
- goto err;
- cp->gp = gp; /* stay here until reach past s+n */
- cp->str = s + n;
- goto tostep;
- case ROP_REF:
- if (cp->wasgp == gp) /* rest of matched string */
- goto checkspin;
- if ((n = gp->alt.info.sub) >= cp->nset)
- goto failed;
- if ((len = cp->rm[n].rm_eo) < 0)
- goto failed;
- if ((len -= n = cp->rm[n].rm_so) == 0)
- goto tonext;
- if (casecmp(s1, xp, n, len, mb_cur_max) == 0)
- goto failed;
- if ((n = s - s1) >= len)
- goto nextwc;
- n = len - n;
- goto spin;
- case ROP_END: /* success! */
- if (xp->flags & REG_NONEMPTY)
- {
- if (s2 == 0)
- goto failed;
- }
- if (xp->nmatch == 0)
- goto match;
- /*
- * Mark any skipped subexpressions as failing to match.
- */
- if ((n = cp->nset) < xp->nmatch)
- {
- do
- {
- cp->rm[n].rm_so = -1;
- cp->rm[n].rm_eo = -1;
- } while (++n < xp->nmatch);
- }
- /*
- * Note the left-most match that's longest.
- */
- n = cp->rm[0].rm_so;
- if (rmso < 0 || n < rmso)
- {
- rmso = n;
- record:;
- memcpy(xp->match, cp->rm,
- xp->nmatch * sizeof(regmatch_t));
- goto failed;
- }
- if (rmso < n || xp->match[0].rm_eo > cp->rm[0].rm_eo)
- goto failed;
- if (xp->match[0].rm_eo < cp->rm[0].rm_eo)
- goto record;
-#if 0 /* maximize the lengths of earlier LP...RPs */
- /*
- * If both are of the same length and start
- * at the same point, choose the one with
- * a "longest submatch from left to right"
- * where an empty string wins over a nonmatch.
- */
- for (n = 1; n < xp->nmatch; n++)
- {
- ssize_t nlen;
-
- /*
- * First, go with the choice that has any
- * match for subexpr n.
- */
- len = xp->match[n].rm_eo;
- nlen = cp->rm[n].rm_eo;
- if (nlen < 0)
- {
- if (len >= 0)
- break;
- }
- else if (len < 0)
- goto record;
- /*
- * Both have a match; go with the longer.
- */
- len -= xp->match[n].rm_so;
- nlen -= cp->rm[n].rm_so;
- if (nlen < len)
- break;
- if (nlen > len)
- goto record;
- }
-#else /* take LP and RP as "fence posts" and maximize earlier gaps */
- /*
- * If both are of the same length and start
- * at the same point, choose the one with
- * the larger earlier subpatterns, in which
- * each rm_so and rm_eo serves as a separator.
- */
- for (n = 1; n < xp->nmatch; n++)
- {
- ssize_t nlen;
- int use;
-
- if (xp->flags & REG_AVOIDNULL) {
- /*
- * This is to to satisfy POSIX.1-2001
- * XBD pp. 172-173 ll. 6127-6129, whose
- * translation is "do not match null
- * expressions if there is a choice".
- * See also POSIX.2 interpretation #43
- * in which the question was raised.
- *
- * The first subexpression of "\(x*\)*"
- * must thus match the string "xxx".
- */
- use = cp->rm[n].rm_eo -
- cp->rm[n].rm_so >=
- xp->match[n].rm_eo -
- xp->match[n].rm_so ||
- xp->match[n].rm_so < 0;
- } else
- use = 1;
- /*
- * Choose the rightmost ROP_LP as that
- * maximizes the gap from before.
- */
- len = xp->match[n].rm_so;
- nlen = cp->rm[n].rm_so;
- if (len < nlen && use)
- goto record;
- if (len > nlen)
- break;
- /*
- * The ROP_LPs are at the same point:
- * Choose the rightmost ROP_RP.
- */
- len = xp->match[n].rm_eo;
- nlen = cp->rm[n].rm_eo;
- if (len < nlen && use)
- goto record;
- if (len > nlen)
- break;
- }
-#endif
- goto failed;
- }
- /*
- * Finished the current Context list. If the input string
- * has been entirely scanned, we're done. Otherwise, make
- * the next step list current for the next character.
- * If the next step list was empty and there's an existing
- * match, that's the left-most longest.
- */
- if (wc == '\0')
- {
- if (rmso >= 0)
- goto match;
- goto nomatch;
- }
- np->ecur = np->estp;
- if ((np->cur = np->step) == 0)
- {
- if (rmso >= 0)
- goto match;
- np->ecur = &np->cur; /* was pointing at step */
- }
- np->step = 0;
- np->estp = &np->step;
- }
-nomatch:;
- ret = REG_NOMATCH;
-match:;
- np->avail = 0;
- for (cp = np->allcp; cp != 0; cp = cpn)
- {
- cpn = cp->link;
- cp->next = np->avail;
- np->avail = cp;
- }
- np->sp = 0;
- for (sp = np->allsp; sp != 0; sp = spn)
- {
- spn = sp->link;
- sp->prev = np->sp;
- np->sp = sp;
- }
- return ret;
-err:;
- ret = REG_ESPACE;
- goto match;
-}