aboutsummaryrefslogtreecommitdiff
path: root/lobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'lobject.c')
-rw-r--r--lobject.c144
1 files changed, 107 insertions, 37 deletions
diff --git a/lobject.c b/lobject.c
index 67c37124..123f0e57 100644
--- a/lobject.c
+++ b/lobject.c
@@ -364,25 +364,44 @@ int luaO_utf8esc (char *buff, unsigned long x) {
364 364
365 365
366/* 366/*
367** Convert a number object to a string 367** Convert a number object to a string, adding it to a buffer
368*/ 368*/
369void luaO_tostring (lua_State *L, TValue *obj) { 369static size_t tostringbuff (TValue *obj, char *buff) {
370 char buff[MAXNUMBER2STR];
371 size_t len; 370 size_t len;
372 lua_assert(ttisnumber(obj)); 371 lua_assert(ttisnumber(obj));
373 if (ttisinteger(obj)) 372 if (ttisinteger(obj))
374 len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); 373 len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
375 else { 374 else {
376 len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); 375 len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj));
377 if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ 376 if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
378 buff[len++] = lua_getlocaledecpoint(); 377 buff[len++] = lua_getlocaledecpoint();
379 buff[len++] = '0'; /* adds '.0' to result */ 378 buff[len++] = '0'; /* adds '.0' to result */
380 } 379 }
381 } 380 }
381 return len;
382}
383
384
385/*
386** Convert a number object to a Lua string, replacing the value at 'obj'
387*/
388void luaO_tostring (lua_State *L, TValue *obj) {
389 char buff[MAXNUMBER2STR];
390 size_t len = tostringbuff(obj, buff);
382 setsvalue(L, obj, luaS_newlstr(L, buff, len)); 391 setsvalue(L, obj, luaS_newlstr(L, buff, len));
383} 392}
384 393
385 394
395/* size for buffer used by 'luaO_pushvfstring' */
396#define BUFVFS 400
397
398/* buffer used by 'luaO_pushvfstring' */
399typedef struct BuffFS {
400 int blen; /* length of partial string in 'buff' */
401 char buff[BUFVFS]; /* holds last part of the result */
402} BuffFS;
403
404
386static void pushstr (lua_State *L, const char *str, size_t l) { 405static void pushstr (lua_State *L, const char *str, size_t l) {
387 setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); 406 setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
388 L->top++; 407 L->top++;
@@ -390,59 +409,109 @@ static void pushstr (lua_State *L, const char *str, size_t l) {
390 409
391 410
392/* 411/*
412** empty the buffer into the stack
413*/
414static void clearbuff (lua_State *L, BuffFS *buff) {
415 pushstr(L, buff->buff, buff->blen); /* push buffer */
416 buff->blen = 0; /* buffer now is empty */
417}
418
419
420/*
421** Add 'str' to the buffer. It buffer has no enough space,
422** empty the buffer. If string is still larger than the buffer,
423** push the string directly to the stack. Return number of items
424** pushed.
425*/
426static int addstr2buff (lua_State *L, BuffFS *buff, const char *str,
427 size_t slen) {
428 int pushed = 0; /* number of items pushed to the stack */
429 lua_assert(buff->blen <= BUFVFS);
430 if (slen > BUFVFS - cast_sizet(buff->blen)) { /* string does not fit? */
431 clearbuff(L, buff);
432 pushed = 1;
433 if (slen >= BUFVFS) { /* string still does not fit into buffer? */
434 pushstr(L, str, slen); /* push string */
435 return 2;
436 }
437 }
438 memcpy(buff->buff + buff->blen, str, slen); /* add string to buffer */
439 buff->blen += slen;
440 return pushed;
441}
442
443
444/*
445** Add a number to the buffer; return number of strings pushed into
446** the stack. (At most one, to free buffer space.)
447*/
448static int addnum2buff (lua_State *L, BuffFS *buff, TValue *num) {
449 char numbuff[MAXNUMBER2STR];
450 size_t len = tostringbuff(num, numbuff); /* format number into 'numbuff' */
451 return addstr2buff(L, buff, numbuff, len);
452}
453
454
455/*
393** this function handles only '%d', '%c', '%f', '%p', and '%s' 456** this function handles only '%d', '%c', '%f', '%p', and '%s'
394 conventional formats, plus Lua-specific '%I' and '%U' 457 conventional formats, plus Lua-specific '%I' and '%U'
395*/ 458*/
396const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { 459const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
397 int n = 0; /* number of strings in the stack to concatenate */ 460 BuffFS buff; /* holds last part of the result */
398 const char *e; /* points to next conversion specifier */ 461 int pushed = 0; /* number of strings in the stack to concatenate */
462 const char *e; /* points to next '%' */
463 buff.blen = 0;
399 while ((e = strchr(fmt, '%')) != NULL) { 464 while ((e = strchr(fmt, '%')) != NULL) {
400 pushstr(L, fmt, e - fmt); /* string up to conversion specifier */ 465 pushed += addstr2buff(L, &buff, fmt, e - fmt); /* add 'fmt' up to '%' */
401 switch (*(e+1)) { 466 switch (*(e + 1)) { /* conversion specifier */
402 case 's': { /* zero-terminated string */ 467 case 's': { /* zero-terminated string */
403 const char *s = va_arg(argp, char *); 468 const char *s = va_arg(argp, char *);
404 if (s == NULL) s = "(null)"; 469 if (s == NULL) s = "(null)";
405 pushstr(L, s, strlen(s)); 470 pushed += addstr2buff(L, &buff, s, strlen(s));
406 break; 471 break;
407 } 472 }
408 case 'c': { /* an 'int' as a character */ 473 case 'c': { /* an 'int' as a character */
409 char buff = cast_char(va_arg(argp, int)); 474 /* if non-printable character, print its code */
410 if (lisprint(cast_uchar(buff))) 475 char bf[10];
411 pushstr(L, &buff, 1); 476 int c = va_arg(argp, int);
412 else /* non-printable character; print its code */ 477 int l = (lisprint(c)) ? l_sprintf(bf, sizeof(bf), "%c", c)
413 luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); 478 : l_sprintf(bf, sizeof(bf), "<\\%u>", c);
479 pushed += addstr2buff(L, &buff, bf, l);
414 break; 480 break;
415 } 481 }
416 case 'd': { /* an 'int' */ 482 case 'd': { /* an 'int' */
417 setivalue(s2v(L->top), va_arg(argp, int)); 483 TValue num;
418 goto top2str; 484 setivalue(&num, va_arg(argp, int));
485 pushed += addnum2buff(L, &buff, &num);
486 break;
419 } 487 }
420 case 'I': { /* a 'lua_Integer' */ 488 case 'I': { /* a 'lua_Integer' */
421 setivalue(s2v(L->top), cast(lua_Integer, va_arg(argp, l_uacInt))); 489 TValue num;
422 goto top2str; 490 setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt)));
491 pushed += addnum2buff(L, &buff, &num);
492 break;
423 } 493 }
424 case 'f': { /* a 'lua_Number' */ 494 case 'f': { /* a 'lua_Number' */
425 setfltvalue(s2v(L->top), cast_num(va_arg(argp, l_uacNumber))); 495 TValue num;
426 top2str: /* convert the top element to a string */ 496 setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber)));
427 L->top++; 497 pushed += addnum2buff(L, &buff, &num);
428 luaO_tostring(L, s2v(L->top - 1));
429 break; 498 break;
430 } 499 }
431 case 'p': { /* a pointer */ 500 case 'p': { /* a pointer */
432 char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ 501 char bf[3 * sizeof(void*) + 8]; /* should be enough space for '%p' */
433 void *p = va_arg(argp, void *); 502 void *p = va_arg(argp, void *);
434 int l = lua_pointer2str(buff, sizeof(buff), p); 503 int l = l_sprintf(bf, sizeof(bf), "%p", p);
435 pushstr(L, buff, l); 504 pushed += addstr2buff(L, &buff, bf, l);
436 break; 505 break;
437 } 506 }
438 case 'U': { /* a 'long' as a UTF-8 sequence */ 507 case 'U': { /* a 'long' as a UTF-8 sequence */
439 char buff[UTF8BUFFSZ]; 508 char bf[UTF8BUFFSZ];
440 int l = luaO_utf8esc(buff, va_arg(argp, long)); 509 int l = luaO_utf8esc(bf, va_arg(argp, long));
441 pushstr(L, buff + UTF8BUFFSZ - l, l); 510 pushed += addstr2buff(L, &buff, bf + UTF8BUFFSZ - l, l);
442 break; 511 break;
443 } 512 }
444 case '%': { 513 case '%': {
445 pushstr(L, "%", 1); 514 pushed += addstr2buff(L, &buff, "%", 1);
446 break; 515 break;
447 } 516 }
448 default: { 517 default: {
@@ -450,15 +519,16 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
450 *(e + 1)); 519 *(e + 1));
451 } 520 }
452 } 521 }
453 n += 2; 522 if (pushed > 1 && L->top + 2 > L->stack_last) { /* no free stack space? */
454 if (L->top + 2 > L->stack_last) { /* no free stack space? */ 523 luaV_concat(L, pushed); /* join all partial results into one */
455 luaV_concat(L, n); 524 pushed = 1;
456 n = 1;
457 } 525 }
458 fmt = e + 2; 526 fmt = e + 2; /* skip '%' and the specifier */
459 } 527 }
460 pushstr(L, fmt, strlen(fmt)); 528 pushed += addstr2buff(L, &buff, fmt, strlen(fmt)); /* rest of 'fmt' */
461 if (n > 0) luaV_concat(L, n + 1); 529 clearbuff(L, &buff); /* empty buffer into the stack */
530 if (pushed > 0)
531 luaV_concat(L, pushed + 1); /* join all partial results */
462 return svalue(s2v(L->top - 1)); 532 return svalue(s2v(L->top - 1));
463} 533}
464 534