diff options
Diffstat (limited to 'src/lj_str.c')
-rw-r--r-- | src/lj_str.c | 140 |
1 files changed, 65 insertions, 75 deletions
diff --git a/src/lj_str.c b/src/lj_str.c index 6548ee4d..9eb04c57 100644 --- a/src/lj_str.c +++ b/src/lj_str.c | |||
@@ -1,9 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | ** String handling. | 2 | ** String handling. |
3 | ** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h | 3 | ** Copyright (C) 2005-2013 Mike Pall. See Copyright Notice in luajit.h |
4 | ** | ||
5 | ** Portions taken verbatim or adapted from the Lua interpreter. | ||
6 | ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h | ||
7 | */ | 4 | */ |
8 | 5 | ||
9 | #include <stdio.h> | 6 | #include <stdio.h> |
@@ -14,6 +11,7 @@ | |||
14 | #include "lj_obj.h" | 11 | #include "lj_obj.h" |
15 | #include "lj_gc.h" | 12 | #include "lj_gc.h" |
16 | #include "lj_err.h" | 13 | #include "lj_err.h" |
14 | #include "lj_buf.h" | ||
17 | #include "lj_str.h" | 15 | #include "lj_str.h" |
18 | #include "lj_state.h" | 16 | #include "lj_state.h" |
19 | #include "lj_char.h" | 17 | #include "lj_char.h" |
@@ -170,14 +168,14 @@ void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s) | |||
170 | /* -- Type conversions ---------------------------------------------------- */ | 168 | /* -- Type conversions ---------------------------------------------------- */ |
171 | 169 | ||
172 | /* Print number to buffer. Canonicalizes non-finite values. */ | 170 | /* Print number to buffer. Canonicalizes non-finite values. */ |
173 | size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) | 171 | MSize LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) |
174 | { | 172 | { |
175 | if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ | 173 | if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ |
176 | lua_Number n = o->n; | 174 | lua_Number n = o->n; |
177 | #if __BIONIC__ | 175 | #if __BIONIC__ |
178 | if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; } | 176 | if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; } |
179 | #endif | 177 | #endif |
180 | return (size_t)lua_number2str(s, n); | 178 | return (MSize)lua_number2str(s, n); |
181 | } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { | 179 | } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { |
182 | s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3; | 180 | s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3; |
183 | } else if ((o->u32.hi & 0x80000000) == 0) { | 181 | } else if ((o->u32.hi & 0x80000000) == 0) { |
@@ -187,30 +185,68 @@ size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) | |||
187 | } | 185 | } |
188 | } | 186 | } |
189 | 187 | ||
190 | /* Print integer to buffer. Returns pointer to start. */ | 188 | /* Print integer to buffer. Returns pointer to start (!= buffer start). */ |
191 | char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k) | 189 | static char *str_bufint(char *p, int32_t k) |
192 | { | 190 | { |
193 | uint32_t u = (uint32_t)(k < 0 ? -k : k); | 191 | uint32_t u = (uint32_t)(k < 0 ? -k : k); |
194 | p += 1+10; | 192 | p += LJ_STR_INTBUF; |
195 | do { *--p = (char)('0' + u % 10); } while (u /= 10); | 193 | do { *--p = (char)('0' + u % 10); } while (u /= 10); |
196 | if (k < 0) *--p = '-'; | 194 | if (k < 0) *--p = '-'; |
197 | return p; | 195 | return p; |
198 | } | 196 | } |
199 | 197 | ||
198 | /* Print pointer to buffer. */ | ||
199 | MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v) | ||
200 | { | ||
201 | ptrdiff_t x = (ptrdiff_t)v; | ||
202 | MSize i, n = LJ_STR_PTRBUF; | ||
203 | if (x == 0) { | ||
204 | p[0] = 'N'; p[1] = 'U'; p[2] = 'L'; p[3] = 'L'; | ||
205 | return 4; | ||
206 | } | ||
207 | #if LJ_64 | ||
208 | /* Shorten output for 64 bit pointers. */ | ||
209 | n = 2+2*4+((x >> 32) ? 2+2*(lj_fls((uint32_t)(x >> 32))>>3) : 0); | ||
210 | #endif | ||
211 | p[0] = '0'; | ||
212 | p[1] = 'x'; | ||
213 | for (i = n-1; i >= 2; i--, x >>= 4) | ||
214 | p[i] = "0123456789abcdef"[(x & 15)]; | ||
215 | return n; | ||
216 | } | ||
217 | |||
218 | /* Print TValue to buffer (only for numbers) and return pointer to start. */ | ||
219 | const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp) | ||
220 | { | ||
221 | if (tvisstr(o)) { | ||
222 | *lenp = strV(o)->len; | ||
223 | return strVdata(o); | ||
224 | } else if (tvisint(o)) { | ||
225 | char *p = str_bufint(buf, intV(o)); | ||
226 | *lenp = (MSize)(buf+LJ_STR_INTBUF-p); | ||
227 | return p; | ||
228 | } else if (tvisnum(o)) { | ||
229 | *lenp = lj_str_bufnum(buf, o); | ||
230 | return buf; | ||
231 | } else { | ||
232 | return NULL; | ||
233 | } | ||
234 | } | ||
235 | |||
200 | /* Convert number to string. */ | 236 | /* Convert number to string. */ |
201 | GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np) | 237 | GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np) |
202 | { | 238 | { |
203 | char buf[LJ_STR_NUMBUF]; | 239 | char buf[LJ_STR_NUMBUF]; |
204 | size_t len = lj_str_bufnum(buf, (TValue *)np); | 240 | MSize len = lj_str_bufnum(buf, (TValue *)np); |
205 | return lj_str_new(L, buf, len); | 241 | return lj_str_new(L, buf, len); |
206 | } | 242 | } |
207 | 243 | ||
208 | /* Convert integer to string. */ | 244 | /* Convert integer to string. */ |
209 | GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k) | 245 | GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k) |
210 | { | 246 | { |
211 | char s[1+10]; | 247 | char buf[LJ_STR_INTBUF]; |
212 | char *p = lj_str_bufint(s, k); | 248 | char *p = str_bufint(buf, k); |
213 | return lj_str_new(L, p, (size_t)(s+sizeof(s)-p)); | 249 | return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p)); |
214 | } | 250 | } |
215 | 251 | ||
216 | GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o) | 252 | GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o) |
@@ -220,54 +256,32 @@ GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o) | |||
220 | 256 | ||
221 | /* -- String formatting --------------------------------------------------- */ | 257 | /* -- String formatting --------------------------------------------------- */ |
222 | 258 | ||
223 | static void addstr(lua_State *L, SBuf *sb, const char *str, MSize len) | ||
224 | { | ||
225 | char *p; | ||
226 | MSize i; | ||
227 | if (sb->n + len > sb->sz) { | ||
228 | MSize sz = sb->sz * 2; | ||
229 | while (sb->n + len > sz) sz = sz * 2; | ||
230 | lj_str_resizebuf(L, sb, sz); | ||
231 | } | ||
232 | p = sb->buf + sb->n; | ||
233 | sb->n += len; | ||
234 | for (i = 0; i < len; i++) p[i] = str[i]; | ||
235 | } | ||
236 | |||
237 | static void addchar(lua_State *L, SBuf *sb, int c) | ||
238 | { | ||
239 | if (sb->n + 1 > sb->sz) { | ||
240 | MSize sz = sb->sz * 2; | ||
241 | lj_str_resizebuf(L, sb, sz); | ||
242 | } | ||
243 | sb->buf[sb->n++] = (char)c; | ||
244 | } | ||
245 | |||
246 | /* Push formatted message as a string object to Lua stack. va_list variant. */ | 259 | /* Push formatted message as a string object to Lua stack. va_list variant. */ |
247 | const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp) | 260 | const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp) |
248 | { | 261 | { |
249 | SBuf *sb = &G(L)->tmpbuf; | 262 | SBuf *sb = &G(L)->tmpbuf; |
250 | lj_str_needbuf(L, sb, (MSize)strlen(fmt)); | 263 | setsbufL(sb, L); |
251 | lj_str_resetbuf(sb); | 264 | lj_buf_need(sb, (MSize)strlen(fmt)); |
265 | lj_buf_reset(sb); | ||
252 | for (;;) { | 266 | for (;;) { |
253 | const char *e = strchr(fmt, '%'); | 267 | const char *e = strchr(fmt, '%'); |
254 | if (e == NULL) break; | 268 | if (e == NULL) break; |
255 | addstr(L, sb, fmt, (MSize)(e-fmt)); | 269 | lj_buf_putmem(sb, fmt, (MSize)(e-fmt)); |
256 | /* This function only handles %s, %c, %d, %f and %p formats. */ | 270 | /* This function only handles %s, %c, %d, %f and %p formats. */ |
257 | switch (e[1]) { | 271 | switch (e[1]) { |
258 | case 's': { | 272 | case 's': { |
259 | const char *s = va_arg(argp, char *); | 273 | const char *s = va_arg(argp, char *); |
260 | if (s == NULL) s = "(null)"; | 274 | if (s == NULL) s = "(null)"; |
261 | addstr(L, sb, s, (MSize)strlen(s)); | 275 | lj_buf_putmem(sb, s, (MSize)strlen(s)); |
262 | break; | 276 | break; |
263 | } | 277 | } |
264 | case 'c': | 278 | case 'c': |
265 | addchar(L, sb, va_arg(argp, int)); | 279 | lj_buf_putb(sb, va_arg(argp, int)); |
266 | break; | 280 | break; |
267 | case 'd': { | 281 | case 'd': { |
268 | char buf[LJ_STR_INTBUF]; | 282 | char buf[LJ_STR_INTBUF]; |
269 | char *p = lj_str_bufint(buf, va_arg(argp, int32_t)); | 283 | char *p = str_bufint(buf, va_arg(argp, int32_t)); |
270 | addstr(L, sb, p, (MSize)(buf+LJ_STR_INTBUF-p)); | 284 | lj_buf_putmem(sb, p, (MSize)(buf+LJ_STR_INTBUF-p)); |
271 | break; | 285 | break; |
272 | } | 286 | } |
273 | case 'f': { | 287 | case 'f': { |
@@ -276,41 +290,28 @@ const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp) | |||
276 | MSize len; | 290 | MSize len; |
277 | tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER)); | 291 | tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER)); |
278 | len = (MSize)lj_str_bufnum(buf, &tv); | 292 | len = (MSize)lj_str_bufnum(buf, &tv); |
279 | addstr(L, sb, buf, len); | 293 | lj_buf_putmem(sb, buf, len); |
280 | break; | 294 | break; |
281 | } | 295 | } |
282 | case 'p': { | 296 | case 'p': { |
283 | #define FMTP_CHARS (2*sizeof(ptrdiff_t)) | 297 | #define FMTP_CHARS (2*sizeof(ptrdiff_t)) |
284 | char buf[2+FMTP_CHARS]; | 298 | char buf[LJ_STR_PTRBUF]; |
285 | ptrdiff_t p = (ptrdiff_t)(va_arg(argp, void *)); | 299 | MSize len = lj_str_bufptr(buf, va_arg(argp, void *)); |
286 | ptrdiff_t i, lasti = 2+FMTP_CHARS; | 300 | lj_buf_putmem(sb, buf, len); |
287 | if (p == 0) { | ||
288 | addstr(L, sb, "NULL", 4); | ||
289 | break; | ||
290 | } | ||
291 | #if LJ_64 | ||
292 | /* Shorten output for 64 bit pointers. */ | ||
293 | lasti = 2+2*4+((p >> 32) ? 2+2*(lj_fls((uint32_t)(p >> 32))>>3) : 0); | ||
294 | #endif | ||
295 | buf[0] = '0'; | ||
296 | buf[1] = 'x'; | ||
297 | for (i = lasti-1; i >= 2; i--, p >>= 4) | ||
298 | buf[i] = "0123456789abcdef"[(p & 15)]; | ||
299 | addstr(L, sb, buf, (MSize)lasti); | ||
300 | break; | 301 | break; |
301 | } | 302 | } |
302 | case '%': | 303 | case '%': |
303 | addchar(L, sb, '%'); | 304 | lj_buf_putb(sb, '%'); |
304 | break; | 305 | break; |
305 | default: | 306 | default: |
306 | addchar(L, sb, '%'); | 307 | lj_buf_putb(sb, '%'); |
307 | addchar(L, sb, e[1]); | 308 | lj_buf_putb(sb, e[1]); |
308 | break; | 309 | break; |
309 | } | 310 | } |
310 | fmt = e+2; | 311 | fmt = e+2; |
311 | } | 312 | } |
312 | addstr(L, sb, fmt, (MSize)strlen(fmt)); | 313 | lj_buf_putmem(sb, fmt, (MSize)strlen(fmt)); |
313 | setstrV(L, L->top, lj_str_new(L, sb->buf, sb->n)); | 314 | setstrV(L, L->top, lj_buf_str(L, sb)); |
314 | incr_top(L); | 315 | incr_top(L); |
315 | return strVdata(L->top - 1); | 316 | return strVdata(L->top - 1); |
316 | } | 317 | } |
@@ -326,14 +327,3 @@ const char *lj_str_pushf(lua_State *L, const char *fmt, ...) | |||
326 | return msg; | 327 | return msg; |
327 | } | 328 | } |
328 | 329 | ||
329 | /* -- Buffer handling ----------------------------------------------------- */ | ||
330 | |||
331 | char *lj_str_needbuf(lua_State *L, SBuf *sb, MSize sz) | ||
332 | { | ||
333 | if (sz > sb->sz) { | ||
334 | if (sz < LJ_MIN_SBUF) sz = LJ_MIN_SBUF; | ||
335 | lj_str_resizebuf(L, sb, sz); | ||
336 | } | ||
337 | return sb->buf; | ||
338 | } | ||
339 | |||