aboutsummaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lstrlib.c')
-rw-r--r--lstrlib.c130
1 files changed, 84 insertions, 46 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 6230cd0c..53ed80a3 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -660,25 +660,46 @@ static const char *lmemfind (const char *s1, size_t l1,
660} 660}
661 661
662 662
663static void push_onecapture (MatchState *ms, int i, const char *s, 663/*
664 const char *e) { 664** get information about the i-th capture. If there are no captures
665** and 'i==0', return information about the whole match, which
666** is the range 's'..'e'. If the capture is a string, return
667** its length and put its address in '*cap'. If it is an integer
668** (a position), push it on the stack and return CAP_POSITION.
669*/
670static size_t get_onecapture (MatchState *ms, int i, const char *s,
671 const char *e, const char **cap) {
665 if (i >= ms->level) { 672 if (i >= ms->level) {
666 if (i == 0) /* ms->level == 0, too */ 673 if (i != 0)
667 lua_pushlstring(ms->L, s, e - s); /* add whole match */
668 else
669 luaL_error(ms->L, "invalid capture index %%%d", i + 1); 674 luaL_error(ms->L, "invalid capture index %%%d", i + 1);
675 *cap = s;
676 return e - s;
670 } 677 }
671 else { 678 else {
672 ptrdiff_t l = ms->capture[i].len; 679 ptrdiff_t capl = ms->capture[i].len;
673 if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); 680 *cap = ms->capture[i].init;
674 if (l == CAP_POSITION) 681 if (capl == CAP_UNFINISHED)
682 luaL_error(ms->L, "unfinished capture");
683 else if (capl == CAP_POSITION)
675 lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); 684 lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
676 else 685 return capl;
677 lua_pushlstring(ms->L, ms->capture[i].init, l);
678 } 686 }
679} 687}
680 688
681 689
690/*
691** Push the i-th capture on the stack.
692*/
693static void push_onecapture (MatchState *ms, int i, const char *s,
694 const char *e) {
695 const char *cap;
696 ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
697 if (l != CAP_POSITION)
698 lua_pushlstring(ms->L, cap, l);
699 /* else position was already pushed */
700}
701
702
682static int push_captures (MatchState *ms, const char *s, const char *e) { 703static int push_captures (MatchState *ms, const char *s, const char *e) {
683 int i; 704 int i;
684 int nlevels = (ms->level == 0 && s) ? 1 : ms->level; 705 int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
@@ -817,60 +838,72 @@ static int gmatch (lua_State *L) {
817 838
818static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, 839static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
819 const char *e) { 840 const char *e) {
820 size_t l, i; 841 size_t l;
821 lua_State *L = ms->L; 842 lua_State *L = ms->L;
822 const char *news = lua_tolstring(L, 3, &l); 843 const char *news = lua_tolstring(L, 3, &l);
823 for (i = 0; i < l; i++) { 844 const char *p;
824 if (news[i] != L_ESC) 845 while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
825 luaL_addchar(b, news[i]); 846 luaL_addlstring(b, news, p - news);
826 else { 847 p++; /* skip ESC */
827 i++; /* skip ESC */ 848 if (*p == L_ESC) /* '%%' */
828 if (!isdigit(uchar(news[i]))) { 849 luaL_addchar(b, *p);
829 if (news[i] != L_ESC) 850 else if (*p == '0') /* '%0' */
830 luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); 851 luaL_addlstring(b, s, e - s);
831 luaL_addchar(b, news[i]); 852 else if (isdigit(uchar(*p))) { /* '%n' */
832 } 853 const char *cap;
833 else if (news[i] == '0') 854 ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
834 luaL_addlstring(b, s, e - s); 855 if (resl == CAP_POSITION)
835 else { 856 luaL_addvalue(b); /* add position to accumulated result */
836 push_onecapture(ms, news[i] - '1', s, e); 857 else
837 luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ 858 luaL_addlstring(b, cap, resl);
838 lua_remove(L, -2); /* remove original value */
839 luaL_addvalue(b); /* add capture to accumulated result */
840 }
841 } 859 }
860 else
861 luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
862 l -= p + 1 - news;
863 news = p + 1;
842 } 864 }
865 luaL_addlstring(b, news, l);
843} 866}
844 867
845 868
846static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, 869/*
847 const char *e, int tr) { 870** Add the replacement value to the string buffer 'b'.
871** Return true if the original string was changed. (Function calls and
872** table indexing resulting in nil or false do not change the subject.)
873*/
874static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
875 const char *e, int tr) {
848 lua_State *L = ms->L; 876 lua_State *L = ms->L;
849 switch (tr) { 877 switch (tr) {
850 case LUA_TFUNCTION: { 878 case LUA_TFUNCTION: { /* call the function */
851 int n; 879 int n;
852 lua_pushvalue(L, 3); 880 lua_pushvalue(L, 3); /* push the function */
853 n = push_captures(ms, s, e); 881 n = push_captures(ms, s, e); /* all captures as arguments */
854 lua_call(L, n, 1); 882 lua_call(L, n, 1); /* call it */
855 break; 883 break;
856 } 884 }
857 case LUA_TTABLE: { 885 case LUA_TTABLE: { /* index the table */
858 push_onecapture(ms, 0, s, e); 886 push_onecapture(ms, 0, s, e); /* first capture is the index */
859 lua_gettable(L, 3); 887 lua_gettable(L, 3);
860 break; 888 break;
861 } 889 }
862 default: { /* LUA_TNUMBER or LUA_TSTRING */ 890 default: { /* LUA_TNUMBER or LUA_TSTRING */
863 add_s(ms, b, s, e); 891 add_s(ms, b, s, e); /* add value to the buffer */
864 return; 892 return 1; /* something changed */
865 } 893 }
866 } 894 }
867 if (!lua_toboolean(L, -1)) { /* nil or false? */ 895 if (!lua_toboolean(L, -1)) { /* nil or false? */
868 lua_pop(L, 1); 896 lua_pop(L, 1); /* remove value */
869 lua_pushlstring(L, s, e - s); /* keep original text */ 897 luaL_addlstring(b, s, e - s); /* keep original text */
898 return 0; /* no changes */
870 } 899 }
871 else if (!lua_isstring(L, -1)) 900 else if (!lua_isstring(L, -1))
872 luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); 901 return luaL_error(L, "invalid replacement value (a %s)",
873 luaL_addvalue(b); /* add result to accumulator */ 902 luaL_typename(L, -1));
903 else {
904 luaL_addvalue(b); /* add result to accumulator */
905 return 1; /* something changed */
906 }
874} 907}
875 908
876 909
@@ -883,6 +916,7 @@ static int str_gsub (lua_State *L) {
883 lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ 916 lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
884 int anchor = (*p == '^'); 917 int anchor = (*p == '^');
885 lua_Integer n = 0; /* replacement count */ 918 lua_Integer n = 0; /* replacement count */
919 int changed = 0; /* change flag */
886 MatchState ms; 920 MatchState ms;
887 luaL_Buffer b; 921 luaL_Buffer b;
888 luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || 922 luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -898,7 +932,7 @@ static int str_gsub (lua_State *L) {
898 reprepstate(&ms); /* (re)prepare state for new match */ 932 reprepstate(&ms); /* (re)prepare state for new match */
899 if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ 933 if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
900 n++; 934 n++;
901 add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ 935 changed = add_value(&ms, &b, src, e, tr) | changed;
902 src = lastmatch = e; 936 src = lastmatch = e;
903 } 937 }
904 else if (src < ms.src_end) /* otherwise, skip one character */ 938 else if (src < ms.src_end) /* otherwise, skip one character */
@@ -906,8 +940,12 @@ static int str_gsub (lua_State *L) {
906 else break; /* end of subject */ 940 else break; /* end of subject */
907 if (anchor) break; 941 if (anchor) break;
908 } 942 }
909 luaL_addlstring(&b, src, ms.src_end-src); 943 if (!changed) /* no changes? */
910 luaL_pushresult(&b); 944 lua_pushvalue(L, 1); /* return original string */
945 else { /* something changed */
946 luaL_addlstring(&b, src, ms.src_end-src);
947 luaL_pushresult(&b); /* create and return new string */
948 }
911 lua_pushinteger(L, n); /* number of substitutions */ 949 lua_pushinteger(L, n); /* number of substitutions */
912 return 2; 950 return 2;
913} 951}