diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-03-31 16:07:42 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-03-31 16:07:42 -0300 |
commit | 783aa8a9da5f32eb14b39d9332b41fa01ef81d52 (patch) | |
tree | 59bb622e13fb95b2c4b0e71c62d0ed67381ffc68 /lstrlib.c | |
parent | 8d4feb504f34c182ad991102d5ccd974b3a5f1b8 (diff) | |
download | lua-783aa8a9da5f32eb14b39d9332b41fa01ef81d52.tar.gz lua-783aa8a9da5f32eb14b39d9332b41fa01ef81d52.tar.bz2 lua-783aa8a9da5f32eb14b39d9332b41fa01ef81d52.zip |
new way to avoid infinite loops in empty matches: "Python rule"
("Empty matches for the pattern are replaced only when not
adjacent to a previous match")
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 16 |
1 files changed, 8 insertions, 8 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.241 2016/03/23 17:12:17 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.242 2016/03/23 18:08:26 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 | */ |
@@ -681,6 +681,7 @@ static int str_match (lua_State *L) { | |||
681 | typedef struct GMatchState { | 681 | typedef struct GMatchState { |
682 | const char *src; /* current position */ | 682 | const char *src; /* current position */ |
683 | const char *p; /* pattern */ | 683 | const char *p; /* pattern */ |
684 | const char *lastmatch; /* end of last match */ | ||
684 | MatchState ms; /* match state */ | 685 | MatchState ms; /* match state */ |
685 | } GMatchState; | 686 | } GMatchState; |
686 | 687 | ||
@@ -692,9 +693,8 @@ static int gmatch_aux (lua_State *L) { | |||
692 | for (src = gm->src; src <= gm->ms.src_end; src++) { | 693 | for (src = gm->src; src <= gm->ms.src_end; src++) { |
693 | const char *e; | 694 | const char *e; |
694 | reprepstate(&gm->ms); | 695 | reprepstate(&gm->ms); |
695 | if ((e = match(&gm->ms, src, gm->p)) != NULL) { | 696 | if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { |
696 | /* in empty matches, advance at least one position */ | 697 | gm->src = gm->lastmatch = e; |
697 | gm->src = (e == src) ? src + 1 : e; | ||
698 | return push_captures(&gm->ms, src, e); | 698 | return push_captures(&gm->ms, src, e); |
699 | } | 699 | } |
700 | } | 700 | } |
@@ -710,7 +710,7 @@ static int gmatch (lua_State *L) { | |||
710 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | 710 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ |
711 | gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); | 711 | gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); |
712 | prepstate(&gm->ms, L, s, ls, p, lp); | 712 | prepstate(&gm->ms, L, s, ls, p, lp); |
713 | gm->src = s; gm->p = p; | 713 | gm->src = s; gm->p = p; gm->lastmatch = NULL; |
714 | lua_pushcclosure(L, gmatch_aux, 3); | 714 | lua_pushcclosure(L, gmatch_aux, 3); |
715 | return 1; | 715 | return 1; |
716 | } | 716 | } |
@@ -779,6 +779,7 @@ static int str_gsub (lua_State *L) { | |||
779 | size_t srcl, lp; | 779 | size_t srcl, lp; |
780 | const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ | 780 | const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ |
781 | const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ | 781 | const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ |
782 | const char *lastmatch = NULL; /* end of last match */ | ||
782 | int tr = lua_type(L, 3); /* replacement type */ | 783 | int tr = lua_type(L, 3); /* replacement type */ |
783 | lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ | 784 | lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ |
784 | int anchor = (*p == '^'); | 785 | int anchor = (*p == '^'); |
@@ -796,12 +797,11 @@ static int str_gsub (lua_State *L) { | |||
796 | while (n < max_s) { | 797 | while (n < max_s) { |
797 | const char *e; | 798 | const char *e; |
798 | reprepstate(&ms); /* (re)prepare state for new match */ | 799 | reprepstate(&ms); /* (re)prepare state for new match */ |
799 | if ((e = match(&ms, src, p)) != NULL) { /* match? */ | 800 | if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ |
800 | n++; | 801 | n++; |
801 | add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ | 802 | add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ |
803 | src = lastmatch = e; | ||
802 | } | 804 | } |
803 | if (e && e>src) /* non empty match? */ | ||
804 | src = e; /* skip it */ | ||
805 | else if (src < ms.src_end) /* otherwise, skip one character */ | 805 | else if (src < ms.src_end) /* otherwise, skip one character */ |
806 | luaL_addchar(&b, *src++); | 806 | luaL_addchar(&b, *src++); |
807 | else break; /* end of subject */ | 807 | else break; /* end of subject */ |