diff options
Diffstat (limited to 'src/lj_strfmt.c')
-rw-r--r-- | src/lj_strfmt.c | 221 |
1 files changed, 185 insertions, 36 deletions
diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c index e8fe2538..b44350e7 100644 --- a/src/lj_strfmt.c +++ b/src/lj_strfmt.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include "lj_obj.h" | 11 | #include "lj_obj.h" |
12 | #include "lj_buf.h" | 12 | #include "lj_buf.h" |
13 | #include "lj_str.h" | ||
13 | #include "lj_state.h" | 14 | #include "lj_state.h" |
14 | #include "lj_char.h" | 15 | #include "lj_char.h" |
15 | #include "lj_strfmt.h" | 16 | #include "lj_strfmt.h" |
@@ -86,35 +87,124 @@ retlit: | |||
86 | return fs->len ? STRFMT_LIT : STRFMT_EOF; | 87 | return fs->len ? STRFMT_LIT : STRFMT_EOF; |
87 | } | 88 | } |
88 | 89 | ||
89 | /* -- Formatted conversions to buffer ------------------------------------- */ | 90 | /* -- Raw conversions ----------------------------------------------------- */ |
90 | 91 | ||
91 | /* Add formatted char to buffer. */ | 92 | /* Write number to bufer. */ |
92 | SBuf *lj_strfmt_putchar(SBuf *sb, SFormat sf, int32_t c) | 93 | char * LJ_FASTCALL lj_strfmt_wnum(char *p, cTValue *o) |
93 | { | 94 | { |
94 | MSize width = STRFMT_WIDTH(sf); | 95 | if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ |
95 | char *p = lj_buf_more(sb, width > 1 ? width : 1); | 96 | #if __BIONIC__ |
96 | if ((sf & STRFMT_F_LEFT)) *p++ = (char)c; | 97 | if (tvismzero(o)) { *p++ = '-'; *p++ = '0'; return p; } |
97 | while (width-- > 1) *p++ = ' '; | 98 | #endif |
98 | if (!(sf & STRFMT_F_LEFT)) *p++ = (char)c; | 99 | return p + lua_number2str(p, o->n); |
99 | setsbufP(sb, p); | 100 | } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { |
101 | *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; | ||
102 | } else if ((o->u32.hi & 0x80000000) == 0) { | ||
103 | *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; | ||
104 | } else { | ||
105 | *p++ = '-'; *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; | ||
106 | } | ||
107 | return p; | ||
108 | } | ||
109 | |||
110 | #define WINT_R(x, sh, sc) \ | ||
111 | { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); } | ||
112 | |||
113 | /* Write integer to buffer. */ | ||
114 | char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k) | ||
115 | { | ||
116 | uint32_t u = (uint32_t)k; | ||
117 | if (k < 0) { u = (uint32_t)-k; *p++ = '-'; } | ||
118 | if (u < 10000) { | ||
119 | if (u < 10) goto dig1; if (u < 100) goto dig2; if (u < 1000) goto dig3; | ||
120 | } else { | ||
121 | uint32_t v = u / 10000; u -= v * 10000; | ||
122 | if (v < 10000) { | ||
123 | if (v < 10) goto dig5; if (v < 100) goto dig6; if (v < 1000) goto dig7; | ||
124 | } else { | ||
125 | uint32_t w = v / 10000; v -= w * 10000; | ||
126 | if (w >= 10) WINT_R(w, 10, 10) | ||
127 | *p++ = (char)('0'+w); | ||
128 | } | ||
129 | WINT_R(v, 23, 1000) | ||
130 | dig7: WINT_R(v, 12, 100) | ||
131 | dig6: WINT_R(v, 10, 10) | ||
132 | dig5: *p++ = (char)('0'+v); | ||
133 | } | ||
134 | WINT_R(u, 23, 1000) | ||
135 | dig3: WINT_R(u, 12, 100) | ||
136 | dig2: WINT_R(u, 10, 10) | ||
137 | dig1: *p++ = (char)('0'+u); | ||
138 | return p; | ||
139 | } | ||
140 | #undef WINT_R | ||
141 | |||
142 | /* Write pointer to buffer. */ | ||
143 | char * LJ_FASTCALL lj_strfmt_wptr(char *p, const void *v) | ||
144 | { | ||
145 | ptrdiff_t x = (ptrdiff_t)v; | ||
146 | MSize i, n = STRFMT_MAXBUF_PTR; | ||
147 | if (x == 0) { | ||
148 | *p++ = 'N'; *p++ = 'U'; *p++ = 'L'; *p++ = 'L'; | ||
149 | return p; | ||
150 | } | ||
151 | #if LJ_64 | ||
152 | /* Shorten output for 64 bit pointers. */ | ||
153 | n = 2+2*4+((x >> 32) ? 2+2*(lj_fls((uint32_t)(x >> 32))>>3) : 0); | ||
154 | #endif | ||
155 | p[0] = '0'; | ||
156 | p[1] = 'x'; | ||
157 | for (i = n-1; i >= 2; i--, x >>= 4) | ||
158 | p[i] = "0123456789abcdef"[(x & 15)]; | ||
159 | return p+n; | ||
160 | } | ||
161 | |||
162 | /* Write ULEB128 to buffer. */ | ||
163 | char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v) | ||
164 | { | ||
165 | for (; v >= 0x80; v >>= 7) | ||
166 | *p++ = (char)((v & 0x7f) | 0x80); | ||
167 | *p++ = (char)v; | ||
168 | return p; | ||
169 | } | ||
170 | |||
171 | /* Return string or write number to buffer and return pointer to start. */ | ||
172 | const char *lj_strfmt_wstrnum(char *buf, cTValue *o, MSize *lenp) | ||
173 | { | ||
174 | if (tvisstr(o)) { | ||
175 | *lenp = strV(o)->len; | ||
176 | return strVdata(o); | ||
177 | } else if (tvisint(o)) { | ||
178 | *lenp = (MSize)(lj_strfmt_wint(buf, intV(o)) - buf); | ||
179 | return buf; | ||
180 | } else if (tvisnum(o)) { | ||
181 | *lenp = (MSize)(lj_strfmt_wnum(buf, o) - buf); | ||
182 | return buf; | ||
183 | } else { | ||
184 | return NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /* -- Unformatted conversions to buffer ----------------------------------- */ | ||
189 | |||
190 | /* Add integer to buffer. */ | ||
191 | SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k) | ||
192 | { | ||
193 | setsbufP(sb, lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT), k)); | ||
100 | return sb; | 194 | return sb; |
101 | } | 195 | } |
102 | 196 | ||
103 | /* Add formatted string to buffer. */ | 197 | #if LJ_HASJIT |
104 | SBuf *lj_strfmt_putstr(SBuf *sb, SFormat sf, GCstr *str) | 198 | /* Add number to buffer. */ |
199 | SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o) | ||
105 | { | 200 | { |
106 | MSize len = str->len <= STRFMT_PREC(sf) ? str->len : STRFMT_PREC(sf); | 201 | setsbufP(sb, lj_strfmt_wnum(lj_buf_more(sb, STRFMT_MAXBUF_NUM), o)); |
107 | MSize width = STRFMT_WIDTH(sf); | ||
108 | char *p = lj_buf_more(sb, width > len ? width : len); | ||
109 | if ((sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); | ||
110 | while (width-- > len) *p++ = ' '; | ||
111 | if (!(sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); | ||
112 | setsbufP(sb, p); | ||
113 | return sb; | 202 | return sb; |
114 | } | 203 | } |
204 | #endif | ||
115 | 205 | ||
116 | /* Add quoted string to buffer (no formatting). */ | 206 | /* Add quoted string to buffer. */ |
117 | SBuf *lj_strfmt_putquoted(SBuf *sb, GCstr *str) | 207 | SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) |
118 | { | 208 | { |
119 | const char *s = strdata(str); | 209 | const char *s = strdata(str); |
120 | MSize len = str->len; | 210 | MSize len = str->len; |
@@ -143,10 +233,37 @@ SBuf *lj_strfmt_putquoted(SBuf *sb, GCstr *str) | |||
143 | return sb; | 233 | return sb; |
144 | } | 234 | } |
145 | 235 | ||
236 | /* -- Formatted conversions to buffer ------------------------------------- */ | ||
237 | |||
238 | /* Add formatted char to buffer. */ | ||
239 | SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat sf, int32_t c) | ||
240 | { | ||
241 | MSize width = STRFMT_WIDTH(sf); | ||
242 | char *p = lj_buf_more(sb, width > 1 ? width : 1); | ||
243 | if ((sf & STRFMT_F_LEFT)) *p++ = (char)c; | ||
244 | while (width-- > 1) *p++ = ' '; | ||
245 | if (!(sf & STRFMT_F_LEFT)) *p++ = (char)c; | ||
246 | setsbufP(sb, p); | ||
247 | return sb; | ||
248 | } | ||
249 | |||
250 | /* Add formatted string to buffer. */ | ||
251 | SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat sf, GCstr *str) | ||
252 | { | ||
253 | MSize len = str->len <= STRFMT_PREC(sf) ? str->len : STRFMT_PREC(sf); | ||
254 | MSize width = STRFMT_WIDTH(sf); | ||
255 | char *p = lj_buf_more(sb, width > len ? width : len); | ||
256 | if ((sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); | ||
257 | while (width-- > len) *p++ = ' '; | ||
258 | if (!(sf & STRFMT_F_LEFT)) p = lj_buf_wmem(p, strdata(str), len); | ||
259 | setsbufP(sb, p); | ||
260 | return sb; | ||
261 | } | ||
262 | |||
146 | /* Add formatted signed/unsigned integer to buffer. */ | 263 | /* Add formatted signed/unsigned integer to buffer. */ |
147 | SBuf *lj_strfmt_putxint(SBuf *sb, SFormat sf, uint64_t k) | 264 | SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k) |
148 | { | 265 | { |
149 | char buf[1+22], *q = buf + sizeof(buf), *p; | 266 | char buf[STRFMT_MAXBUF_XINT], *q = buf + sizeof(buf), *p; |
150 | #ifdef LUA_USE_ASSERT | 267 | #ifdef LUA_USE_ASSERT |
151 | char *ps; | 268 | char *ps; |
152 | #endif | 269 | #endif |
@@ -217,31 +334,31 @@ SBuf *lj_strfmt_putxint(SBuf *sb, SFormat sf, uint64_t k) | |||
217 | } | 334 | } |
218 | 335 | ||
219 | /* Add number formatted as signed integer to buffer. */ | 336 | /* Add number formatted as signed integer to buffer. */ |
220 | SBuf *lj_strfmt_putnum_int(SBuf *sb, SFormat sf, lua_Number n) | 337 | SBuf *lj_strfmt_putfnum_int(SBuf *sb, SFormat sf, lua_Number n) |
221 | { | 338 | { |
222 | int64_t k = (int64_t)n; | 339 | int64_t k = (int64_t)n; |
223 | if (checki32(k) && sf == STRFMT_INT) | 340 | if (checki32(k) && sf == STRFMT_INT) |
224 | return lj_buf_putint(sb, k); /* Shortcut for plain %d. */ | 341 | return lj_strfmt_putint(sb, k); /* Shortcut for plain %d. */ |
225 | else | 342 | else |
226 | return lj_strfmt_putxint(sb, sf, (uint64_t)k); | 343 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); |
227 | } | 344 | } |
228 | 345 | ||
229 | /* Add number formatted as unsigned integer to buffer. */ | 346 | /* Add number formatted as unsigned integer to buffer. */ |
230 | SBuf *lj_strfmt_putnum_uint(SBuf *sb, SFormat sf, lua_Number n) | 347 | SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n) |
231 | { | 348 | { |
232 | int64_t k; | 349 | int64_t k; |
233 | if (n >= 9223372036854775808.0) | 350 | if (n >= 9223372036854775808.0) |
234 | k = (int64_t)(n - 18446744073709551616.0); | 351 | k = (int64_t)(n - 18446744073709551616.0); |
235 | else | 352 | else |
236 | k = (int64_t)n; | 353 | k = (int64_t)n; |
237 | return lj_strfmt_putxint(sb, sf, (uint64_t)k); | 354 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); |
238 | } | 355 | } |
239 | 356 | ||
240 | /* Max. sprintf buffer size needed. At least #string.format("%.99f", -1e308). */ | 357 | /* Max. sprintf buffer size needed. At least #string.format("%.99f", -1e308). */ |
241 | #define STRFMT_FMTNUMBUF 512 | 358 | #define STRFMT_FMTNUMBUF 512 |
242 | 359 | ||
243 | /* Add formatted floating-point number to buffer. */ | 360 | /* Add formatted floating-point number to buffer. */ |
244 | SBuf *lj_strfmt_putnum(SBuf *sb, SFormat sf, lua_Number n) | 361 | SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat sf, lua_Number n) |
245 | { | 362 | { |
246 | TValue tv; | 363 | TValue tv; |
247 | tv.n = n; | 364 | tv.n = n; |
@@ -296,13 +413,45 @@ SBuf *lj_strfmt_putnum(SBuf *sb, SFormat sf, lua_Number n) | |||
296 | 413 | ||
297 | /* -- Conversions to strings ---------------------------------------------- */ | 414 | /* -- Conversions to strings ---------------------------------------------- */ |
298 | 415 | ||
416 | /* Convert integer to string. */ | ||
417 | GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k) | ||
418 | { | ||
419 | char buf[STRFMT_MAXBUF_INT]; | ||
420 | MSize len = (MSize)(lj_strfmt_wint(buf, k) - buf); | ||
421 | return lj_str_new(L, buf, len); | ||
422 | } | ||
423 | |||
424 | /* Convert number to string. */ | ||
425 | GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o) | ||
426 | { | ||
427 | char buf[STRFMT_MAXBUF_NUM]; | ||
428 | MSize len = (MSize)(lj_strfmt_wnum(buf, o) - buf); | ||
429 | return lj_str_new(L, buf, len); | ||
430 | } | ||
431 | |||
432 | /* Convert integer or number to string. */ | ||
433 | GCstr * LJ_FASTCALL lj_strfmt_number(lua_State *L, cTValue *o) | ||
434 | { | ||
435 | return tvisint(o) ? lj_strfmt_int(L, intV(o)) : lj_strfmt_num(L, o); | ||
436 | } | ||
437 | |||
438 | #if LJ_HASJIT | ||
439 | /* Convert char value to string. */ | ||
440 | GCstr * LJ_FASTCALL lj_strfmt_char(lua_State *L, int c) | ||
441 | { | ||
442 | char buf[1]; | ||
443 | buf[0] = c; | ||
444 | return lj_str_new(L, buf, 1); | ||
445 | } | ||
446 | #endif | ||
447 | |||
299 | /* Raw conversion of object to string. */ | 448 | /* Raw conversion of object to string. */ |
300 | GCstr *lj_strfmt_obj(lua_State *L, cTValue *o) | 449 | GCstr *lj_strfmt_obj(lua_State *L, cTValue *o) |
301 | { | 450 | { |
302 | if (tvisstr(o)) { | 451 | if (tvisstr(o)) { |
303 | return strV(o); | 452 | return strV(o); |
304 | } else if (tvisnumber(o)) { | 453 | } else if (tvisnumber(o)) { |
305 | return lj_str_fromnumber(L, o); | 454 | return lj_strfmt_number(L, o); |
306 | } else if (tvisnil(o)) { | 455 | } else if (tvisnil(o)) { |
307 | return lj_str_newlit(L, "nil"); | 456 | return lj_str_newlit(L, "nil"); |
308 | } else if (tvisfalse(o)) { | 457 | } else if (tvisfalse(o)) { |
@@ -315,9 +464,9 @@ GCstr *lj_strfmt_obj(lua_State *L, cTValue *o) | |||
315 | *p++ = ':'; *p++ = ' '; | 464 | *p++ = ':'; *p++ = ' '; |
316 | if (tvisfunc(o) && isffunc(funcV(o))) { | 465 | if (tvisfunc(o) && isffunc(funcV(o))) { |
317 | p = lj_buf_wmem(p, "builtin#", 8); | 466 | p = lj_buf_wmem(p, "builtin#", 8); |
318 | p = lj_str_bufint(p, funcV(o)->c.ffid); | 467 | p = lj_strfmt_wint(p, funcV(o)->c.ffid); |
319 | } else { | 468 | } else { |
320 | p = lj_str_bufptr(p, lj_obj_ptr(o)); | 469 | p = lj_strfmt_wptr(p, lj_obj_ptr(o)); |
321 | } | 470 | } |
322 | return lj_str_new(L, buf, (size_t)(p - buf)); | 471 | return lj_str_new(L, buf, (size_t)(p - buf)); |
323 | } | 472 | } |
@@ -350,15 +499,15 @@ const char *lj_strfmt_pushvf(lua_State *L, const char *fmt, va_list argp) | |||
350 | lj_buf_putmem(sb, fs.str, fs.len); | 499 | lj_buf_putmem(sb, fs.str, fs.len); |
351 | break; | 500 | break; |
352 | case STRFMT_INT: | 501 | case STRFMT_INT: |
353 | lj_strfmt_putxint(sb, sf, va_arg(argp, int32_t)); | 502 | lj_strfmt_putfxint(sb, sf, va_arg(argp, int32_t)); |
354 | break; | 503 | break; |
355 | case STRFMT_UINT: | 504 | case STRFMT_UINT: |
356 | lj_strfmt_putxint(sb, sf, va_arg(argp, uint32_t)); | 505 | lj_strfmt_putfxint(sb, sf, va_arg(argp, uint32_t)); |
357 | break; | 506 | break; |
358 | case STRFMT_NUM: { | 507 | case STRFMT_NUM: { |
359 | TValue tv; | 508 | TValue tv; |
360 | tv.n = va_arg(argp, lua_Number); | 509 | tv.n = va_arg(argp, lua_Number); |
361 | setsbufP(sb, lj_str_bufnum(lj_buf_more(sb, LJ_STR_NUMBUF), &tv)); | 510 | setsbufP(sb, lj_strfmt_wnum(lj_buf_more(sb, STRFMT_MAXBUF_NUM), &tv)); |
362 | break; | 511 | break; |
363 | } | 512 | } |
364 | case STRFMT_STR: { | 513 | case STRFMT_STR: { |
@@ -371,8 +520,8 @@ const char *lj_strfmt_pushvf(lua_State *L, const char *fmt, va_list argp) | |||
371 | lj_buf_putb(sb, va_arg(argp, int)); | 520 | lj_buf_putb(sb, va_arg(argp, int)); |
372 | break; | 521 | break; |
373 | case STRFMT_PTR: | 522 | case STRFMT_PTR: |
374 | setsbufP(sb, lj_str_bufptr(lj_buf_more(sb, LJ_STR_PTRBUF), | 523 | setsbufP(sb, lj_strfmt_wptr(lj_buf_more(sb, STRFMT_MAXBUF_PTR), |
375 | va_arg(argp, void *))); | 524 | va_arg(argp, void *))); |
376 | break; | 525 | break; |
377 | case STRFMT_ERR: | 526 | case STRFMT_ERR: |
378 | default: | 527 | default: |