aboutsummaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-01-08 14:22:32 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-01-08 14:22:32 -0200
commit264659bd53e92969a1e17d65c0266597cde24b5d (patch)
tree6aba62d2b6ac2a46dc064ea7193c8134200a7d57 /lstrlib.c
parent4ace93ca6502dd1da38d5c06fa099d229e791ba8 (diff)
downloadlua-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.c76
1 files changed, 52 insertions, 24 deletions
diff --git a/lstrlib.c b/lstrlib.c
index dde868c0..41ebc523 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -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/*
64static 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*/
71static 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*/
87static 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
71static int str_sub (lua_State *L) { 100static 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) {
149static int str_byte (lua_State *L) { 176static 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);