diff options
Diffstat (limited to 'src/lib_string.c')
-rw-r--r-- | src/lib_string.c | 453 |
1 files changed, 130 insertions, 323 deletions
diff --git a/src/lib_string.c b/src/lib_string.c index c1e595c9..76b0730a 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,12 +124,12 @@ 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 | ||
@@ -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,91 @@ LJLIB_CF(string_gsub) | |||
698 | 640 | ||
699 | /* ------------------------------------------------------------------------ */ | 641 | /* ------------------------------------------------------------------------ */ |
700 | 642 | ||
701 | /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ | 643 | /* Emulate tostring() inline. */ |
702 | #define MAX_FMTITEM 512 | 644 | static GCstr *string_fmt_tostring(lua_State *L, int arg, int retry) |
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 | { | ||
787 | if (sizeof(LUA_INTFRM_T) == 4) { | ||
788 | return (unsigned LUA_INTFRM_T)lj_lib_checkbit(L, arg); | ||
789 | } else { | ||
790 | cTValue *o; | ||
791 | lj_lib_checknumber(L, arg); | ||
792 | o = L->base+arg-1; | ||
793 | if (tvisint(o)) | ||
794 | return (unsigned LUA_INTFRM_T)intV(o); | ||
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 | { | 645 | { |
804 | TValue *o = L->base+arg-1; | 646 | TValue *o = L->base+arg-1; |
805 | cTValue *mo; | 647 | cTValue *mo; |
806 | lua_assert(o < L->top); /* Caller already checks for existence. */ | 648 | lua_assert(o < L->top); /* Caller already checks for existence. */ |
807 | if (LJ_LIKELY(tvisstr(o))) | 649 | if (LJ_LIKELY(tvisstr(o))) |
808 | return strV(o); | 650 | return strV(o); |
809 | if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { | 651 | if (retry != 2 && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { |
810 | copyTV(L, L->top++, mo); | 652 | copyTV(L, L->top++, mo); |
811 | copyTV(L, L->top++, o); | 653 | copyTV(L, L->top++, o); |
812 | lua_call(L, 1, 1); | 654 | lua_call(L, 1, 1); |
813 | L->top--; | 655 | copyTV(L, L->base+arg-1, --L->top); |
814 | if (tvisstr(L->top)) | 656 | return NULL; /* Buffer may be overwritten, retry. */ |
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 | } | 657 | } |
835 | } | 658 | return lj_strfmt_obj(L, o); |
836 | 659 | } | |
837 | LJLIB_CF(string_format) | 660 | |
838 | { | 661 | LJLIB_CF(string_format) LJLIB_REC(.) |
839 | int arg = 1, top = (int)(L->top - L->base); | 662 | { |
840 | GCstr *fmt = lj_lib_checkstr(L, arg); | 663 | int arg, top = (int)(L->top - L->base); |
841 | const char *strfrmt = strdata(fmt); | 664 | GCstr *fmt; |
842 | const char *strfrmt_end = strfrmt + fmt->len; | 665 | SBuf *sb; |
843 | luaL_Buffer b; | 666 | FormatState fs; |
844 | luaL_buffinit(L, &b); | 667 | SFormat sf; |
845 | while (strfrmt < strfrmt_end) { | 668 | int retry = 0; |
846 | if (*strfrmt != L_ESC) { | 669 | again: |
847 | luaL_addchar(&b, *strfrmt++); | 670 | arg = 1; |
848 | } else if (*++strfrmt == L_ESC) { | 671 | sb = lj_buf_tmp_(L); |
849 | luaL_addchar(&b, *strfrmt++); /* %% */ | 672 | fmt = lj_lib_checkstr(L, arg); |
850 | } else { /* format item */ | 673 | lj_strfmt_init(&fs, strdata(fmt), fmt->len); |
851 | char form[MAX_FMTSPEC]; /* to store the format (`%...') */ | 674 | while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { |
852 | char buff[MAX_FMTITEM]; /* to store the formatted item */ | 675 | if (sf == STRFMT_LIT) { |
853 | int n = 0; | 676 | lj_buf_putmem(sb, fs.str, fs.len); |
677 | } else if (sf == STRFMT_ERR) { | ||
678 | lj_err_callerv(L, LJ_ERR_STRFMT, strdata(lj_str_new(L, fs.str, fs.len))); | ||
679 | } else { | ||
854 | if (++arg > top) | 680 | if (++arg > top) |
855 | luaL_argerror(L, arg, lj_obj_typename[0]); | 681 | luaL_argerror(L, arg, lj_obj_typename[0]); |
856 | strfrmt = scanformat(L, strfrmt, form); | 682 | switch (STRFMT_TYPE(sf)) { |
857 | switch (*strfrmt++) { | 683 | case STRFMT_INT: |
858 | case 'c': | 684 | if (tvisint(L->base+arg-1)) { |
859 | n = sprintf(buff, form, lj_lib_checkint(L, arg)); | 685 | int32_t k = intV(L->base+arg-1); |
686 | if (sf == STRFMT_INT) | ||
687 | lj_strfmt_putint(sb, k); /* Shortcut for plain %d. */ | ||
688 | else | ||
689 | lj_strfmt_putfxint(sb, sf, k); | ||
690 | } else { | ||
691 | lj_strfmt_putfnum_int(sb, sf, lj_lib_checknum(L, arg)); | ||
692 | } | ||
860 | break; | 693 | break; |
861 | case 'd': case 'i': | 694 | case STRFMT_UINT: |
862 | addintlen(form); | 695 | if (tvisint(L->base+arg-1)) |
863 | n = sprintf(buff, form, num2intfrm(L, arg)); | 696 | lj_strfmt_putfxint(sb, sf, intV(L->base+arg-1)); |
697 | else | ||
698 | lj_strfmt_putfnum_uint(sb, sf, lj_lib_checknum(L, arg)); | ||
864 | break; | 699 | break; |
865 | case 'o': case 'u': case 'x': case 'X': | 700 | case STRFMT_NUM: |
866 | addintlen(form); | 701 | lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg)); |
867 | n = sprintf(buff, form, num2uintfrm(L, arg)); | ||
868 | break; | 702 | break; |
869 | case 'e': case 'E': case 'f': case 'g': case 'G': case 'a': case 'A': { | 703 | case STRFMT_STR: { |
870 | TValue tv; | 704 | GCstr *str = string_fmt_tostring(L, arg, retry); |
871 | tv.n = lj_lib_checknum(L, arg); | 705 | if (str == NULL) |
872 | if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) { | 706 | retry = 1; |
873 | /* Canonicalize output of non-finite values. */ | 707 | else if ((sf & STRFMT_T_QUOTED)) |
874 | char *p, nbuf[LJ_STR_NUMBUF]; | 708 | lj_strfmt_putquoted(sb, str); /* No formatting. */ |
875 | size_t len = lj_str_bufnum(nbuf, &tv); | 709 | else |
876 | if (strfrmt[-1] < 'a') { | 710 | lj_strfmt_putfstr(sb, sf, str); |
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; | 711 | break; |
889 | } | 712 | } |
890 | case 'q': | 713 | case STRFMT_CHAR: |
891 | addquoted(L, &b, arg); | 714 | lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg)); |
892 | continue; | 715 | break; |
893 | case 'p': | 716 | case STRFMT_PTR: /* No formatting. */ |
894 | lj_str_pushf(L, "%p", lua_topointer(L, arg)); | 717 | lj_strfmt_putptr(sb, lj_obj_ptr(L->base+arg-1)); |
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; | 718 | break; |
908 | } | ||
909 | default: | 719 | default: |
910 | lj_err_callerv(L, LJ_ERR_STRFMTO, *(strfrmt -1)); | 720 | lua_assert(0); |
911 | break; | 721 | break; |
912 | } | 722 | } |
913 | luaL_addlstring(&b, buff, n); | ||
914 | } | 723 | } |
915 | } | 724 | } |
916 | luaL_pushresult(&b); | 725 | if (retry++ == 1) goto again; |
726 | setstrV(L, L->top-1, lj_buf_str(L, sb)); | ||
727 | lj_gc_check(L); | ||
917 | return 1; | 728 | return 1; |
918 | } | 729 | } |
919 | 730 | ||
@@ -926,10 +737,6 @@ LUALIB_API int luaopen_string(lua_State *L) | |||
926 | GCtab *mt; | 737 | GCtab *mt; |
927 | global_State *g; | 738 | global_State *g; |
928 | LJ_LIB_REG(L, LUA_STRLIBNAME, string); | 739 | 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); | 740 | mt = lj_tab_new(L, 0, 1); |
934 | /* NOBARRIER: basemt is a GC root. */ | 741 | /* NOBARRIER: basemt is a GC root. */ |
935 | g = G(L); | 742 | g = G(L); |