diff options
-rw-r--r-- | lstrlib.c | 76 | ||||
-rw-r--r-- | lvm.c | 14 | ||||
-rw-r--r-- | manual/manual.of | 42 | ||||
-rw-r--r-- | testes/pm.lua | 29 | ||||
-rw-r--r-- | testes/strings.lua | 5 | ||||
-rw-r--r-- | testes/tpack.lua | 2 |
6 files changed, 116 insertions, 52 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); |
@@ -991,7 +991,8 @@ void luaV_finishOp (lua_State *L) { | |||
991 | 991 | ||
992 | /* | 992 | /* |
993 | ** Protect code that will finish the loop (returns) or can only raise | 993 | ** Protect code that will finish the loop (returns) or can only raise |
994 | ** errors. | 994 | ** errors. (That is, it will not return to the interpreter main loop |
995 | ** after changing the stack or hooks.) | ||
995 | */ | 996 | */ |
996 | #define halfProtect(exp) (savepc(L), (exp)) | 997 | #define halfProtect(exp) (savepc(L), (exp)) |
997 | 998 | ||
@@ -1607,7 +1608,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1607 | L->top = ra; | 1608 | L->top = ra; |
1608 | halfProtect(luaD_poscall(L, ci, 0)); /* no hurry... */ | 1609 | halfProtect(luaD_poscall(L, ci, 0)); /* no hurry... */ |
1609 | } | 1610 | } |
1610 | else { | 1611 | else { /* do the 'poscall' here */ |
1611 | int nres = ci->nresults; | 1612 | int nres = ci->nresults; |
1612 | L->ci = ci->previous; /* back to caller */ | 1613 | L->ci = ci->previous; /* back to caller */ |
1613 | L->top = base - 1; | 1614 | L->top = base - 1; |
@@ -1621,7 +1622,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1621 | L->top = ra + 1; | 1622 | L->top = ra + 1; |
1622 | halfProtect(luaD_poscall(L, ci, 1)); /* no hurry... */ | 1623 | halfProtect(luaD_poscall(L, ci, 1)); /* no hurry... */ |
1623 | } | 1624 | } |
1624 | else { | 1625 | else { /* do the 'poscall' here */ |
1625 | int nres = ci->nresults; | 1626 | int nres = ci->nresults; |
1626 | L->ci = ci->previous; /* back to caller */ | 1627 | L->ci = ci->previous; /* back to caller */ |
1627 | if (nres == 0) | 1628 | if (nres == 0) |
@@ -1652,8 +1653,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1652 | lua_Integer ilimit, initv; | 1653 | lua_Integer ilimit, initv; |
1653 | int stopnow; | 1654 | int stopnow; |
1654 | if (unlikely(!forlimit(plimit, &ilimit, 1, &stopnow))) { | 1655 | if (unlikely(!forlimit(plimit, &ilimit, 1, &stopnow))) { |
1655 | savestate(L, ci); /* for the error message */ | 1656 | savestate(L, ci); /* for the error message */ |
1656 | luaG_forerror(L, plimit, "limit"); | 1657 | luaG_forerror(L, plimit, "limit"); |
1657 | } | 1658 | } |
1658 | initv = (stopnow ? 0 : ivalue(init)); | 1659 | initv = (stopnow ? 0 : ivalue(init)); |
1659 | setivalue(plimit, ilimit); | 1660 | setivalue(plimit, ilimit); |
@@ -1717,8 +1718,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1717 | vmbreak; | 1718 | vmbreak; |
1718 | } | 1719 | } |
1719 | vmcase(OP_TFORPREP) { | 1720 | vmcase(OP_TFORPREP) { |
1720 | /* is 'toclose' not nil? */ | 1721 | if (!ttisnil(s2v(ra + 3))) { /* is 'toclose' not nil? */ |
1721 | if (!ttisnil(s2v(ra + 3))) { | ||
1722 | /* create to-be-closed upvalue for it */ | 1722 | /* create to-be-closed upvalue for it */ |
1723 | halfProtect(luaF_newtbcupval(L, ra + 3)); | 1723 | halfProtect(luaF_newtbcupval(L, ra + 3)); |
1724 | } | 1724 | } |
diff --git a/manual/manual.of b/manual/manual.of index b9ab1ebe..421d04de 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -83,25 +83,10 @@ it usually represents the absence of a useful value. | |||
83 | The type @emph{boolean} has two values, @false and @true. | 83 | The type @emph{boolean} has two values, @false and @true. |
84 | Both @nil and @false make a condition false; | 84 | Both @nil and @false make a condition false; |
85 | any other value makes it true. | 85 | any other value makes it true. |
86 | The type @emph{number} represents both | ||
87 | integer numbers and real (floating-point) numbers. | ||
88 | The type @emph{string} represents immutable sequences of bytes. | ||
89 | @index{eight-bit clean} | ||
90 | Lua is 8-bit clean: | ||
91 | strings can contain any 8-bit value, | ||
92 | including @x{embedded zeros} (@Char{\0}). | ||
93 | Lua is also encoding-agnostic; | ||
94 | it makes no assumptions about the contents of a string. | ||
95 | 86 | ||
96 | The type @emph{number} uses two internal representations, | 87 | The type @emph{number} represents both |
97 | or two @x{subtypes}, | 88 | integer numbers and real (floating-point) numbers, |
98 | one called @def{integer} and the other called @def{float}. | 89 | using two @x{subtypes}: @def{integer} and @def{float}. |
99 | Lua has explicit rules about when each representation is used, | ||
100 | but it also converts between them automatically as needed @see{coercion}. | ||
101 | Therefore, | ||
102 | the programmer may choose to mostly ignore the difference | ||
103 | between integers and floats | ||
104 | or to assume complete control over the representation of each number. | ||
105 | Standard Lua uses 64-bit integers and double-precision (64-bit) floats, | 90 | Standard Lua uses 64-bit integers and double-precision (64-bit) floats, |
106 | but you can also compile Lua so that it | 91 | but you can also compile Lua so that it |
107 | uses 32-bit integers and/or single-precision (32-bit) floats. | 92 | uses 32-bit integers and/or single-precision (32-bit) floats. |
@@ -110,6 +95,22 @@ is particularly attractive | |||
110 | for small machines and embedded systems. | 95 | for small machines and embedded systems. |
111 | (See macro @id{LUA_32BITS} in file @id{luaconf.h}.) | 96 | (See macro @id{LUA_32BITS} in file @id{luaconf.h}.) |
112 | 97 | ||
98 | Lua has explicit rules about when each subtype is used, | ||
99 | but it also converts between them automatically as needed @see{coercion}. | ||
100 | Therefore, | ||
101 | the programmer may choose to mostly ignore the difference | ||
102 | between integers and floats | ||
103 | or to assume complete control over the representation of each number. | ||
104 | |||
105 | The type @emph{string} represents immutable sequences of bytes. | ||
106 | @index{eight-bit clean} | ||
107 | Lua is 8-bit clean: | ||
108 | strings can contain any 8-bit value, | ||
109 | including @x{embedded zeros} (@Char{\0}). | ||
110 | Lua is also encoding-agnostic; | ||
111 | it makes no assumptions about the contents of a string. | ||
112 | The length of any string in Lua must fit in a Lua integer. | ||
113 | |||
113 | Lua can call (and manipulate) functions written in Lua and | 114 | Lua can call (and manipulate) functions written in Lua and |
114 | functions written in C @see{functioncall}. | 115 | functions written in C @see{functioncall}. |
115 | Both are represented by the type @emph{function}. | 116 | Both are represented by the type @emph{function}. |
@@ -6788,13 +6789,16 @@ the string argument should not contain @x{embedded zeros}. | |||
6788 | 6789 | ||
6789 | } | 6790 | } |
6790 | 6791 | ||
6791 | @LibEntry{string.gmatch (s, pattern)| | 6792 | @LibEntry{string.gmatch (s, pattern [, init])| |
6792 | Returns an iterator function that, | 6793 | Returns an iterator function that, |
6793 | each time it is called, | 6794 | each time it is called, |
6794 | returns the next captures from @id{pattern} @see{pm} | 6795 | returns the next captures from @id{pattern} @see{pm} |
6795 | over the string @id{s}. | 6796 | over the string @id{s}. |
6796 | If @id{pattern} specifies no captures, | 6797 | If @id{pattern} specifies no captures, |
6797 | then the whole match is produced in each call. | 6798 | then the whole match is produced in each call. |
6799 | A third, optional numeric argument @id{init} specifies | ||
6800 | where to start the search; | ||
6801 | its default value @N{is 1} and can be negative. | ||
6798 | 6802 | ||
6799 | As an example, the following loop | 6803 | As an example, the following loop |
6800 | will iterate over all the words from string @id{s}, | 6804 | will iterate over all the words from string @id{s}, |
diff --git a/testes/pm.lua b/testes/pm.lua index 1afaccf6..8cc8772e 100644 --- a/testes/pm.lua +++ b/testes/pm.lua | |||
@@ -297,6 +297,35 @@ for k,v in pairs(t) do assert(k+1 == v+0); a=a+1 end | |||
297 | assert(a == 3) | 297 | assert(a == 3) |
298 | 298 | ||
299 | 299 | ||
300 | do -- init parameter in gmatch | ||
301 | local s = 0 | ||
302 | for k in string.gmatch("10 20 30", "%d+", 3) do | ||
303 | s = s + tonumber(k) | ||
304 | end | ||
305 | assert(s == 50) | ||
306 | |||
307 | s = 0 | ||
308 | for k in string.gmatch("11 21 31", "%d+", -4) do | ||
309 | s = s + tonumber(k) | ||
310 | end | ||
311 | assert(s == 32) | ||
312 | |||
313 | -- there is an empty string at the end of the subject | ||
314 | s = 0 | ||
315 | for k in string.gmatch("11 21 31", "%w*", 9) do | ||
316 | s = s + 1 | ||
317 | end | ||
318 | assert(s == 1) | ||
319 | |||
320 | -- there are no empty strings after the end of the subject | ||
321 | s = 0 | ||
322 | for k in string.gmatch("11 21 31", "%w*", 10) do | ||
323 | s = s + 1 | ||
324 | end | ||
325 | assert(s == 0) | ||
326 | end | ||
327 | |||
328 | |||
300 | -- tests for `%f' (`frontiers') | 329 | -- tests for `%f' (`frontiers') |
301 | 330 | ||
302 | assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x") | 331 | assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x") |
diff --git a/testes/strings.lua b/testes/strings.lua index 587a0e06..88480924 100644 --- a/testes/strings.lua +++ b/testes/strings.lua | |||
@@ -94,6 +94,11 @@ assert(string.char(string.byte("\xe4l\0ķu", 1, -1)) == "\xe4l\0ķu") | |||
94 | assert(string.char(string.byte("\xe4l\0ķu", 1, 0)) == "") | 94 | assert(string.char(string.byte("\xe4l\0ķu", 1, 0)) == "") |
95 | assert(string.char(string.byte("\xe4l\0ķu", -10, 100)) == "\xe4l\0ķu") | 95 | assert(string.char(string.byte("\xe4l\0ķu", -10, 100)) == "\xe4l\0ķu") |
96 | 96 | ||
97 | checkerror("out of range", string.char, 256) | ||
98 | checkerror("out of range", string.char, -1) | ||
99 | checkerror("out of range", string.char, math.maxinteger) | ||
100 | checkerror("out of range", string.char, math.mininteger) | ||
101 | |||
97 | assert(string.upper("ab\0c") == "AB\0C") | 102 | assert(string.upper("ab\0c") == "AB\0C") |
98 | assert(string.lower("\0ABCc%$") == "\0abcc%$") | 103 | assert(string.lower("\0ABCc%$") == "\0abcc%$") |
99 | assert(string.rep('teste', 0) == '') | 104 | assert(string.rep('teste', 0) == '') |
diff --git a/testes/tpack.lua b/testes/tpack.lua index 4c5fc7f7..2b9953f8 100644 --- a/testes/tpack.lua +++ b/testes/tpack.lua | |||
@@ -314,9 +314,7 @@ do -- testing initial position | |||
314 | for i = 1, #x + 1 do | 314 | for i = 1, #x + 1 do |
315 | assert(unpack("c0", x, i) == "") | 315 | assert(unpack("c0", x, i) == "") |
316 | end | 316 | end |
317 | checkerror("out of string", unpack, "c0", x, 0) | ||
318 | checkerror("out of string", unpack, "c0", x, #x + 2) | 317 | checkerror("out of string", unpack, "c0", x, #x + 2) |
319 | checkerror("out of string", unpack, "c0", x, -(#x + 1)) | ||
320 | 318 | ||
321 | end | 319 | end |
322 | 320 | ||