diff options
| author | Li Jin <dragon-fly@qq.com> | 2020-06-22 16:50:40 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2020-06-22 16:50:40 +0800 |
| commit | cd2b60b101a398cb9356d746364e70eaed1860f1 (patch) | |
| tree | a1fe71b76faabc4883f16905a94164ce5c23e692 /src/lua/lstrlib.c | |
| parent | 88c1052e700f38cf3d8ad82d469da4c487760b7e (diff) | |
| download | yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.tar.gz yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.tar.bz2 yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.zip | |
add support for local variable declared with attribute 'close' and 'const' for Lua 5.4.
Diffstat (limited to '')
| -rw-r--r-- | src/lua/lstrlib.c (renamed from src/lua-5.3/lstrlib.c) | 483 |
1 files changed, 352 insertions, 131 deletions
diff --git a/src/lua-5.3/lstrlib.c b/src/lua/lstrlib.c index b4bed7e..2ba8bde 100644 --- a/src/lua-5.3/lstrlib.c +++ b/src/lua/lstrlib.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ | 2 | ** $Id: lstrlib.c $ |
| 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 | */ |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <float.h> | 14 | #include <float.h> |
| 15 | #include <limits.h> | 15 | #include <limits.h> |
| 16 | #include <locale.h> | 16 | #include <locale.h> |
| 17 | #include <math.h> | ||
| 17 | #include <stddef.h> | 18 | #include <stddef.h> |
| 18 | #include <stdio.h> | 19 | #include <stdio.h> |
| 19 | #include <stdlib.h> | 20 | #include <stdlib.h> |
| @@ -59,23 +60,50 @@ static int str_len (lua_State *L) { | |||
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | 62 | ||
| 62 | /* translate a relative string position: negative means back from end */ | 63 | /* |
| 63 | static lua_Integer posrelat (lua_Integer pos, size_t len) { | 64 | ** translate a relative initial string position |
| 64 | if (pos >= 0) return pos; | 65 | ** (negative means back from end): clip result to [1, inf). |
| 65 | else if (0u - (size_t)pos > len) return 0; | 66 | ** The length of any string in Lua must fit in a lua_Integer, |
| 66 | 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; | ||
| 67 | } | 97 | } |
| 68 | 98 | ||
| 69 | 99 | ||
| 70 | static int str_sub (lua_State *L) { | 100 | static int str_sub (lua_State *L) { |
| 71 | size_t l; | 101 | size_t l; |
| 72 | const char *s = luaL_checklstring(L, 1, &l); | 102 | const char *s = luaL_checklstring(L, 1, &l); |
| 73 | lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); | 103 | size_t start = posrelatI(luaL_checkinteger(L, 2), l); |
| 74 | lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); | 104 | size_t end = getendpos(L, 3, -1, l); |
| 75 | if (start < 1) start = 1; | ||
| 76 | if (end > (lua_Integer)l) end = l; | ||
| 77 | if (start <= end) | 105 | if (start <= end) |
| 78 | lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); | 106 | lua_pushlstring(L, s + start - 1, (end - start) + 1); |
| 79 | else lua_pushliteral(L, ""); | 107 | else lua_pushliteral(L, ""); |
| 80 | return 1; | 108 | return 1; |
| 81 | } | 109 | } |
| @@ -148,13 +176,12 @@ static int str_rep (lua_State *L) { | |||
| 148 | static int str_byte (lua_State *L) { | 176 | static int str_byte (lua_State *L) { |
| 149 | size_t l; | 177 | size_t l; |
| 150 | const char *s = luaL_checklstring(L, 1, &l); | 178 | const char *s = luaL_checklstring(L, 1, &l); |
| 151 | lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); | 179 | lua_Integer pi = luaL_optinteger(L, 2, 1); |
| 152 | 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); | ||
| 153 | int n, i; | 182 | int n, i; |
| 154 | if (posi < 1) posi = 1; | ||
| 155 | if (pose > (lua_Integer)l) pose = l; | ||
| 156 | if (posi > pose) return 0; /* empty interval; return no values */ | 183 | if (posi > pose) return 0; /* empty interval; return no values */ |
| 157 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ | 184 | if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */ |
| 158 | return luaL_error(L, "string slice too long"); | 185 | return luaL_error(L, "string slice too long"); |
| 159 | n = (int)(pose - posi) + 1; | 186 | n = (int)(pose - posi) + 1; |
| 160 | luaL_checkstack(L, n, "string slice too long"); | 187 | luaL_checkstack(L, n, "string slice too long"); |
| @@ -170,8 +197,8 @@ static int str_char (lua_State *L) { | |||
| 170 | luaL_Buffer b; | 197 | luaL_Buffer b; |
| 171 | char *p = luaL_buffinitsize(L, &b, n); | 198 | char *p = luaL_buffinitsize(L, &b, n); |
| 172 | for (i=1; i<=n; i++) { | 199 | for (i=1; i<=n; i++) { |
| 173 | lua_Integer c = luaL_checkinteger(L, i); | 200 | lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); |
| 174 | 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"); |
| 175 | p[i - 1] = uchar(c); | 202 | p[i - 1] = uchar(c); |
| 176 | } | 203 | } |
| 177 | luaL_pushresultsize(&b, n); | 204 | luaL_pushresultsize(&b, n); |
| @@ -179,22 +206,38 @@ static int str_char (lua_State *L) { | |||
| 179 | } | 206 | } |
| 180 | 207 | ||
| 181 | 208 | ||
| 182 | static int writer (lua_State *L, const void *b, size_t size, void *B) { | 209 | /* |
| 183 | (void)L; | 210 | ** Buffer to store the result of 'string.dump'. It must be initialized |
| 184 | luaL_addlstring((luaL_Buffer *) B, (const char *)b, size); | 211 | ** after the call to 'lua_dump', to ensure that the function is on the |
| 212 | ** top of the stack when 'lua_dump' is called. ('luaL_buffinit' might | ||
| 213 | ** push stuff.) | ||
| 214 | */ | ||
| 215 | struct str_Writer { | ||
| 216 | int init; /* true iff buffer has been initialized */ | ||
| 217 | luaL_Buffer B; | ||
| 218 | }; | ||
| 219 | |||
| 220 | |||
| 221 | static int writer (lua_State *L, const void *b, size_t size, void *ud) { | ||
| 222 | struct str_Writer *state = (struct str_Writer *)ud; | ||
| 223 | if (!state->init) { | ||
| 224 | state->init = 1; | ||
| 225 | luaL_buffinit(L, &state->B); | ||
| 226 | } | ||
| 227 | luaL_addlstring(&state->B, (const char *)b, size); | ||
| 185 | return 0; | 228 | return 0; |
| 186 | } | 229 | } |
| 187 | 230 | ||
| 188 | 231 | ||
| 189 | static int str_dump (lua_State *L) { | 232 | static int str_dump (lua_State *L) { |
| 190 | luaL_Buffer b; | 233 | struct str_Writer state; |
| 191 | int strip = lua_toboolean(L, 2); | 234 | int strip = lua_toboolean(L, 2); |
| 192 | luaL_checktype(L, 1, LUA_TFUNCTION); | 235 | luaL_checktype(L, 1, LUA_TFUNCTION); |
| 193 | lua_settop(L, 1); | 236 | lua_settop(L, 1); /* ensure function is on the top of the stack */ |
| 194 | luaL_buffinit(L,&b); | 237 | state.init = 0; |
| 195 | if (lua_dump(L, writer, &b, strip) != 0) | 238 | if (lua_dump(L, writer, &state, strip) != 0) |
| 196 | return luaL_error(L, "unable to dump given function"); | 239 | return luaL_error(L, "unable to dump given function"); |
| 197 | luaL_pushresult(&b); | 240 | luaL_pushresult(&state.B); |
| 198 | return 1; | 241 | return 1; |
| 199 | } | 242 | } |
| 200 | 243 | ||
| @@ -202,6 +245,105 @@ static int str_dump (lua_State *L) { | |||
| 202 | 245 | ||
| 203 | /* | 246 | /* |
| 204 | ** {====================================================== | 247 | ** {====================================================== |
| 248 | ** METAMETHODS | ||
| 249 | ** ======================================================= | ||
| 250 | */ | ||
| 251 | |||
| 252 | #if defined(LUA_NOCVTS2N) /* { */ | ||
| 253 | |||
| 254 | /* no coercion from strings to numbers */ | ||
| 255 | |||
| 256 | static const luaL_Reg stringmetamethods[] = { | ||
| 257 | {"__index", NULL}, /* placeholder */ | ||
| 258 | {NULL, NULL} | ||
| 259 | }; | ||
| 260 | |||
| 261 | #else /* }{ */ | ||
| 262 | |||
| 263 | static int tonum (lua_State *L, int arg) { | ||
| 264 | if (lua_type(L, arg) == LUA_TNUMBER) { /* already a number? */ | ||
| 265 | lua_pushvalue(L, arg); | ||
| 266 | return 1; | ||
| 267 | } | ||
| 268 | else { /* check whether it is a numerical string */ | ||
| 269 | size_t len; | ||
| 270 | const char *s = lua_tolstring(L, arg, &len); | ||
| 271 | return (s != NULL && lua_stringtonumber(L, s) == len + 1); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | |||
| 276 | static void trymt (lua_State *L, const char *mtname) { | ||
| 277 | lua_settop(L, 2); /* back to the original arguments */ | ||
| 278 | if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname)) | ||
| 279 | luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, | ||
| 280 | luaL_typename(L, -2), luaL_typename(L, -1)); | ||
| 281 | lua_insert(L, -3); /* put metamethod before arguments */ | ||
| 282 | lua_call(L, 2, 1); /* call metamethod */ | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | static int arith (lua_State *L, int op, const char *mtname) { | ||
| 287 | if (tonum(L, 1) && tonum(L, 2)) | ||
| 288 | lua_arith(L, op); /* result will be on the top */ | ||
| 289 | else | ||
| 290 | trymt(L, mtname); | ||
| 291 | return 1; | ||
| 292 | } | ||
| 293 | |||
| 294 | |||
| 295 | static int arith_add (lua_State *L) { | ||
| 296 | return arith(L, LUA_OPADD, "__add"); | ||
| 297 | } | ||
| 298 | |||
| 299 | static int arith_sub (lua_State *L) { | ||
| 300 | return arith(L, LUA_OPSUB, "__sub"); | ||
| 301 | } | ||
| 302 | |||
| 303 | static int arith_mul (lua_State *L) { | ||
| 304 | return arith(L, LUA_OPMUL, "__mul"); | ||
| 305 | } | ||
| 306 | |||
| 307 | static int arith_mod (lua_State *L) { | ||
| 308 | return arith(L, LUA_OPMOD, "__mod"); | ||
| 309 | } | ||
| 310 | |||
| 311 | static int arith_pow (lua_State *L) { | ||
| 312 | return arith(L, LUA_OPPOW, "__pow"); | ||
| 313 | } | ||
| 314 | |||
| 315 | static int arith_div (lua_State *L) { | ||
| 316 | return arith(L, LUA_OPDIV, "__div"); | ||
| 317 | } | ||
| 318 | |||
| 319 | static int arith_idiv (lua_State *L) { | ||
| 320 | return arith(L, LUA_OPIDIV, "__idiv"); | ||
| 321 | } | ||
| 322 | |||
| 323 | static int arith_unm (lua_State *L) { | ||
| 324 | return arith(L, LUA_OPUNM, "__unm"); | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | static const luaL_Reg stringmetamethods[] = { | ||
| 329 | {"__add", arith_add}, | ||
| 330 | {"__sub", arith_sub}, | ||
| 331 | {"__mul", arith_mul}, | ||
| 332 | {"__mod", arith_mod}, | ||
| 333 | {"__pow", arith_pow}, | ||
| 334 | {"__div", arith_div}, | ||
| 335 | {"__idiv", arith_idiv}, | ||
| 336 | {"__unm", arith_unm}, | ||
| 337 | {"__index", NULL}, /* placeholder */ | ||
| 338 | {NULL, NULL} | ||
| 339 | }; | ||
| 340 | |||
| 341 | #endif /* } */ | ||
| 342 | |||
| 343 | /* }====================================================== */ | ||
| 344 | |||
| 345 | /* | ||
| 346 | ** {====================================================== | ||
| 205 | ** PATTERN MATCHING | 347 | ** PATTERN MATCHING |
| 206 | ** ======================================================= | 348 | ** ======================================================= |
| 207 | */ | 349 | */ |
| @@ -547,25 +689,46 @@ static const char *lmemfind (const char *s1, size_t l1, | |||
| 547 | } | 689 | } |
| 548 | 690 | ||
| 549 | 691 | ||
| 550 | static void push_onecapture (MatchState *ms, int i, const char *s, | 692 | /* |
| 551 | const char *e) { | 693 | ** get information about the i-th capture. If there are no captures |
| 694 | ** and 'i==0', return information about the whole match, which | ||
| 695 | ** is the range 's'..'e'. If the capture is a string, return | ||
| 696 | ** its length and put its address in '*cap'. If it is an integer | ||
| 697 | ** (a position), push it on the stack and return CAP_POSITION. | ||
| 698 | */ | ||
| 699 | static size_t get_onecapture (MatchState *ms, int i, const char *s, | ||
| 700 | const char *e, const char **cap) { | ||
| 552 | if (i >= ms->level) { | 701 | if (i >= ms->level) { |
| 553 | if (i == 0) /* ms->level == 0, too */ | 702 | if (i != 0) |
| 554 | lua_pushlstring(ms->L, s, e - s); /* add whole match */ | ||
| 555 | else | ||
| 556 | luaL_error(ms->L, "invalid capture index %%%d", i + 1); | 703 | luaL_error(ms->L, "invalid capture index %%%d", i + 1); |
| 704 | *cap = s; | ||
| 705 | return e - s; | ||
| 557 | } | 706 | } |
| 558 | else { | 707 | else { |
| 559 | ptrdiff_t l = ms->capture[i].len; | 708 | ptrdiff_t capl = ms->capture[i].len; |
| 560 | if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); | 709 | *cap = ms->capture[i].init; |
| 561 | if (l == CAP_POSITION) | 710 | if (capl == CAP_UNFINISHED) |
| 711 | luaL_error(ms->L, "unfinished capture"); | ||
| 712 | else if (capl == CAP_POSITION) | ||
| 562 | lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); | 713 | lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); |
| 563 | else | 714 | return capl; |
| 564 | lua_pushlstring(ms->L, ms->capture[i].init, l); | ||
| 565 | } | 715 | } |
| 566 | } | 716 | } |
| 567 | 717 | ||
| 568 | 718 | ||
| 719 | /* | ||
| 720 | ** Push the i-th capture on the stack. | ||
| 721 | */ | ||
| 722 | static void push_onecapture (MatchState *ms, int i, const char *s, | ||
| 723 | const char *e) { | ||
| 724 | const char *cap; | ||
| 725 | ptrdiff_t l = get_onecapture(ms, i, s, e, &cap); | ||
| 726 | if (l != CAP_POSITION) | ||
| 727 | lua_pushlstring(ms->L, cap, l); | ||
| 728 | /* else position was already pushed */ | ||
| 729 | } | ||
| 730 | |||
| 731 | |||
| 569 | static int push_captures (MatchState *ms, const char *s, const char *e) { | 732 | static int push_captures (MatchState *ms, const char *s, const char *e) { |
| 570 | int i; | 733 | int i; |
| 571 | int nlevels = (ms->level == 0 && s) ? 1 : ms->level; | 734 | int nlevels = (ms->level == 0 && s) ? 1 : ms->level; |
| @@ -608,16 +771,15 @@ static int str_find_aux (lua_State *L, int find) { | |||
| 608 | size_t ls, lp; | 771 | size_t ls, lp; |
| 609 | const char *s = luaL_checklstring(L, 1, &ls); | 772 | const char *s = luaL_checklstring(L, 1, &ls); |
| 610 | const char *p = luaL_checklstring(L, 2, &lp); | 773 | const char *p = luaL_checklstring(L, 2, &lp); |
| 611 | lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); | 774 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; |
| 612 | if (init < 1) init = 1; | 775 | if (init > ls) { /* start after string's end? */ |
| 613 | else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ | 776 | luaL_pushfail(L); /* cannot find anything */ |
| 614 | lua_pushnil(L); /* cannot find anything */ | ||
| 615 | return 1; | 777 | return 1; |
| 616 | } | 778 | } |
| 617 | /* explicit request or no special characters? */ | 779 | /* explicit request or no special characters? */ |
| 618 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { | 780 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { |
| 619 | /* do a plain search */ | 781 | /* do a plain search */ |
| 620 | const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); | 782 | const char *s2 = lmemfind(s + init, ls - init, p, lp); |
| 621 | if (s2) { | 783 | if (s2) { |
| 622 | lua_pushinteger(L, (s2 - s) + 1); | 784 | lua_pushinteger(L, (s2 - s) + 1); |
| 623 | lua_pushinteger(L, (s2 - s) + lp); | 785 | lua_pushinteger(L, (s2 - s) + lp); |
| @@ -626,7 +788,7 @@ static int str_find_aux (lua_State *L, int find) { | |||
| 626 | } | 788 | } |
| 627 | else { | 789 | else { |
| 628 | MatchState ms; | 790 | MatchState ms; |
| 629 | const char *s1 = s + init - 1; | 791 | const char *s1 = s + init; |
| 630 | int anchor = (*p == '^'); | 792 | int anchor = (*p == '^'); |
| 631 | if (anchor) { | 793 | if (anchor) { |
| 632 | p++; lp--; /* skip anchor character */ | 794 | p++; lp--; /* skip anchor character */ |
| @@ -646,7 +808,7 @@ static int str_find_aux (lua_State *L, int find) { | |||
| 646 | } | 808 | } |
| 647 | } while (s1++ < ms.src_end && !anchor); | 809 | } while (s1++ < ms.src_end && !anchor); |
| 648 | } | 810 | } |
| 649 | lua_pushnil(L); /* not found */ | 811 | luaL_pushfail(L); /* not found */ |
| 650 | return 1; | 812 | return 1; |
| 651 | } | 813 | } |
| 652 | 814 | ||
| @@ -690,11 +852,14 @@ static int gmatch (lua_State *L) { | |||
| 690 | size_t ls, lp; | 852 | size_t ls, lp; |
| 691 | const char *s = luaL_checklstring(L, 1, &ls); | 853 | const char *s = luaL_checklstring(L, 1, &ls); |
| 692 | const char *p = luaL_checklstring(L, 2, &lp); | 854 | const char *p = luaL_checklstring(L, 2, &lp); |
| 855 | size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; | ||
| 693 | GMatchState *gm; | 856 | GMatchState *gm; |
| 694 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | 857 | lua_settop(L, 2); /* keep strings on closure to avoid being collected */ |
| 695 | gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); | 858 | gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); |
| 859 | if (init > ls) /* start after string's end? */ | ||
| 860 | init = ls + 1; /* avoid overflows in 's + init' */ | ||
| 696 | prepstate(&gm->ms, L, s, ls, p, lp); | 861 | prepstate(&gm->ms, L, s, ls, p, lp); |
| 697 | gm->src = s; gm->p = p; gm->lastmatch = NULL; | 862 | gm->src = s + init; gm->p = p; gm->lastmatch = NULL; |
| 698 | lua_pushcclosure(L, gmatch_aux, 3); | 863 | lua_pushcclosure(L, gmatch_aux, 3); |
| 699 | return 1; | 864 | return 1; |
| 700 | } | 865 | } |
| @@ -702,60 +867,72 @@ static int gmatch (lua_State *L) { | |||
| 702 | 867 | ||
| 703 | static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, | 868 | static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, |
| 704 | const char *e) { | 869 | const char *e) { |
| 705 | size_t l, i; | 870 | size_t l; |
| 706 | lua_State *L = ms->L; | 871 | lua_State *L = ms->L; |
| 707 | const char *news = lua_tolstring(L, 3, &l); | 872 | const char *news = lua_tolstring(L, 3, &l); |
| 708 | for (i = 0; i < l; i++) { | 873 | const char *p; |
| 709 | if (news[i] != L_ESC) | 874 | while ((p = (char *)memchr(news, L_ESC, l)) != NULL) { |
| 710 | luaL_addchar(b, news[i]); | 875 | luaL_addlstring(b, news, p - news); |
| 711 | else { | 876 | p++; /* skip ESC */ |
| 712 | i++; /* skip ESC */ | 877 | if (*p == L_ESC) /* '%%' */ |
| 713 | if (!isdigit(uchar(news[i]))) { | 878 | luaL_addchar(b, *p); |
| 714 | if (news[i] != L_ESC) | 879 | else if (*p == '0') /* '%0' */ |
| 715 | luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); | 880 | luaL_addlstring(b, s, e - s); |
| 716 | luaL_addchar(b, news[i]); | 881 | else if (isdigit(uchar(*p))) { /* '%n' */ |
| 717 | } | 882 | const char *cap; |
| 718 | else if (news[i] == '0') | 883 | ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap); |
| 719 | luaL_addlstring(b, s, e - s); | 884 | if (resl == CAP_POSITION) |
| 720 | else { | 885 | luaL_addvalue(b); /* add position to accumulated result */ |
| 721 | push_onecapture(ms, news[i] - '1', s, e); | 886 | else |
| 722 | luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ | 887 | luaL_addlstring(b, cap, resl); |
| 723 | lua_remove(L, -2); /* remove original value */ | ||
| 724 | luaL_addvalue(b); /* add capture to accumulated result */ | ||
| 725 | } | ||
| 726 | } | 888 | } |
| 889 | else | ||
| 890 | luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); | ||
| 891 | l -= p + 1 - news; | ||
| 892 | news = p + 1; | ||
| 727 | } | 893 | } |
| 894 | luaL_addlstring(b, news, l); | ||
| 728 | } | 895 | } |
| 729 | 896 | ||
| 730 | 897 | ||
| 731 | static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, | 898 | /* |
| 732 | const char *e, int tr) { | 899 | ** Add the replacement value to the string buffer 'b'. |
| 900 | ** Return true if the original string was changed. (Function calls and | ||
| 901 | ** table indexing resulting in nil or false do not change the subject.) | ||
| 902 | */ | ||
| 903 | static int add_value (MatchState *ms, luaL_Buffer *b, const char *s, | ||
| 904 | const char *e, int tr) { | ||
| 733 | lua_State *L = ms->L; | 905 | lua_State *L = ms->L; |
| 734 | switch (tr) { | 906 | switch (tr) { |
| 735 | case LUA_TFUNCTION: { | 907 | case LUA_TFUNCTION: { /* call the function */ |
| 736 | int n; | 908 | int n; |
| 737 | lua_pushvalue(L, 3); | 909 | lua_pushvalue(L, 3); /* push the function */ |
| 738 | n = push_captures(ms, s, e); | 910 | n = push_captures(ms, s, e); /* all captures as arguments */ |
| 739 | lua_call(L, n, 1); | 911 | lua_call(L, n, 1); /* call it */ |
| 740 | break; | 912 | break; |
| 741 | } | 913 | } |
| 742 | case LUA_TTABLE: { | 914 | case LUA_TTABLE: { /* index the table */ |
| 743 | push_onecapture(ms, 0, s, e); | 915 | push_onecapture(ms, 0, s, e); /* first capture is the index */ |
| 744 | lua_gettable(L, 3); | 916 | lua_gettable(L, 3); |
| 745 | break; | 917 | break; |
| 746 | } | 918 | } |
| 747 | default: { /* LUA_TNUMBER or LUA_TSTRING */ | 919 | default: { /* LUA_TNUMBER or LUA_TSTRING */ |
| 748 | add_s(ms, b, s, e); | 920 | add_s(ms, b, s, e); /* add value to the buffer */ |
| 749 | return; | 921 | return 1; /* something changed */ |
| 750 | } | 922 | } |
| 751 | } | 923 | } |
| 752 | if (!lua_toboolean(L, -1)) { /* nil or false? */ | 924 | if (!lua_toboolean(L, -1)) { /* nil or false? */ |
| 753 | lua_pop(L, 1); | 925 | lua_pop(L, 1); /* remove value */ |
| 754 | lua_pushlstring(L, s, e - s); /* keep original text */ | 926 | luaL_addlstring(b, s, e - s); /* keep original text */ |
| 927 | return 0; /* no changes */ | ||
| 755 | } | 928 | } |
| 756 | else if (!lua_isstring(L, -1)) | 929 | else if (!lua_isstring(L, -1)) |
| 757 | luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); | 930 | return luaL_error(L, "invalid replacement value (a %s)", |
| 758 | luaL_addvalue(b); /* add result to accumulator */ | 931 | luaL_typename(L, -1)); |
| 932 | else { | ||
| 933 | luaL_addvalue(b); /* add result to accumulator */ | ||
| 934 | return 1; /* something changed */ | ||
| 935 | } | ||
| 759 | } | 936 | } |
| 760 | 937 | ||
| 761 | 938 | ||
| @@ -768,11 +945,12 @@ static int str_gsub (lua_State *L) { | |||
| 768 | lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ | 945 | lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ |
| 769 | int anchor = (*p == '^'); | 946 | int anchor = (*p == '^'); |
| 770 | lua_Integer n = 0; /* replacement count */ | 947 | lua_Integer n = 0; /* replacement count */ |
| 948 | int changed = 0; /* change flag */ | ||
| 771 | MatchState ms; | 949 | MatchState ms; |
| 772 | luaL_Buffer b; | 950 | luaL_Buffer b; |
| 773 | luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || | 951 | luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || |
| 774 | tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, | 952 | tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, |
| 775 | "string/function/table expected"); | 953 | "string/function/table"); |
| 776 | luaL_buffinit(L, &b); | 954 | luaL_buffinit(L, &b); |
| 777 | if (anchor) { | 955 | if (anchor) { |
| 778 | p++; lp--; /* skip anchor character */ | 956 | p++; lp--; /* skip anchor character */ |
| @@ -783,7 +961,7 @@ static int str_gsub (lua_State *L) { | |||
| 783 | reprepstate(&ms); /* (re)prepare state for new match */ | 961 | reprepstate(&ms); /* (re)prepare state for new match */ |
| 784 | if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ | 962 | if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ |
| 785 | n++; | 963 | n++; |
| 786 | add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ | 964 | changed = add_value(&ms, &b, src, e, tr) | changed; |
| 787 | src = lastmatch = e; | 965 | src = lastmatch = e; |
| 788 | } | 966 | } |
| 789 | else if (src < ms.src_end) /* otherwise, skip one character */ | 967 | else if (src < ms.src_end) /* otherwise, skip one character */ |
| @@ -791,8 +969,12 @@ static int str_gsub (lua_State *L) { | |||
| 791 | else break; /* end of subject */ | 969 | else break; /* end of subject */ |
| 792 | if (anchor) break; | 970 | if (anchor) break; |
| 793 | } | 971 | } |
| 794 | luaL_addlstring(&b, src, ms.src_end-src); | 972 | if (!changed) /* no changes? */ |
| 795 | luaL_pushresult(&b); | 973 | lua_pushvalue(L, 1); /* return original string */ |
| 974 | else { /* something changed */ | ||
| 975 | luaL_addlstring(&b, src, ms.src_end-src); | ||
| 976 | luaL_pushresult(&b); /* create and return new string */ | ||
| 977 | } | ||
| 796 | lua_pushinteger(L, n); /* number of substitutions */ | 978 | lua_pushinteger(L, n); /* number of substitutions */ |
| 797 | return 2; | 979 | return 2; |
| 798 | } | 980 | } |
| @@ -813,8 +995,6 @@ static int str_gsub (lua_State *L) { | |||
| 813 | ** Hexadecimal floating-point formatter | 995 | ** Hexadecimal floating-point formatter |
| 814 | */ | 996 | */ |
| 815 | 997 | ||
| 816 | #include <math.h> | ||
| 817 | |||
| 818 | #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) | 998 | #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) |
| 819 | 999 | ||
| 820 | 1000 | ||
| @@ -824,7 +1004,7 @@ static int str_gsub (lua_State *L) { | |||
| 824 | ** to nibble boundaries by making what is left after that first digit a | 1004 | ** to nibble boundaries by making what is left after that first digit a |
| 825 | ** multiple of 4. | 1005 | ** multiple of 4. |
| 826 | */ | 1006 | */ |
| 827 | #define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) | 1007 | #define L_NBFD ((l_floatatt(MANT_DIG) - 1)%4 + 1) |
| 828 | 1008 | ||
| 829 | 1009 | ||
| 830 | /* | 1010 | /* |
| @@ -851,7 +1031,7 @@ static int num2straux (char *buff, int sz, lua_Number x) { | |||
| 851 | lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ | 1031 | lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ |
| 852 | int n = 0; /* character count */ | 1032 | int n = 0; /* character count */ |
| 853 | if (m < 0) { /* is number negative? */ | 1033 | if (m < 0) { /* is number negative? */ |
| 854 | buff[n++] = '-'; /* add signal */ | 1034 | buff[n++] = '-'; /* add sign */ |
| 855 | m = -m; /* make it positive */ | 1035 | m = -m; /* make it positive */ |
| 856 | } | 1036 | } |
| 857 | buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ | 1037 | buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ |
| @@ -887,17 +1067,30 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, | |||
| 887 | 1067 | ||
| 888 | 1068 | ||
| 889 | /* | 1069 | /* |
| 890 | ** Maximum size of each formatted item. This maximum size is produced | 1070 | ** Maximum size for items formatted with '%f'. This size is produced |
| 891 | ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', | 1071 | ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', |
| 892 | ** and '\0') + number of decimal digits to represent maxfloat (which | 1072 | ** and '\0') + number of decimal digits to represent maxfloat (which |
| 893 | ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra | 1073 | ** is maximum exponent + 1). (99+3+1, adding some extra, 110) |
| 894 | ** expenses", such as locale-dependent stuff) | ||
| 895 | */ | 1074 | */ |
| 896 | #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) | 1075 | #define MAX_ITEMF (110 + l_floatatt(MAX_10_EXP)) |
| 1076 | |||
| 1077 | |||
| 1078 | /* | ||
| 1079 | ** All formats except '%f' do not need that large limit. The other | ||
| 1080 | ** float formats use exponents, so that they fit in the 99 limit for | ||
| 1081 | ** significant digits; 's' for large strings and 'q' add items directly | ||
| 1082 | ** to the buffer; all integer formats also fit in the 99 limit. The | ||
| 1083 | ** worst case are floats: they may need 99 significant digits, plus | ||
| 1084 | ** '0x', '-', '.', 'e+XXXX', and '\0'. Adding some extra, 120. | ||
| 1085 | */ | ||
| 1086 | #define MAX_ITEM 120 | ||
| 897 | 1087 | ||
| 898 | 1088 | ||
| 899 | /* valid flags in a format specification */ | 1089 | /* valid flags in a format specification */ |
| 900 | #define FLAGS "-+ #0" | 1090 | #if !defined(L_FMTFLAGS) |
| 1091 | #define L_FMTFLAGS "-+ #0" | ||
| 1092 | #endif | ||
| 1093 | |||
| 901 | 1094 | ||
| 902 | /* | 1095 | /* |
| 903 | ** maximum size of each format specification (such as "%-099.99d") | 1096 | ** maximum size of each format specification (such as "%-099.99d") |
| @@ -929,14 +1122,32 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) { | |||
| 929 | 1122 | ||
| 930 | 1123 | ||
| 931 | /* | 1124 | /* |
| 932 | ** Ensures the 'buff' string uses a dot as the radix character. | 1125 | ** Serialize a floating-point number in such a way that it can be |
| 1126 | ** scanned back by Lua. Use hexadecimal format for "common" numbers | ||
| 1127 | ** (to preserve precision); inf, -inf, and NaN are handled separately. | ||
| 1128 | ** (NaN cannot be expressed as a numeral, so we write '(0/0)' for it.) | ||
| 933 | */ | 1129 | */ |
| 934 | static void checkdp (char *buff, int nb) { | 1130 | static int quotefloat (lua_State *L, char *buff, lua_Number n) { |
| 935 | if (memchr(buff, '.', nb) == NULL) { /* no dot? */ | 1131 | const char *s; /* for the fixed representations */ |
| 936 | char point = lua_getlocaledecpoint(); /* try locale point */ | 1132 | if (n == (lua_Number)HUGE_VAL) /* inf? */ |
| 937 | char *ppoint = (char *)memchr(buff, point, nb); | 1133 | s = "1e9999"; |
| 938 | if (ppoint) *ppoint = '.'; /* change it to a dot */ | 1134 | else if (n == -(lua_Number)HUGE_VAL) /* -inf? */ |
| 1135 | s = "-1e9999"; | ||
| 1136 | else if (n != n) /* NaN? */ | ||
| 1137 | s = "(0/0)"; | ||
| 1138 | else { /* format number as hexadecimal */ | ||
| 1139 | int nb = lua_number2strx(L, buff, MAX_ITEM, | ||
| 1140 | "%" LUA_NUMBER_FRMLEN "a", n); | ||
| 1141 | /* ensures that 'buff' string uses a dot as the radix character */ | ||
| 1142 | if (memchr(buff, '.', nb) == NULL) { /* no dot? */ | ||
| 1143 | char point = lua_getlocaledecpoint(); /* try locale point */ | ||
| 1144 | char *ppoint = (char *)memchr(buff, point, nb); | ||
| 1145 | if (ppoint) *ppoint = '.'; /* change it to a dot */ | ||
| 1146 | } | ||
| 1147 | return nb; | ||
| 939 | } | 1148 | } |
| 1149 | /* for the fixed representations */ | ||
| 1150 | return l_sprintf(buff, MAX_ITEM, "%s", s); | ||
| 940 | } | 1151 | } |
| 941 | 1152 | ||
| 942 | 1153 | ||
| @@ -951,15 +1162,12 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { | |||
| 951 | case LUA_TNUMBER: { | 1162 | case LUA_TNUMBER: { |
| 952 | char *buff = luaL_prepbuffsize(b, MAX_ITEM); | 1163 | char *buff = luaL_prepbuffsize(b, MAX_ITEM); |
| 953 | int nb; | 1164 | int nb; |
| 954 | if (!lua_isinteger(L, arg)) { /* float? */ | 1165 | if (!lua_isinteger(L, arg)) /* float? */ |
| 955 | lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ | 1166 | nb = quotefloat(L, buff, lua_tonumber(L, arg)); |
| 956 | nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); | ||
| 957 | checkdp(buff, nb); /* ensure it uses a dot */ | ||
| 958 | } | ||
| 959 | else { /* integers */ | 1167 | else { /* integers */ |
| 960 | lua_Integer n = lua_tointeger(L, arg); | 1168 | lua_Integer n = lua_tointeger(L, arg); |
| 961 | const char *format = (n == LUA_MININTEGER) /* corner case? */ | 1169 | const char *format = (n == LUA_MININTEGER) /* corner case? */ |
| 962 | ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ | 1170 | ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hex */ |
| 963 | : LUA_INTEGER_FMT; /* else use default format */ | 1171 | : LUA_INTEGER_FMT; /* else use default format */ |
| 964 | nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); | 1172 | nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); |
| 965 | } | 1173 | } |
| @@ -980,8 +1188,8 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { | |||
| 980 | 1188 | ||
| 981 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { | 1189 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { |
| 982 | const char *p = strfrmt; | 1190 | const char *p = strfrmt; |
| 983 | while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ | 1191 | while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */ |
| 984 | if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) | 1192 | if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char)) |
| 985 | luaL_error(L, "invalid format (repeated flags)"); | 1193 | luaL_error(L, "invalid format (repeated flags)"); |
| 986 | if (isdigit(uchar(*p))) p++; /* skip width */ | 1194 | if (isdigit(uchar(*p))) p++; /* skip width */ |
| 987 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ | 1195 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ |
| @@ -1028,36 +1236,51 @@ static int str_format (lua_State *L) { | |||
| 1028 | luaL_addchar(&b, *strfrmt++); /* %% */ | 1236 | luaL_addchar(&b, *strfrmt++); /* %% */ |
| 1029 | else { /* format item */ | 1237 | else { /* format item */ |
| 1030 | char form[MAX_FORMAT]; /* to store the format ('%...') */ | 1238 | char form[MAX_FORMAT]; /* to store the format ('%...') */ |
| 1031 | char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ | 1239 | int maxitem = MAX_ITEM; |
| 1240 | char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ | ||
| 1032 | int nb = 0; /* number of bytes in added item */ | 1241 | int nb = 0; /* number of bytes in added item */ |
| 1033 | if (++arg > top) | 1242 | if (++arg > top) |
| 1034 | luaL_argerror(L, arg, "no value"); | 1243 | return luaL_argerror(L, arg, "no value"); |
| 1035 | strfrmt = scanformat(L, strfrmt, form); | 1244 | strfrmt = scanformat(L, strfrmt, form); |
| 1036 | switch (*strfrmt++) { | 1245 | switch (*strfrmt++) { |
| 1037 | case 'c': { | 1246 | case 'c': { |
| 1038 | nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); | 1247 | nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); |
| 1039 | break; | 1248 | break; |
| 1040 | } | 1249 | } |
| 1041 | case 'd': case 'i': | 1250 | case 'd': case 'i': |
| 1042 | case 'o': case 'u': case 'x': case 'X': { | 1251 | case 'o': case 'u': case 'x': case 'X': { |
| 1043 | lua_Integer n = luaL_checkinteger(L, arg); | 1252 | lua_Integer n = luaL_checkinteger(L, arg); |
| 1044 | addlenmod(form, LUA_INTEGER_FRMLEN); | 1253 | addlenmod(form, LUA_INTEGER_FRMLEN); |
| 1045 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); | 1254 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); |
| 1046 | break; | 1255 | break; |
| 1047 | } | 1256 | } |
| 1048 | case 'a': case 'A': | 1257 | case 'a': case 'A': |
| 1049 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1258 | addlenmod(form, LUA_NUMBER_FRMLEN); |
| 1050 | nb = lua_number2strx(L, buff, MAX_ITEM, form, | 1259 | nb = lua_number2strx(L, buff, maxitem, form, |
| 1051 | luaL_checknumber(L, arg)); | 1260 | luaL_checknumber(L, arg)); |
| 1052 | break; | 1261 | break; |
| 1053 | case 'e': case 'E': case 'f': | 1262 | case 'f': |
| 1054 | case 'g': case 'G': { | 1263 | maxitem = MAX_ITEMF; /* extra space for '%f' */ |
| 1264 | buff = luaL_prepbuffsize(&b, maxitem); | ||
| 1265 | /* FALLTHROUGH */ | ||
| 1266 | case 'e': case 'E': case 'g': case 'G': { | ||
| 1055 | lua_Number n = luaL_checknumber(L, arg); | 1267 | lua_Number n = luaL_checknumber(L, arg); |
| 1056 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1268 | addlenmod(form, LUA_NUMBER_FRMLEN); |
| 1057 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); | 1269 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); |
| 1270 | break; | ||
| 1271 | } | ||
| 1272 | case 'p': { | ||
| 1273 | const void *p = lua_topointer(L, arg); | ||
| 1274 | if (p == NULL) { /* avoid calling 'printf' with argument NULL */ | ||
| 1275 | p = "(null)"; /* result */ | ||
| 1276 | form[strlen(form) - 1] = 's'; /* format it as a string */ | ||
| 1277 | } | ||
| 1278 | nb = l_sprintf(buff, maxitem, form, p); | ||
| 1058 | break; | 1279 | break; |
| 1059 | } | 1280 | } |
| 1060 | case 'q': { | 1281 | case 'q': { |
| 1282 | if (form[2] != '\0') /* modifiers? */ | ||
| 1283 | return luaL_error(L, "specifier '%%q' cannot have modifiers"); | ||
| 1061 | addliteral(L, &b, arg); | 1284 | addliteral(L, &b, arg); |
| 1062 | break; | 1285 | break; |
| 1063 | } | 1286 | } |
| @@ -1073,18 +1296,17 @@ static int str_format (lua_State *L) { | |||
| 1073 | luaL_addvalue(&b); /* keep entire string */ | 1296 | luaL_addvalue(&b); /* keep entire string */ |
| 1074 | } | 1297 | } |
| 1075 | else { /* format the string into 'buff' */ | 1298 | else { /* format the string into 'buff' */ |
| 1076 | nb = l_sprintf(buff, MAX_ITEM, form, s); | 1299 | nb = l_sprintf(buff, maxitem, form, s); |
| 1077 | lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ | 1300 | lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ |
| 1078 | } | 1301 | } |
| 1079 | } | 1302 | } |
| 1080 | break; | 1303 | break; |
| 1081 | } | 1304 | } |
| 1082 | default: { /* also treat cases 'pnLlh' */ | 1305 | default: { /* also treat cases 'pnLlh' */ |
| 1083 | return luaL_error(L, "invalid option '%%%c' to 'format'", | 1306 | return luaL_error(L, "invalid conversion '%s' to 'format'", form); |
| 1084 | *(strfrmt - 1)); | ||
| 1085 | } | 1307 | } |
| 1086 | } | 1308 | } |
| 1087 | lua_assert(nb < MAX_ITEM); | 1309 | lua_assert(nb < maxitem); |
| 1088 | luaL_addsize(&b, nb); | 1310 | luaL_addsize(&b, nb); |
| 1089 | } | 1311 | } |
| 1090 | } | 1312 | } |
| @@ -1422,17 +1644,12 @@ static int str_packsize (lua_State *L) { | |||
| 1422 | while (*fmt != '\0') { | 1644 | while (*fmt != '\0') { |
| 1423 | int size, ntoalign; | 1645 | int size, ntoalign; |
| 1424 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); | 1646 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); |
| 1647 | luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1, | ||
| 1648 | "variable-length format"); | ||
| 1425 | size += ntoalign; /* total space used by option */ | 1649 | size += ntoalign; /* total space used by option */ |
| 1426 | luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, | 1650 | luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, |
| 1427 | "format result too large"); | 1651 | "format result too large"); |
| 1428 | totalsize += size; | 1652 | totalsize += size; |
| 1429 | switch (opt) { | ||
| 1430 | case Kstring: /* strings with length count */ | ||
| 1431 | case Kzstr: /* zero-terminated string */ | ||
| 1432 | luaL_argerror(L, 1, "variable-length format"); | ||
| 1433 | /* call never return, but to avoid warnings: *//* FALLTHROUGH */ | ||
| 1434 | default: break; | ||
| 1435 | } | ||
| 1436 | } | 1653 | } |
| 1437 | lua_pushinteger(L, (lua_Integer)totalsize); | 1654 | lua_pushinteger(L, (lua_Integer)totalsize); |
| 1438 | return 1; | 1655 | return 1; |
| @@ -1478,15 +1695,15 @@ static int str_unpack (lua_State *L) { | |||
| 1478 | const char *fmt = luaL_checkstring(L, 1); | 1695 | const char *fmt = luaL_checkstring(L, 1); |
| 1479 | size_t ld; | 1696 | size_t ld; |
| 1480 | const char *data = luaL_checklstring(L, 2, &ld); | 1697 | const char *data = luaL_checklstring(L, 2, &ld); |
| 1481 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | 1698 | size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; |
| 1482 | int n = 0; /* number of results */ | 1699 | int n = 0; /* number of results */ |
| 1483 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | 1700 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); |
| 1484 | initheader(L, &h); | 1701 | initheader(L, &h); |
| 1485 | while (*fmt != '\0') { | 1702 | while (*fmt != '\0') { |
| 1486 | int size, ntoalign; | 1703 | int size, ntoalign; |
| 1487 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); | 1704 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); |
| 1488 | if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) | 1705 | luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2, |
| 1489 | luaL_argerror(L, 2, "data string too short"); | 1706 | "data string too short"); |
| 1490 | pos += ntoalign; /* skip alignment */ | 1707 | pos += ntoalign; /* skip alignment */ |
| 1491 | /* stack space for item + next position */ | 1708 | /* stack space for item + next position */ |
| 1492 | luaL_checkstack(L, 2, "too many results"); | 1709 | luaL_checkstack(L, 2, "too many results"); |
| @@ -1515,13 +1732,15 @@ static int str_unpack (lua_State *L) { | |||
| 1515 | } | 1732 | } |
| 1516 | case Kstring: { | 1733 | case Kstring: { |
| 1517 | size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); | 1734 | size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); |
| 1518 | luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); | 1735 | luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short"); |
| 1519 | lua_pushlstring(L, data + pos + size, len); | 1736 | lua_pushlstring(L, data + pos + size, len); |
| 1520 | pos += len; /* skip string */ | 1737 | pos += len; /* skip string */ |
| 1521 | break; | 1738 | break; |
| 1522 | } | 1739 | } |
| 1523 | case Kzstr: { | 1740 | case Kzstr: { |
| 1524 | size_t len = (int)strlen(data + pos); | 1741 | size_t len = (int)strlen(data + pos); |
| 1742 | luaL_argcheck(L, pos + len < ld, 2, | ||
| 1743 | "unfinished string for format 'z'"); | ||
| 1525 | lua_pushlstring(L, data + pos, len); | 1744 | lua_pushlstring(L, data + pos, len); |
| 1526 | pos += len + 1; /* skip string plus final '\0' */ | 1745 | pos += len + 1; /* skip string plus final '\0' */ |
| 1527 | break; | 1746 | break; |
| @@ -1562,7 +1781,9 @@ static const luaL_Reg strlib[] = { | |||
| 1562 | 1781 | ||
| 1563 | 1782 | ||
| 1564 | static void createmetatable (lua_State *L) { | 1783 | static void createmetatable (lua_State *L) { |
| 1565 | lua_createtable(L, 0, 1); /* table to be metatable for strings */ | 1784 | /* table to be metatable for strings */ |
| 1785 | luaL_newlibtable(L, stringmetamethods); | ||
| 1786 | luaL_setfuncs(L, stringmetamethods, 0); | ||
| 1566 | lua_pushliteral(L, ""); /* dummy string */ | 1787 | lua_pushliteral(L, ""); /* dummy string */ |
| 1567 | lua_pushvalue(L, -2); /* copy table */ | 1788 | lua_pushvalue(L, -2); /* copy table */ |
| 1568 | lua_setmetatable(L, -2); /* set table as metatable for strings */ | 1789 | lua_setmetatable(L, -2); /* set table as metatable for strings */ |
