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 int read_pattern (lua_State *L, FILE *f, const char *p) { int inskip = 0; /* {skip} level */ int c = NEED_OTHER; luaL_Buffer b; luaL_buffinit(L, &b); while (*p != '\0') { switch (*p) { case '{': inskip++; p++; continue; case '}': if (!inskip) lua_error(L, "unbalanced braces in read pattern"); inskip--; p++; continue; default: { const char *ep = luaI_classend(L, p); /* get what is next */ int m; /* match result */ if (c == NEED_OTHER) c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); if (m) { if (!inskip) luaL_putchar(&b, c); c = NEED_OTHER; } switch (*ep) { case '+': /* repetition (1 or more) */ if (!m) goto break_while; /* pattern fails? */ /* else go through */ case '*': /* repetition (0 or more) */ while (m) { /* reads the same item until it fails */ c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); if (m && !inskip) luaL_putchar(&b, c); } /* go through to continue reading the pattern */ case '?': /* optional */ p = ep+1; /* continues reading the pattern */ continue; default: if (!m) goto break_while; /* pattern fails? */ p = ep; /* else continues reading the pattern */ } } } } break_while: if (c != NEED_OTHER) ungetc(c, f); luaL_pushresult(&b); /* close buffer */ return (*p == '\0'); }
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 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 `[' after `%%f' in pattern"); ep = luaI_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, *(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 = luaI_classend(ms, p); /* points to what is next */ int m = s<ms->src_end && luaI_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); */ } } } } }