diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-01-08 14:22:32 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-01-08 14:22:32 -0200 |
commit | 264659bd53e92969a1e17d65c0266597cde24b5d (patch) | |
tree | 6aba62d2b6ac2a46dc064ea7193c8134200a7d57 /lstrlib.c | |
parent | 4ace93ca6502dd1da38d5c06fa099d229e791ba8 (diff) | |
download | lua-264659bd53e92969a1e17d65c0266597cde24b5d.tar.gz lua-264659bd53e92969a1e17d65c0266597cde24b5d.tar.bz2 lua-264659bd53e92969a1e17d65c0266597cde24b5d.zip |
Optional 'init' argument to 'string.gmatch'
The function 'string.gmatch' now has an optional 'init' argument,
similar to 'string.find' and 'string.match'. Moreover, there was
some reorganization in the manipulation of indices in the string
library.
This commit also includes small janitorial work in the manual
and in comments in the interpreter loop.
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 76 |
1 files changed, 52 insertions, 24 deletions
@@ -60,23 +60,50 @@ static int str_len (lua_State *L) { | |||
60 | } | 60 | } |
61 | 61 | ||
62 | 62 | ||
63 | /* translate a relative string position: negative means back from end */ | 63 | /* |
64 | static lua_Integer posrelat (lua_Integer pos, size_t len) { | 64 | ** translate a relative initial string position |
65 | if (pos >= 0) return pos; | 65 | ** (negative means back from end): clip result to [1, inf). |
66 | else if (0u - (size_t)pos > len) return 0; | 66 | ** The length of any string in Lua must fit in a lua_Integer, |
67 | else return (lua_Integer)len + pos + 1; | 67 | ** so there are no overflows in the casts. |
68 | ** The inverted comparison avoids a possible overflow | ||
69 | ** computing '-pos'. | ||
70 | */ | ||
71 | static size_t posrelatI (lua_Integer pos, size_t len) { | ||
72 | if (pos > 0) | ||
73 | return (size_t)pos; | ||
74 | else if (pos == 0) | ||
75 | return 1; | ||
76 | else if (pos < -(lua_Integer)len) /* inverted comparison */ | ||
77 | return 1; /* clip to 1 */ | ||
78 | else return len + (size_t)pos + 1; | ||
79 | } | ||
80 | |||
81 | |||
82 | /* | ||
83 | ** Gets an optional ending string position from argument 'arg', | ||
84 | ** with default value 'def'. | ||
85 | ** Negative means back from end: clip result to [0, len] | ||
86 | */ | ||
87 | static size_t getendpos (lua_State *L, int arg, lua_Integer def, | ||
88 | size_t len) { | ||
89 | lua_Integer pos = luaL_optinteger(L, arg, def); | ||
90 | if (pos > (lua_Integer)len) | ||
91 | return len; | ||
92 | else if (pos >= 0) | ||
93 | return (size_t)pos; | ||
94 | else if (pos < -(lua_Integer)len) | ||
95 | return 0; | ||
96 | else return len + (size_t)pos + 1; | ||
68 | } | 97 | } |
69 | 98 | ||
70 | 99 | ||
71 | static int str_sub (lua_State *L) { | 100 | static int str_sub (lua_State *L) { |
72 | size_t l; | 101 | size_t l; |
73 | const char *s = luaL_checklstring(L, 1, &l); | 102 | const char *s = luaL_checklstring(L, 1, &l); |
74 | lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); | 103 | size_t start = posrelatI(luaL_checkinteger(L, 2), l); |
75 | lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); | 104 | size_t end = getendpos(L, 3, -1, l); |
76 | if (start < 1) start = 1; | ||
77 | if (end > (lua_Integer)l) end = l; | ||
78 | if (start <= end) | 105 | if (start <= end) |
79 | lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); | 106 | lua_pushlstring(L, s + start - 1, (end - start) + 1); |
80 | else lua_pushliteral(L, ""); | 107 | else lua_pushliteral(L, ""); |
81 | return 1; | 108 | return 1; |
82 | } | 109 | } |
@@ -149,11 +176,10 @@ static int str_rep (lua_State *L) { | |||
149 | static int str_byte (lua_State *L) { | 176 | static int str_byte (lua_State *L) { |
150 | size_t l; | 177 | size_t l; |
151 | const char *s = luaL_checklstring(L, 1, &l); | 178 | const char *s = luaL_checklstring(L, 1, &l); |
152 | lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); | 179 | lua_Integer pi = luaL_optinteger(L, 2, 1); |
153 | lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); | 180 | size_t posi = posrelatI(pi, l); |
181 | size_t pose = getendpos(L, 3, pi, l); | ||
154 | int n, i; | 182 | int n, i; |
155 | if (posi < 1) posi = 1; | ||
156 | if (pose > (lua_Integer)l) pose = l; | ||
157 | if (posi > pose) return 0; /* empty interval; return no values */ | 183 | if (posi > pose) return 0; /* empty interval; return no values */ |
158 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ | 184 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ |
159 | return luaL_error(L, "string slice too long"); | 185 | return luaL_error(L, "string slice too long"); |
@@ -171,8 +197,8 @@ static int str_char (lua_State *L) { | |||
171 | luaL_Buffer b; | 197 | luaL_Buffer b; |
172 | char *p = luaL_buffinitsize(L, &b, n); | 198 | char *p = luaL_buffinitsize(L, &b, n); |
173 | for (i=1; i<=n; i++) { | 199 | for (i=1; i<=n; i++) { |
174 | lua_Integer c = luaL_checkinteger(L, i); | 200 | lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); |
175 | luaL_argcheck(L, uchar(c) == c, i, "value out of range"); | 201 | luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range"); |
176 | p[i - 1] = uchar(c); | 202 | p[i - 1] = uchar(c); |
177 | } | 203 | } |
178 | luaL_pushresultsize(&b, n); | 204 | luaL_pushresultsize(&b, n); |
@@ -695,16 +721,15 @@ static int str_find_aux (lua_State *L, int find) { | |||
695 | size_t ls, lp; | 721 | size_t ls, lp; |
696 | const char *s = luaL_checklstring(L, 1, &ls); | 722 | const char *s = luaL_checklstring(L, 1, &ls); |
697 | const char *p = luaL_checklstring(L, 2, &lp); | 723 | const char *p = luaL_checklstring(L, 2, &lp); |
698 | lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); | 724 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; |
699 | if (init < 1) init = 1; | 725 | if (init > ls) { /* start after string's end? */ |
700 | else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ | ||
701 | lua_pushnil(L); /* cannot find anything */ | 726 | lua_pushnil(L); /* cannot find anything */ |
702 | return 1; | 727 | return 1; |
703 | } | 728 | } |
704 | /* explicit request or no special characters? */ | 729 | /* explicit request or no special characters? */ |
705 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { | 730 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { |
706 | /* do a plain search */ | 731 | /* do a plain search */ |
707 | const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); | 732 | const char *s2 = lmemfind(s + init, ls - init, p, lp); |
708 | if (s2) { | 733 | if (s2) { |
709 | lua_pushinteger(L, (s2 - s) + 1); | 734 | lua_pushinteger(L, (s2 - s) + 1); |
710 | lua_pushinteger(L, (s2 - s) + lp); | 735 | lua_pushinteger(L, (s2 - s) + lp); |
@@ -713,7 +738,7 @@ static int str_find_aux (lua_State *L, int find) { | |||
713 | } | 738 | } |
714 | else { | 739 | else { |
715 | MatchState ms; | 740 | MatchState ms; |
716 | const char *s1 = s + init - 1; | 741 | const char *s1 = s + init; |
717 | int anchor = (*p == '^'); | 742 | int anchor = (*p == '^'); |
718 | if (anchor) { | 743 | if (anchor) { |
719 | p++; lp--; /* skip anchor character */ | 744 | p++; lp--; /* skip anchor character */ |
@@ -777,11 +802,14 @@ static int gmatch (lua_State *L) { | |||
777 | size_t ls, lp; | 802 | size_t ls, lp; |
778 | const char *s = luaL_checklstring(L, 1, &ls); | 803 | const char *s = luaL_checklstring(L, 1, &ls); |
779 | const char *p = luaL_checklstring(L, 2, &lp); | 804 | const char *p = luaL_checklstring(L, 2, &lp); |
805 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; | ||
780 | GMatchState *gm; | 806 | GMatchState *gm; |
781 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | 807 | lua_settop(L, 2); /* keep strings on closure to avoid being collected */ |
782 | gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); | 808 | gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); |
809 | if (init > ls) /* start after string's end? */ | ||
810 | init = ls + 1; /* avoid overflows in 's + init' */ | ||
783 | prepstate(&gm->ms, L, s, ls, p, lp); | 811 | prepstate(&gm->ms, L, s, ls, p, lp); |
784 | gm->src = s; gm->p = p; gm->lastmatch = NULL; | 812 | gm->src = s + init; gm->p = p; gm->lastmatch = NULL; |
785 | lua_pushcclosure(L, gmatch_aux, 3); | 813 | lua_pushcclosure(L, gmatch_aux, 3); |
786 | return 1; | 814 | return 1; |
787 | } | 815 | } |
@@ -1572,7 +1600,7 @@ static int str_unpack (lua_State *L) { | |||
1572 | const char *fmt = luaL_checkstring(L, 1); | 1600 | const char *fmt = luaL_checkstring(L, 1); |
1573 | size_t ld; | 1601 | size_t ld; |
1574 | const char *data = luaL_checklstring(L, 2, &ld); | 1602 | const char *data = luaL_checklstring(L, 2, &ld); |
1575 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | 1603 | size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; |
1576 | int n = 0; /* number of results */ | 1604 | int n = 0; /* number of results */ |
1577 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | 1605 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); |
1578 | initheader(L, &h); | 1606 | initheader(L, &h); |