static const char *matchitem (const char *s, const char *p, struct Capture *cap, const char **ep) { if (*p == ESC) { p++; if (isdigit((byte)*p)) { /* capture */ int32 l = check_cap(*p, cap); int32 len = cap->capture[l].len; *ep = p+1; if (cap->src_end-s >= len && memcmp(cap->capture[l].init, s, len) == 0) return s+len; else return NULL; } else if (*p == 'b') { /* balanced string */ p++; if (*p == 0 || *(p+1) == 0) lua_error("unbalanced pattern"); *ep = p+2; return matchbalance(s, *p, *(p+1), cap); } else p--; /* and go through */ } /* "luaI_singlematch" sets "ep" (so must be called even when *s == 0) */ return (luaI_singlematch((byte)*s, p, ep) && s<cap->src_end) ? s+1 : NULL; }
static const char *match (lua_State *L, const char *s, const char *p, struct Capture *cap) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': /* start capture */ return start_capture(L, s, p, cap); case ')': /* end capture */ return end_capture(L, s, p, cap); case ESC: /* may be %[0-9] or %b */ if (isdigit((unsigned char)(*(p+1)))) { /* capture? */ s = match_capture(L, s, *(p+1), cap); if (s == NULL) return NULL; p+=2; goto init; /* else return match(L, s, p+2, cap) */ } else if (*(p+1) == 'b') { /* balanced string? */ s = matchbalance(L, s, p+2, cap); if (s == NULL) return NULL; p+=4; goto init; /* else return match(L, s, p+4, cap); */ } else goto dflt; /* case default */ case '\0': /* end of pattern */ return s; /* match succeeded */ case '$': if (*(p+1) == '\0') /* is the '$' the last char in pattern? */ return (s == cap->src_end) ? s : NULL; /* check end of string */ else goto dflt; default: dflt: { /* it is a pattern item */ const char *ep = luaI_classend(L, p); /* points to what is next */ int m = s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep); switch (*ep) { case '?': { /* optional */ const char *res; if (m && ((res=match(L, s+1, ep+1, cap)) != NULL)) return res; p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */ } case '*': /* 0 or more repetitions */ return max_expand(L, s, p, ep, cap); case '+': /* 1 or more repetitions */ return (m ? max_expand(L, s+1, p, ep, cap) : NULL); case '-': /* 0 or more repetitions (minimum) */ return min_expand(L, s, p, ep, cap); default: if (!m) return NULL; s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */ } } } }
static const lua_WChar *match (MatchState *ms, const lua_WChar *s, const lua_WChar *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': /* start capture */ if (*(p+1) == ')') /* position capture? */ return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); case ')': /* end capture */ return end_capture(ms, s, p+1); case ESC: /* may be %[0-9] or %b */ if (iswdigit(*(p+1))) { /* capture? */ s = match_capture(ms, s, *(p+1)); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } else if (*(p+1) == 'b') { /* balanced string? */ s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; /* else return match(ms, s, p+4); */ } else goto dflt; /* case default */ case '\0': /* end of pattern */ return s; /* match succeeded */ case '$': if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; default: dflt: { /* it is a pattern item */ const lua_WChar *ep = luaI_classend(ms, p); /* points to what is next */ int m = s<ms->src_end && luaI_singlematch(*s, p, ep); switch (*ep) { case '?': { /* optional */ const lua_WChar *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; /* else return match(ms, s, ep+1); */ } case '*': /* 0 or more repetitions */ return max_expand(ms, s, p, ep); case '+': /* 1 or more repetitions */ return (m ? max_expand(ms, s+1, p, ep) : NULL); case '-': /* 0 or more repetitions (minimum) */ return min_expand(ms, s, p, ep); default: if (!m) return NULL; s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ } } } }
static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); } case ')': { /* end capture */ return end_capture(ms, s, p+1); } case L_ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; /* else return match(ms, s, p+4); */ } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } goto dflt; /* case default */ } } } case '\0': { /* end of pattern */ return s; /* match succeeded */ } case '$': { if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } default: dflt: { /* it is a pattern item */ const char *ep = classend(ms, p); /* points to what is next */ int m = s<ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; /* else return match(ms, s, ep+1); */ } case '*': { /* 0 or more repetitions */ return max_expand(ms, s, p, ep); } case '+': { /* 1 or more repetitions */ return (m ? max_expand(ms, s+1, p, ep) : NULL); } case '-': { /* 0 or more repetitions (minimum) */ return min_expand(ms, s, p, ep); } default: { if (!m) return NULL; s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ } } } } }
static const char * match(struct match_state *ms, const char *s, const char *p) { const char *ep, *res; char previous; if (ms->matchdepth-- == 0) { match_error(ms, "pattern too complex"); return (NULL); } /* using goto's to optimize tail recursion */ init: /* end of pattern? */ if (p != ms->p_end) { switch (*p) { case '(': /* start capture */ if (*(p + 1) == ')') /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; case ')': /* end capture */ s = end_capture(ms, s, p + 1); break; case '$': /* is the '$' the last char in pattern? */ if ((p + 1) != ms->p_end) { /* no; go to default */ goto dflt; } /* check end of string */ s = (s == ms->src_end) ? s : NULL; break; case L_ESC: /* escaped sequences not in the format class[*+?-]? */ switch (*(p + 1)) { case 'b': /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s != NULL) { p += 4; /* return match(ms, s, p + 4); */ goto init; } /* else fail (s == NULL) */ break; case 'f': /* frontier? */ p += 2; if (*p != '[') { match_error(ms, "missing '['" " after '%f' in pattern"); break; } /* points to what is next */ ep = classend(ms, p); if (ms->error != NULL) break; previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && matchbracketclass(uchar(*s), p, ep - 1)) { p = ep; /* return match(ms, s, ep); */ goto init; } /* match failed */ s = NULL; break; case '0' ... '9': /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p + 1))); if (s != NULL) { p += 2; /* return match(ms, s, p + 2) */ goto init; } break; default: goto dflt; } break; default: /* pattern class plus optional suffix */ dflt: /* points to optional suffix */ ep = classend(ms, p); if (ms->error != NULL) break; /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { if (ms->repetitioncounter-- == 0) { match_error(ms, "max repetition items"); s = NULL; /* fail */ /* accept empty? */ } else if (*ep == '*' || *ep == '?' || *ep == '-') { p = ep + 1; /* return match(ms, s, ep + 1); */ goto init; } else { /* '+' or no suffix */ s = NULL; /* fail */ } } else { /* matched once */ /* handle optional suffix */ switch (*ep) { case '?': /* optional */ if ((res = match(ms, s + 1, ep + 1)) != NULL) s = res; else { /* * else return * match(ms, s, ep + 1); */ p = ep + 1; goto init; } break; case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ /* FALLTHROUGH */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; case '-': /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ s++; p = ep; /* return match(ms, s + 1, ep); */ goto init; } } break; } } ms->matchdepth++; return s; }
static const char *match (MatchState *ms, const char *s, const char *p) { if (ms->matchdepth-- == 0) luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ if (p != ms->p_end) { /* end of pattern? */ switch (*p) { case '(': { /* start capture */ if (*(p + 1) == ')') /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; } case ')': { /* end capture */ s = end_capture(ms, s, p + 1); break; } case '$': { if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; } case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p + 1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s != NULL) { p += 4; goto init; /* return match(ms, s, p + 4); */ } /* else fail (s == NULL) */ break; } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && matchbracketclass(uchar(*s), p, ep - 1)) { p = ep; goto init; /* return match(ms, s, ep); */ } s = NULL; /* match failed */ break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p + 1))); if (s != NULL) { p += 2; goto init; /* return match(ms, s, p + 2) */ } break; } default: goto dflt; } break; } default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to optional suffix */ /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ } else /* '+' or no suffix */ s = NULL; /* fail */ } else { /* matched once */ switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; if ((res = match(ms, s + 1, ep + 1)) != NULL) s = res; else { p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ } break; } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ /* go through */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; case '-': /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ } } break; } } } ms->matchdepth++; return s; }
static char *match (char *s, char *p, int level) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': /* start capture */ if (level >= MAX_CAPT) lua_error("too many captures"); capture[level].init = s; capture[level].len = -1; level++; p++; goto init; /* return match(s, p+1, level); */ case ')': { /* end capture */ int l = capture_to_close(level); char *res; capture[l].len = s - capture[l].init; /* close capture */ if ((res = match(s, p+1, level)) == NULL) /* match failed? */ capture[l].len = -1; /* undo capture */ return res; } case ESC: if (isdigit((unsigned char)(*(p+1)))) { /* capture */ int l = check_cap(*(p+1), level); if (strncmp(capture[l].init, s, capture[l].len) == 0) { /* return match(p+2, s+capture[l].len, level); */ p+=2; s+=capture[l].len; goto init; } else return NULL; } else if (*(p+1) == 'b') { /* balanced string */ if (*(p+2) == 0 || *(p+3) == 0) lua_error("bad balanced pattern specification"); s = matchbalance(s, *(p+2), *(p+3)); if (s == NULL) return NULL; else { /* return match(p+4, s, level); */ p+=4; goto init; } } else goto dflt; case '\0': case '$': /* (possibly) end of pattern */ if (*p == 0 || (*(p+1) == 0 && *s == 0)) { num_captures = level; return s; } else goto dflt; default: dflt: { /* it is a pattern item */ int m = luaL_singlematch(*s, p); char *ep = luaL_item_end(p); /* get what is next */ switch (*ep) { case '*': { /* repetition */ char *res; if (m && (res = match(s+1, p, level))) return res; p=ep+1; goto init; /* else return match(s, ep+1, level); */ } case '-': { /* repetition */ char *res; if ((res = match(s, ep+1, level)) != 0) return res; else if (m) { s++; goto init; /* return match(s+1, p, level); */ } else return NULL; } case '?': { /* optional */ char *res; if (m && (res = match(s+1, ep+1, level))) return res; p=ep+1; goto init; /* else return match(s, ep+1, level); */ } default: if (m) { s++; p=ep; goto init; } /* return match(s+1, ep, level); */ else return NULL; } } } }
static const char *match(LuaMatchState *ms, const char *s, const char *p) { init: // using goto's to optimize tail recursion if (p == ms->p_end) // end of pattern? return s; // match succeeded switch (*p) { case '(': { // start capture if (*(p+1) == ')') // position capture? return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); } case ')': { // end capture return end_capture(ms, s, p+1); } case '$': { if ((p+1) == ms->p_end) // is the `$' the last char in pattern? return (s == ms->src_end) ? s : NULL; // check end of string else goto dflt; } case L_ESC: { // escaped sequences not in the format class[*+?-]? switch (*(p+1)) { case 'b': { // balanced string? s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; // else return match(ms, s, p+4); } case 'f': { // frontier? const char *ep; char previous; p += 2; if (*p != '['){ ms->error = "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"; return NULL; } if(!classend(ms, p, &ep)) return NULL; // points to what is next previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; // else return match(ms, s, ep); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { // capture results (%0-%9)? s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; // else return match(ms, s, p+2) } default: goto dflt; } } default: dflt: { // pattern class plus optional suffix const char *ep; int m; if(!classend(ms, p, &ep)) return NULL; // points to what is next m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { // optional const char *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; // else return match(ms, s, ep+1); } case '*': { // 0 or more repetitions return max_expand(ms, s, p, ep); } case '+': { // 1 or more repetitions return (m ? max_expand(ms, s+1, p, ep) : NULL); } case '-': { // 0 or more repetitions (minimum) return min_expand(ms, s, p, ep); } default: { if (!m) return NULL; s++; p=ep; goto init; // else return match(ms, s+1, ep); } } } } }