diff options
Diffstat (limited to 'src/lib_string.c')
| -rw-r--r-- | src/lib_string.c | 427 |
1 files changed, 81 insertions, 346 deletions
diff --git a/src/lib_string.c b/src/lib_string.c index e534326a..75d855d6 100644 --- a/src/lib_string.c +++ b/src/lib_string.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h | 6 | ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <stdio.h> | ||
| 10 | |||
| 11 | #define lib_string_c | 9 | #define lib_string_c |
| 12 | #define LUA_LIB | 10 | #define LUA_LIB |
| 13 | 11 | ||
| @@ -18,6 +16,7 @@ | |||
| 18 | #include "lj_obj.h" | 16 | #include "lj_obj.h" |
| 19 | #include "lj_gc.h" | 17 | #include "lj_gc.h" |
| 20 | #include "lj_err.h" | 18 | #include "lj_err.h" |
| 19 | #include "lj_buf.h" | ||
| 21 | #include "lj_str.h" | 20 | #include "lj_str.h" |
| 22 | #include "lj_tab.h" | 21 | #include "lj_tab.h" |
| 23 | #include "lj_meta.h" | 22 | #include "lj_meta.h" |
| @@ -25,17 +24,19 @@ | |||
| 25 | #include "lj_ff.h" | 24 | #include "lj_ff.h" |
| 26 | #include "lj_bcdump.h" | 25 | #include "lj_bcdump.h" |
| 27 | #include "lj_char.h" | 26 | #include "lj_char.h" |
| 27 | #include "lj_strfmt.h" | ||
| 28 | #include "lj_lib.h" | 28 | #include "lj_lib.h" |
| 29 | 29 | ||
| 30 | /* ------------------------------------------------------------------------ */ | 30 | /* ------------------------------------------------------------------------ */ |
| 31 | 31 | ||
| 32 | #define LJLIB_MODULE_string | 32 | #define LJLIB_MODULE_string |
| 33 | 33 | ||
| 34 | LJLIB_ASM(string_len) LJLIB_REC(.) | 34 | LJLIB_LUA(string_len) /* |
| 35 | { | 35 | function(s) |
| 36 | lj_lib_checkstr(L, 1); | 36 | CHECK_str(s) |
| 37 | return FFH_RETRY; | 37 | return #s |
| 38 | } | 38 | end |
| 39 | */ | ||
| 39 | 40 | ||
| 40 | LJLIB_ASM(string_byte) LJLIB_REC(string_range 0) | 41 | LJLIB_ASM(string_byte) LJLIB_REC(string_range 0) |
| 41 | { | 42 | { |
| @@ -57,21 +58,21 @@ LJLIB_ASM(string_byte) LJLIB_REC(string_range 0) | |||
| 57 | lj_state_checkstack(L, (MSize)n); | 58 | lj_state_checkstack(L, (MSize)n); |
| 58 | p = (const unsigned char *)strdata(s) + start; | 59 | p = (const unsigned char *)strdata(s) + start; |
| 59 | for (i = 0; i < n; i++) | 60 | for (i = 0; i < n; i++) |
| 60 | setintV(L->base + i-1, p[i]); | 61 | setintV(L->base + i-1-LJ_FR2, p[i]); |
| 61 | return FFH_RES(n); | 62 | return FFH_RES(n); |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | LJLIB_ASM(string_char) | 65 | LJLIB_ASM(string_char) LJLIB_REC(.) |
| 65 | { | 66 | { |
| 66 | int i, nargs = (int)(L->top - L->base); | 67 | int i, nargs = (int)(L->top - L->base); |
| 67 | char *buf = lj_str_needbuf(L, &G(L)->tmpbuf, (MSize)nargs); | 68 | char *buf = lj_buf_tmp(L, (MSize)nargs); |
| 68 | for (i = 1; i <= nargs; i++) { | 69 | for (i = 1; i <= nargs; i++) { |
| 69 | int32_t k = lj_lib_checkint(L, i); | 70 | int32_t k = lj_lib_checkint(L, i); |
| 70 | if (!checku8(k)) | 71 | if (!checku8(k)) |
| 71 | lj_err_arg(L, i, LJ_ERR_BADVAL); | 72 | lj_err_arg(L, i, LJ_ERR_BADVAL); |
| 72 | buf[i-1] = (char)k; | 73 | buf[i-1] = (char)k; |
| 73 | } | 74 | } |
| 74 | setstrV(L, L->base-1, lj_str_new(L, buf, (size_t)nargs)); | 75 | setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs)); |
| 75 | return FFH_RES(1); | 76 | return FFH_RES(1); |
| 76 | } | 77 | } |
| 77 | 78 | ||
| @@ -83,68 +84,38 @@ LJLIB_ASM(string_sub) LJLIB_REC(string_range 1) | |||
| 83 | return FFH_RETRY; | 84 | return FFH_RETRY; |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | LJLIB_ASM(string_rep) | 87 | LJLIB_CF(string_rep) LJLIB_REC(.) |
| 87 | { | 88 | { |
| 88 | GCstr *s = lj_lib_checkstr(L, 1); | 89 | GCstr *s = lj_lib_checkstr(L, 1); |
| 89 | int32_t k = lj_lib_checkint(L, 2); | 90 | int32_t rep = lj_lib_checkint(L, 2); |
| 90 | GCstr *sep = lj_lib_optstr(L, 3); | 91 | GCstr *sep = lj_lib_optstr(L, 3); |
| 91 | int32_t len = (int32_t)s->len; | 92 | SBuf *sb = lj_buf_tmp_(L); |
| 92 | global_State *g = G(L); | 93 | if (sep && rep > 1) { |
| 93 | int64_t tlen; | 94 | GCstr *s2 = lj_buf_cat2str(L, sep, s); |
| 94 | const char *src; | 95 | lj_buf_reset(sb); |
| 95 | char *buf; | 96 | lj_buf_putstr(sb, s); |
| 96 | if (k <= 0) { | 97 | s = s2; |
| 97 | empty: | 98 | rep--; |
| 98 | setstrV(L, L->base-1, &g->strempty); | ||
| 99 | return FFH_RES(1); | ||
| 100 | } | ||
| 101 | if (sep) { | ||
| 102 | tlen = (int64_t)len + sep->len; | ||
| 103 | if (tlen > LJ_MAX_STR) | ||
| 104 | lj_err_caller(L, LJ_ERR_STROV); | ||
| 105 | tlen *= k; | ||
| 106 | if (tlen > LJ_MAX_STR) | ||
| 107 | lj_err_caller(L, LJ_ERR_STROV); | ||
| 108 | } else { | ||
| 109 | tlen = (int64_t)k * len; | ||
| 110 | if (tlen > LJ_MAX_STR) | ||
| 111 | lj_err_caller(L, LJ_ERR_STROV); | ||
| 112 | } | ||
| 113 | if (tlen == 0) goto empty; | ||
| 114 | buf = lj_str_needbuf(L, &g->tmpbuf, (MSize)tlen); | ||
| 115 | src = strdata(s); | ||
| 116 | if (sep) { | ||
| 117 | tlen -= sep->len; /* Ignore trailing separator. */ | ||
| 118 | if (k > 1) { /* Paste one string and one separator. */ | ||
| 119 | int32_t i; | ||
| 120 | i = 0; while (i < len) *buf++ = src[i++]; | ||
| 121 | src = strdata(sep); len = sep->len; | ||
| 122 | i = 0; while (i < len) *buf++ = src[i++]; | ||
| 123 | src = g->tmpbuf.buf; len += s->len; k--; /* Now copy that k-1 times. */ | ||
| 124 | } | ||
| 125 | } | 99 | } |
| 126 | do { | 100 | sb = lj_buf_putstr_rep(sb, s, rep); |
| 127 | int32_t i = 0; | 101 | setstrV(L, L->top-1, lj_buf_str(L, sb)); |
| 128 | do { *buf++ = src[i++]; } while (i < len); | 102 | lj_gc_check(L); |
| 129 | } while (--k > 0); | 103 | return 1; |
| 130 | setstrV(L, L->base-1, lj_str_new(L, g->tmpbuf.buf, (size_t)tlen)); | ||
| 131 | return FFH_RES(1); | ||
| 132 | } | 104 | } |
| 133 | 105 | ||
| 134 | LJLIB_ASM(string_reverse) | 106 | LJLIB_ASM(string_reverse) LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse) |
| 135 | { | 107 | { |
| 136 | GCstr *s = lj_lib_checkstr(L, 1); | 108 | lj_lib_checkstr(L, 1); |
| 137 | lj_str_needbuf(L, &G(L)->tmpbuf, s->len); | ||
| 138 | return FFH_RETRY; | 109 | return FFH_RETRY; |
| 139 | } | 110 | } |
| 140 | LJLIB_ASM_(string_lower) | 111 | LJLIB_ASM_(string_lower) LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower) |
| 141 | LJLIB_ASM_(string_upper) | 112 | LJLIB_ASM_(string_upper) LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper) |
| 142 | 113 | ||
| 143 | /* ------------------------------------------------------------------------ */ | 114 | /* ------------------------------------------------------------------------ */ |
| 144 | 115 | ||
| 145 | static int writer_buf(lua_State *L, const void *p, size_t size, void *b) | 116 | static int writer_buf(lua_State *L, const void *p, size_t size, void *sb) |
| 146 | { | 117 | { |
| 147 | luaL_addlstring((luaL_Buffer *)b, (const char *)p, size); | 118 | lj_buf_putmem((SBuf *)sb, p, (MSize)size); |
| 148 | UNUSED(L); | 119 | UNUSED(L); |
| 149 | return 0; | 120 | return 0; |
| 150 | } | 121 | } |
| @@ -153,19 +124,19 @@ LJLIB_CF(string_dump) | |||
| 153 | { | 124 | { |
| 154 | GCfunc *fn = lj_lib_checkfunc(L, 1); | 125 | GCfunc *fn = lj_lib_checkfunc(L, 1); |
| 155 | int strip = L->base+1 < L->top && tvistruecond(L->base+1); | 126 | int strip = L->base+1 < L->top && tvistruecond(L->base+1); |
| 156 | luaL_Buffer b; | 127 | SBuf *sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */ |
| 157 | L->top = L->base+1; | 128 | L->top = L->base+1; |
| 158 | luaL_buffinit(L, &b); | 129 | if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip)) |
| 159 | if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, &b, strip)) | ||
| 160 | lj_err_caller(L, LJ_ERR_STRDUMP); | 130 | lj_err_caller(L, LJ_ERR_STRDUMP); |
| 161 | luaL_pushresult(&b); | 131 | setstrV(L, L->top-1, lj_buf_str(L, sb)); |
| 132 | lj_gc_check(L); | ||
| 162 | return 1; | 133 | return 1; |
| 163 | } | 134 | } |
| 164 | 135 | ||
| 165 | /* ------------------------------------------------------------------------ */ | 136 | /* ------------------------------------------------------------------------ */ |
| 166 | 137 | ||
| 167 | /* macro to `unsign' a character */ | 138 | /* macro to `unsign' a character */ |
| 168 | #define uchar(c) ((unsigned char)(c)) | 139 | #define uchar(c) ((unsigned char)(c)) |
| 169 | 140 | ||
| 170 | #define CAP_UNFINISHED (-1) | 141 | #define CAP_UNFINISHED (-1) |
| 171 | #define CAP_POSITION (-2) | 142 | #define CAP_POSITION (-2) |
| @@ -183,7 +154,6 @@ typedef struct MatchState { | |||
| 183 | } MatchState; | 154 | } MatchState; |
| 184 | 155 | ||
| 185 | #define L_ESC '%' | 156 | #define L_ESC '%' |
| 186 | #define SPECIALS "^$*+?.([%-" | ||
| 187 | 157 | ||
| 188 | static int check_capture(MatchState *ms, int l) | 158 | static int check_capture(MatchState *ms, int l) |
| 189 | { | 159 | { |
| @@ -450,30 +420,6 @@ static const char *match(MatchState *ms, const char *s, const char *p) | |||
| 450 | return s; | 420 | return s; |
| 451 | } | 421 | } |
| 452 | 422 | ||
| 453 | static const char *lmemfind(const char *s1, size_t l1, | ||
| 454 | const char *s2, size_t l2) | ||
| 455 | { | ||
| 456 | if (l2 == 0) { | ||
| 457 | return s1; /* empty strings are everywhere */ | ||
| 458 | } else if (l2 > l1) { | ||
| 459 | return NULL; /* avoids a negative `l1' */ | ||
| 460 | } else { | ||
| 461 | const char *init; /* to search for a `*s2' inside `s1' */ | ||
| 462 | l2--; /* 1st char will be checked by `memchr' */ | ||
| 463 | l1 = l1-l2; /* `s2' cannot be found after that */ | ||
| 464 | while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { | ||
| 465 | init++; /* 1st char is already checked */ | ||
| 466 | if (memcmp(init, s2+1, l2) == 0) { | ||
| 467 | return init-1; | ||
| 468 | } else { /* correct `l1' and `s1' to try again */ | ||
| 469 | l1 -= (size_t)(init-s1); | ||
| 470 | s1 = init; | ||
| 471 | } | ||
| 472 | } | ||
| 473 | return NULL; /* not found */ | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | static void push_onecapture(MatchState *ms, int i, const char *s, const char *e) | 423 | static void push_onecapture(MatchState *ms, int i, const char *s, const char *e) |
| 478 | { | 424 | { |
| 479 | if (i >= ms->level) { | 425 | if (i >= ms->level) { |
| @@ -501,64 +447,60 @@ static int push_captures(MatchState *ms, const char *s, const char *e) | |||
| 501 | return nlevels; /* number of strings pushed */ | 447 | return nlevels; /* number of strings pushed */ |
| 502 | } | 448 | } |
| 503 | 449 | ||
| 504 | static ptrdiff_t posrelat(ptrdiff_t pos, size_t len) | ||
| 505 | { | ||
| 506 | /* relative string position: negative means back from end */ | ||
| 507 | if (pos < 0) pos += (ptrdiff_t)len + 1; | ||
| 508 | return (pos >= 0) ? pos : 0; | ||
| 509 | } | ||
| 510 | |||
| 511 | static int str_find_aux(lua_State *L, int find) | 450 | static int str_find_aux(lua_State *L, int find) |
| 512 | { | 451 | { |
| 513 | size_t l1, l2; | 452 | GCstr *s = lj_lib_checkstr(L, 1); |
| 514 | const char *s = luaL_checklstring(L, 1, &l1); | 453 | GCstr *p = lj_lib_checkstr(L, 2); |
| 515 | const char *p = luaL_checklstring(L, 2, &l2); | 454 | int32_t start = lj_lib_optint(L, 3, 1); |
| 516 | ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; | 455 | MSize st; |
| 517 | if (init < 0) { | 456 | if (start < 0) start += (int32_t)s->len; else start--; |
| 518 | init = 0; | 457 | if (start < 0) start = 0; |
| 519 | } else if ((size_t)(init) > l1) { | 458 | st = (MSize)start; |
| 459 | if (st > s->len) { | ||
| 520 | #if LJ_52 | 460 | #if LJ_52 |
| 521 | setnilV(L->top-1); | 461 | setnilV(L->top-1); |
| 522 | return 1; | 462 | return 1; |
| 523 | #else | 463 | #else |
| 524 | init = (ptrdiff_t)l1; | 464 | st = s->len; |
| 525 | #endif | 465 | #endif |
| 526 | } | 466 | } |
| 527 | if (find && (lua_toboolean(L, 4) || /* explicit request? */ | 467 | if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) || |
| 528 | strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ | 468 | !lj_str_haspattern(p))) { /* Search for fixed string. */ |
| 529 | /* do a plain search */ | 469 | const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len); |
| 530 | const char *s2 = lmemfind(s+init, l1-(size_t)init, p, l2); | 470 | if (q) { |
| 531 | if (s2) { | 471 | setintV(L->top-2, (int32_t)(q-strdata(s)) + 1); |
| 532 | lua_pushinteger(L, s2-s+1); | 472 | setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len); |
| 533 | lua_pushinteger(L, s2-s+(ptrdiff_t)l2); | ||
| 534 | return 2; | 473 | return 2; |
| 535 | } | 474 | } |
| 536 | } else { | 475 | } else { /* Search for pattern. */ |
| 537 | MatchState ms; | 476 | MatchState ms; |
| 538 | int anchor = (*p == '^') ? (p++, 1) : 0; | 477 | const char *pstr = strdata(p); |
| 539 | const char *s1=s+init; | 478 | const char *sstr = strdata(s) + st; |
| 479 | int anchor = 0; | ||
| 480 | if (*pstr == '^') { pstr++; anchor = 1; } | ||
| 540 | ms.L = L; | 481 | ms.L = L; |
| 541 | ms.src_init = s; | 482 | ms.src_init = strdata(s); |
| 542 | ms.src_end = s+l1; | 483 | ms.src_end = strdata(s) + s->len; |
| 543 | do { | 484 | do { /* Loop through string and try to match the pattern. */ |
| 544 | const char *res; | 485 | const char *q; |
| 545 | ms.level = ms.depth = 0; | 486 | ms.level = ms.depth = 0; |
| 546 | if ((res=match(&ms, s1, p)) != NULL) { | 487 | q = match(&ms, sstr, pstr); |
| 488 | if (q) { | ||
| 547 | if (find) { | 489 | if (find) { |
| 548 | lua_pushinteger(L, s1-s+1); /* start */ | 490 | setintV(L->top++, (int32_t)(sstr-(strdata(s)-1))); |
| 549 | lua_pushinteger(L, res-s); /* end */ | 491 | setintV(L->top++, (int32_t)(q-strdata(s))); |
| 550 | return push_captures(&ms, NULL, 0) + 2; | 492 | return push_captures(&ms, NULL, NULL) + 2; |
| 551 | } else { | 493 | } else { |
| 552 | return push_captures(&ms, s1, res); | 494 | return push_captures(&ms, sstr, q); |
| 553 | } | 495 | } |
| 554 | } | 496 | } |
| 555 | } while (s1++ < ms.src_end && !anchor); | 497 | } while (sstr++ < ms.src_end && !anchor); |
| 556 | } | 498 | } |
| 557 | lua_pushnil(L); /* not found */ | 499 | setnilV(L->top-1); /* Not found. */ |
| 558 | return 1; | 500 | return 1; |
| 559 | } | 501 | } |
| 560 | 502 | ||
| 561 | LJLIB_CF(string_find) | 503 | LJLIB_CF(string_find) LJLIB_REC(.) |
| 562 | { | 504 | { |
| 563 | return str_find_aux(L, 1); | 505 | return str_find_aux(L, 1); |
| 564 | } | 506 | } |
| @@ -698,222 +640,16 @@ LJLIB_CF(string_gsub) | |||
| 698 | 640 | ||
| 699 | /* ------------------------------------------------------------------------ */ | 641 | /* ------------------------------------------------------------------------ */ |
| 700 | 642 | ||
| 701 | /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ | 643 | LJLIB_CF(string_format) LJLIB_REC(.) |
| 702 | #define MAX_FMTITEM 512 | ||
| 703 | /* valid flags in a format specification */ | ||
| 704 | #define FMT_FLAGS "-+ #0" | ||
| 705 | /* | ||
| 706 | ** maximum size of each format specification (such as '%-099.99d') | ||
| 707 | ** (+10 accounts for %99.99x plus margin of error) | ||
| 708 | */ | ||
| 709 | #define MAX_FMTSPEC (sizeof(FMT_FLAGS) + sizeof(LUA_INTFRMLEN) + 10) | ||
| 710 | |||
| 711 | static void addquoted(lua_State *L, luaL_Buffer *b, int arg) | ||
| 712 | { | ||
| 713 | GCstr *str = lj_lib_checkstr(L, arg); | ||
| 714 | int32_t len = (int32_t)str->len; | ||
| 715 | const char *s = strdata(str); | ||
| 716 | luaL_addchar(b, '"'); | ||
| 717 | while (len--) { | ||
| 718 | uint32_t c = uchar(*s); | ||
| 719 | if (c == '"' || c == '\\' || c == '\n') { | ||
| 720 | luaL_addchar(b, '\\'); | ||
| 721 | } else if (lj_char_iscntrl(c)) { /* This can only be 0-31 or 127. */ | ||
| 722 | uint32_t d; | ||
| 723 | luaL_addchar(b, '\\'); | ||
| 724 | if (c >= 100 || lj_char_isdigit(uchar(s[1]))) { | ||
| 725 | luaL_addchar(b, '0'+(c >= 100)); if (c >= 100) c -= 100; | ||
| 726 | goto tens; | ||
| 727 | } else if (c >= 10) { | ||
| 728 | tens: | ||
| 729 | d = (c * 205) >> 11; c -= d * 10; luaL_addchar(b, '0'+d); | ||
| 730 | } | ||
| 731 | c += '0'; | ||
| 732 | } | ||
| 733 | luaL_addchar(b, c); | ||
| 734 | s++; | ||
| 735 | } | ||
| 736 | luaL_addchar(b, '"'); | ||
| 737 | } | ||
| 738 | |||
| 739 | static const char *scanformat(lua_State *L, const char *strfrmt, char *form) | ||
| 740 | { | ||
| 741 | const char *p = strfrmt; | ||
| 742 | while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL) p++; /* skip flags */ | ||
| 743 | if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS)) | ||
| 744 | lj_err_caller(L, LJ_ERR_STRFMTR); | ||
| 745 | if (lj_char_isdigit(uchar(*p))) p++; /* skip width */ | ||
| 746 | if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */ | ||
| 747 | if (*p == '.') { | ||
| 748 | p++; | ||
| 749 | if (lj_char_isdigit(uchar(*p))) p++; /* skip precision */ | ||
| 750 | if (lj_char_isdigit(uchar(*p))) p++; /* (2 digits at most) */ | ||
| 751 | } | ||
| 752 | if (lj_char_isdigit(uchar(*p))) | ||
| 753 | lj_err_caller(L, LJ_ERR_STRFMTW); | ||
| 754 | *(form++) = '%'; | ||
| 755 | strncpy(form, strfrmt, (size_t)(p - strfrmt + 1)); | ||
| 756 | form += p - strfrmt + 1; | ||
| 757 | *form = '\0'; | ||
| 758 | return p; | ||
| 759 | } | ||
| 760 | |||
| 761 | static void addintlen(char *form) | ||
| 762 | { | ||
| 763 | size_t l = strlen(form); | ||
| 764 | char spec = form[l - 1]; | ||
| 765 | strcpy(form + l - 1, LUA_INTFRMLEN); | ||
| 766 | form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; | ||
| 767 | form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; | ||
| 768 | } | ||
| 769 | |||
| 770 | static unsigned LUA_INTFRM_T num2intfrm(lua_State *L, int arg) | ||
| 771 | { | ||
| 772 | if (sizeof(LUA_INTFRM_T) == 4) { | ||
| 773 | return (LUA_INTFRM_T)lj_lib_checkbit(L, arg); | ||
| 774 | } else { | ||
| 775 | cTValue *o; | ||
| 776 | lj_lib_checknumber(L, arg); | ||
| 777 | o = L->base+arg-1; | ||
| 778 | if (tvisint(o)) | ||
| 779 | return (LUA_INTFRM_T)intV(o); | ||
| 780 | else | ||
| 781 | return (LUA_INTFRM_T)numV(o); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 785 | static unsigned LUA_INTFRM_T num2uintfrm(lua_State *L, int arg) | ||
| 786 | { | 644 | { |
| 787 | if (sizeof(LUA_INTFRM_T) == 4) { | 645 | int retry = 0; |
| 788 | return (unsigned LUA_INTFRM_T)lj_lib_checkbit(L, arg); | 646 | SBuf *sb; |
| 789 | } else { | 647 | do { |
| 790 | cTValue *o; | 648 | sb = lj_buf_tmp_(L); |
| 791 | lj_lib_checknumber(L, arg); | 649 | retry = lj_strfmt_putarg(L, sb, 1, -retry); |
| 792 | o = L->base+arg-1; | 650 | } while (retry > 0); |
| 793 | if (tvisint(o)) | 651 | setstrV(L, L->top-1, lj_buf_str(L, sb)); |
| 794 | return (unsigned LUA_INTFRM_T)intV(o); | 652 | lj_gc_check(L); |
| 795 | else if ((int32_t)o->u32.hi < 0) | ||
| 796 | return (unsigned LUA_INTFRM_T)(LUA_INTFRM_T)numV(o); | ||
| 797 | else | ||
| 798 | return (unsigned LUA_INTFRM_T)numV(o); | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | static GCstr *meta_tostring(lua_State *L, int arg) | ||
| 803 | { | ||
| 804 | TValue *o = L->base+arg-1; | ||
| 805 | cTValue *mo; | ||
| 806 | lua_assert(o < L->top); /* Caller already checks for existence. */ | ||
| 807 | if (LJ_LIKELY(tvisstr(o))) | ||
| 808 | return strV(o); | ||
| 809 | if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { | ||
| 810 | copyTV(L, L->top++, mo); | ||
| 811 | copyTV(L, L->top++, o); | ||
| 812 | lua_call(L, 1, 1); | ||
| 813 | L->top--; | ||
| 814 | if (tvisstr(L->top)) | ||
| 815 | return strV(L->top); | ||
| 816 | o = L->base+arg-1; | ||
| 817 | copyTV(L, o, L->top); | ||
| 818 | } | ||
| 819 | if (tvisnumber(o)) { | ||
| 820 | return lj_str_fromnumber(L, o); | ||
| 821 | } else if (tvisnil(o)) { | ||
| 822 | return lj_str_newlit(L, "nil"); | ||
| 823 | } else if (tvisfalse(o)) { | ||
| 824 | return lj_str_newlit(L, "false"); | ||
| 825 | } else if (tvistrue(o)) { | ||
| 826 | return lj_str_newlit(L, "true"); | ||
| 827 | } else { | ||
| 828 | if (tvisfunc(o) && isffunc(funcV(o))) | ||
| 829 | lj_str_pushf(L, "function: builtin#%d", funcV(o)->c.ffid); | ||
| 830 | else | ||
| 831 | lj_str_pushf(L, "%s: %p", lj_typename(o), lua_topointer(L, arg)); | ||
| 832 | L->top--; | ||
| 833 | return strV(L->top); | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | LJLIB_CF(string_format) | ||
| 838 | { | ||
| 839 | int arg = 1, top = (int)(L->top - L->base); | ||
| 840 | GCstr *fmt = lj_lib_checkstr(L, arg); | ||
| 841 | const char *strfrmt = strdata(fmt); | ||
| 842 | const char *strfrmt_end = strfrmt + fmt->len; | ||
| 843 | luaL_Buffer b; | ||
| 844 | luaL_buffinit(L, &b); | ||
| 845 | while (strfrmt < strfrmt_end) { | ||
| 846 | if (*strfrmt != L_ESC) { | ||
| 847 | luaL_addchar(&b, *strfrmt++); | ||
| 848 | } else if (*++strfrmt == L_ESC) { | ||
| 849 | luaL_addchar(&b, *strfrmt++); /* %% */ | ||
| 850 | } else { /* format item */ | ||
| 851 | char form[MAX_FMTSPEC]; /* to store the format (`%...') */ | ||
| 852 | char buff[MAX_FMTITEM]; /* to store the formatted item */ | ||
| 853 | int n = 0; | ||
| 854 | if (++arg > top) | ||
| 855 | luaL_argerror(L, arg, lj_obj_typename[0]); | ||
| 856 | strfrmt = scanformat(L, strfrmt, form); | ||
| 857 | switch (*strfrmt++) { | ||
| 858 | case 'c': | ||
| 859 | n = sprintf(buff, form, lj_lib_checkint(L, arg)); | ||
| 860 | break; | ||
| 861 | case 'd': case 'i': | ||
| 862 | addintlen(form); | ||
| 863 | n = sprintf(buff, form, num2intfrm(L, arg)); | ||
| 864 | break; | ||
| 865 | case 'o': case 'u': case 'x': case 'X': | ||
| 866 | addintlen(form); | ||
| 867 | n = sprintf(buff, form, num2uintfrm(L, arg)); | ||
| 868 | break; | ||
| 869 | case 'e': case 'E': case 'f': case 'g': case 'G': case 'a': case 'A': { | ||
| 870 | TValue tv; | ||
| 871 | tv.n = lj_lib_checknum(L, arg); | ||
| 872 | if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) { | ||
| 873 | /* Canonicalize output of non-finite values. */ | ||
| 874 | char *p, nbuf[LJ_STR_NUMBUF]; | ||
| 875 | size_t len = lj_str_bufnum(nbuf, &tv); | ||
| 876 | if (strfrmt[-1] < 'a') { | ||
| 877 | nbuf[len-3] = nbuf[len-3] - 0x20; | ||
| 878 | nbuf[len-2] = nbuf[len-2] - 0x20; | ||
| 879 | nbuf[len-1] = nbuf[len-1] - 0x20; | ||
| 880 | } | ||
| 881 | nbuf[len] = '\0'; | ||
| 882 | for (p = form; *p < 'A' && *p != '.'; p++) ; | ||
| 883 | *p++ = 's'; *p = '\0'; | ||
| 884 | n = sprintf(buff, form, nbuf); | ||
| 885 | break; | ||
| 886 | } | ||
| 887 | n = sprintf(buff, form, (double)tv.n); | ||
| 888 | break; | ||
| 889 | } | ||
| 890 | case 'q': | ||
| 891 | addquoted(L, &b, arg); | ||
| 892 | continue; | ||
| 893 | case 'p': | ||
| 894 | lj_str_pushf(L, "%p", lua_topointer(L, arg)); | ||
| 895 | luaL_addvalue(&b); | ||
| 896 | continue; | ||
| 897 | case 's': { | ||
| 898 | GCstr *str = meta_tostring(L, arg); | ||
| 899 | if (!strchr(form, '.') && str->len >= 100) { | ||
| 900 | /* no precision and string is too long to be formatted; | ||
| 901 | keep original string */ | ||
| 902 | setstrV(L, L->top++, str); | ||
| 903 | luaL_addvalue(&b); | ||
| 904 | continue; | ||
| 905 | } | ||
| 906 | n = sprintf(buff, form, strdata(str)); | ||
| 907 | break; | ||
| 908 | } | ||
| 909 | default: | ||
| 910 | lj_err_callerv(L, LJ_ERR_STRFMTO, *(strfrmt -1)); | ||
| 911 | break; | ||
| 912 | } | ||
| 913 | luaL_addlstring(&b, buff, n); | ||
| 914 | } | ||
| 915 | } | ||
| 916 | luaL_pushresult(&b); | ||
| 917 | return 1; | 653 | return 1; |
| 918 | } | 654 | } |
| 919 | 655 | ||
| @@ -926,16 +662,15 @@ LUALIB_API int luaopen_string(lua_State *L) | |||
| 926 | GCtab *mt; | 662 | GCtab *mt; |
| 927 | global_State *g; | 663 | global_State *g; |
| 928 | LJ_LIB_REG(L, LUA_STRLIBNAME, string); | 664 | LJ_LIB_REG(L, LUA_STRLIBNAME, string); |
| 929 | #if defined(LUA_COMPAT_GFIND) && !LJ_52 | ||
| 930 | lua_getfield(L, -1, "gmatch"); | ||
| 931 | lua_setfield(L, -2, "gfind"); | ||
| 932 | #endif | ||
| 933 | mt = lj_tab_new(L, 0, 1); | 665 | mt = lj_tab_new(L, 0, 1); |
| 934 | /* NOBARRIER: basemt is a GC root. */ | 666 | /* NOBARRIER: basemt is a GC root. */ |
| 935 | g = G(L); | 667 | g = G(L); |
| 936 | setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt)); | 668 | setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt)); |
| 937 | settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1)); | 669 | settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1)); |
| 938 | mt->nomm = (uint8_t)(~(1u<<MM_index)); | 670 | mt->nomm = (uint8_t)(~(1u<<MM_index)); |
| 671 | #if LJ_HASBUFFER | ||
| 672 | lj_lib_prereg(L, LUA_STRLIBNAME ".buffer", luaopen_string_buffer, tabV(L->top-1)); | ||
| 673 | #endif | ||
| 939 | return 1; | 674 | return 1; |
| 940 | } | 675 | } |
| 941 | 676 | ||
