diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-09-28 15:05:01 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-09-28 15:05:01 -0300 |
commit | 10fffcd80abb2830935a5aa6b1bd1da9b1a77d97 (patch) | |
tree | 2cea1e1b1e5e613e05b6a334e95a27dbdc6e8746 /lstrlib.c | |
parent | 8264dbc2bb42d4119ec54caa55e4bece2d6985d6 (diff) | |
download | lua-10fffcd80abb2830935a5aa6b1bd1da9b1a77d97.tar.gz lua-10fffcd80abb2830935a5aa6b1bd1da9b1a77d97.tar.bz2 lua-10fffcd80abb2830935a5aa6b1bd1da9b1a77d97.zip |
'gmatch' keeps its state in a userdata (keeping the same 'MatchState'
across calls)
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 46 |
1 files changed, 26 insertions, 20 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.232 2015/07/20 16:30:22 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.233 2015/09/26 18:45:03 roberto Exp roberto $ |
3 | ** Standard library for string operations and pattern-matching | 3 | ** Standard library for string operations and pattern-matching |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -677,24 +677,26 @@ static int str_match (lua_State *L) { | |||
677 | } | 677 | } |
678 | 678 | ||
679 | 679 | ||
680 | /* state for 'gmatch' */ | ||
681 | typedef struct GMatchState { | ||
682 | const char *src; /* current position */ | ||
683 | const char *p; /* pattern */ | ||
684 | MatchState ms; /* match state */ | ||
685 | } GMatchState; | ||
686 | |||
687 | |||
680 | static int gmatch_aux (lua_State *L) { | 688 | static int gmatch_aux (lua_State *L) { |
681 | MatchState ms; | 689 | GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); |
682 | size_t ls, lp; | ||
683 | const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); | ||
684 | const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); | ||
685 | const char *src; | 690 | const char *src; |
686 | prepstate(&ms, L, s, ls, p, lp); | 691 | for (src = gm->src; src <= gm->ms.src_end; src++) { |
687 | for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); | ||
688 | src <= ms.src_end; | ||
689 | src++) { | ||
690 | const char *e; | 692 | const char *e; |
691 | reprepstate(&ms); | 693 | reprepstate(&gm->ms); |
692 | if ((e = match(&ms, src, p)) != NULL) { | 694 | if ((e = match(&gm->ms, src, gm->p)) != NULL) { |
693 | lua_Integer newstart = e-s; | 695 | if (e == src) /* empty match? */ |
694 | if (e == src) newstart++; /* empty match? go at least one position */ | 696 | gm->src =src + 1; /* go at least one position */ |
695 | lua_pushinteger(L, newstart); | 697 | else |
696 | lua_replace(L, lua_upvalueindex(3)); | 698 | gm->src = e; |
697 | return push_captures(&ms, src, e); | 699 | return push_captures(&gm->ms, src, e); |
698 | } | 700 | } |
699 | } | 701 | } |
700 | return 0; /* not found */ | 702 | return 0; /* not found */ |
@@ -702,10 +704,14 @@ static int gmatch_aux (lua_State *L) { | |||
702 | 704 | ||
703 | 705 | ||
704 | static int gmatch (lua_State *L) { | 706 | static int gmatch (lua_State *L) { |
705 | luaL_checkstring(L, 1); | 707 | size_t ls, lp; |
706 | luaL_checkstring(L, 2); | 708 | const char *s = luaL_checklstring(L, 1, &ls); |
707 | lua_settop(L, 2); | 709 | const char *p = luaL_checklstring(L, 2, &lp); |
708 | lua_pushinteger(L, 0); | 710 | GMatchState *gm; |
711 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | ||
712 | gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); | ||
713 | prepstate(&gm->ms, L, s, ls, p, lp); | ||
714 | gm->src = s; gm->p = p; | ||
709 | lua_pushcclosure(L, gmatch_aux, 3); | 715 | lua_pushcclosure(L, gmatch_aux, 3); |
710 | return 1; | 716 | return 1; |
711 | } | 717 | } |