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 *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 void io_read() { int32 arg = FIRSTARG; LuaFile *f = (LuaFile *)getfileparam(FINPUT, &arg); char *buff; const char *p = luaL_opt_string(arg, "[^\n]*{\n}"); int inskip = 0; // to control {skips} int c = NEED_OTHER; luaL_resetbuffer(); while (*p) { if (*p == '{') { inskip++; p++; } else if (*p == '}') { if (inskip == 0) lua_error("unbalanced braces in read pattern"); inskip--; p++; } else { const char *ep; // get what is next int m; // match result if (c == NEED_OTHER) { char z; if (f->read(&z, 1) != 1) c = EOF; else c = z; } m = luaI_singlematch((c == EOF) ? 0 : (char)c, p, &ep); if (m) { if (inskip == 0) luaL_addchar(c); c = NEED_OTHER; } switch (*ep) { case '*': // repetition if (!m) p = ep + 1; // else stay in (repeat) the same item break; case '?': // optional p = ep + 1; // continues reading the pattern break; default: if (m) p = ep; // continues reading the pattern else goto break_while; // pattern fails } } } break_while: if (c >= 0) // not EOF nor NEED_OTHER? f->seek(-1, SEEK_CUR); luaL_addchar(0); buff = luaL_buffer(); if (*buff != 0 || *p == 0) // read something or did not fail? lua_pushstring(buff); }
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 *min_expand (MatchState *ms, const lua_WChar *s, const lua_WChar *p, const lua_WChar *ep) { for (;;) { const lua_WChar *res = match(ms, s, ep+1); if (res != NULL) return res; else if (s<ms->src_end && luaI_singlematch(*s, p, ep)) s++; /* try with one more repetition */ else return NULL; } }
static const char *min_expand (lua_State *L, const char *s, const char *p, const char *ep, struct Capture *cap) { for (;;) { const char *res = match(L, s, ep+1, cap); if (res != NULL) return res; else if (s<cap->src_end && luaI_singlematch((unsigned char)*s, p, ep)) s++; /* try with one more repetition */ else return NULL; } }
static const lua_WChar *max_expand (MatchState *ms, const lua_WChar *s, const lua_WChar *p, const lua_WChar *ep) { sint32 i = 0; /* counts maximum expand for item */ while ((s+i)<ms->src_end && luaI_singlematch(*(s+i), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const lua_WChar *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; }
static const char *max_expand (lua_State *L, const char *s, const char *p, const char *ep, struct Capture *cap) { long i = 0; /* counts maximum expand for item */ while ((s+i)<cap->src_end && luaI_singlematch((unsigned char)*(s+i), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(L, (s+i), ep+1, cap); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; }
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 void io_read (void) { int arg = FIRSTARG; FILE *f = getfileparam(FINPUT, &arg); char *buff; char *p = luaL_opt_string(arg, "[^\n]*{\n}"); int inskip = 0; /* to control {skips} */ int c = NEED_OTHER; luaL_resetbuffer(); while (*p) { if (*p == '{') { inskip++; p++; } else if (*p == '}') { if (inskip == 0) lua_error("unbalanced braces in read pattern"); inskip--; p++; } else { char *ep; /* get what is next */ int m; /* match result */ if (c == NEED_OTHER) c = getc(f); m = luaI_singlematch((c == EOF) ? 0 : (char)c, p, &ep); if (m) { if (inskip == 0) luaL_addchar(c); c = NEED_OTHER; } switch (*ep) { case '*': /* repetition */ if (!m) p = ep+1; /* else stay in (repeat) the same item */ break; case '?': /* optional */ p = ep+1; /* continues reading the pattern */ break; default: if (m) p = ep; /* continues reading the pattern */ else goto break_while; /* pattern fails */ } } } break_while: if (c >= 0) /* not EOF nor NEED_OTHER? */ ungetc(c, f); luaL_addchar(0); buff = luaL_buffer(); if (*buff != 0 || *p == 0) /* read something or did not fail? */ lua_pushstring(buff); }
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); */ } } } } }