@@ -364,101 +364,171 @@ int luaO_utf8esc (char *buff, unsigned long x) {
364364
365365
366366/*
367- ** Convert a number object to a string
367+ ** Convert a number object to a string, adding it to a buffer
368368*/
369- void luaO_tostring (lua_State * L , TValue * obj ) {
370- char buff [MAXNUMBER2STR ];
369+ static size_t tostringbuff (TValue * obj , char * buff ) {
371370 size_t len ;
372371 lua_assert (ttisnumber (obj ));
373372 if (ttisinteger (obj ))
374- len = lua_integer2str (buff , sizeof ( buff ) , ivalue (obj ));
373+ len = lua_integer2str (buff , MAXNUMBER2STR , ivalue (obj ));
375374 else {
376- len = lua_number2str (buff , sizeof ( buff ) , fltvalue (obj ));
375+ len = lua_number2str (buff , MAXNUMBER2STR , fltvalue (obj ));
377376 if (buff [strspn (buff , "-0123456789" )] == '\0' ) { /* looks like an int? */
378377 buff [len ++ ] = lua_getlocaledecpoint ();
379378 buff [len ++ ] = '0' ; /* adds '.0' to result */
380379 }
381380 }
381+ return len ;
382+ }
383+
384+
385+ /*
386+ ** Convert a number object to a Lua string, replacing the value at 'obj'
387+ */
388+ void luaO_tostring (lua_State * L , TValue * obj ) {
389+ char buff [MAXNUMBER2STR ];
390+ size_t len = tostringbuff (obj , buff );
382391 setsvalue (L , obj , luaS_newlstr (L , buff , len ));
383392}
384393
385394
395+ /* size for buffer used by 'luaO_pushvfstring' */
396+ #define BUFVFS 400
397+
398+ /* buffer used by 'luaO_pushvfstring' */
399+ typedef 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+
386405static void pushstr (lua_State * L , const char * str , size_t l ) {
387406 setsvalue2s (L , L -> top , luaS_newlstr (L , str , l ));
388407 L -> top ++ ;
389408}
390409
391410
411+ /*
412+ ** empty the buffer into the stack
413+ */
414+ static 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+ */
426+ static 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+ */
448+ static 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+
392455/*
393456** this function handles only '%d', '%c', '%f', '%p', and '%s'
394457 conventional formats, plus Lua-specific '%I' and '%U'
395458*/
396459const char * luaO_pushvfstring (lua_State * L , const char * fmt , va_list argp ) {
397- int n = 0 ; /* number of strings in the stack to concatenate */
398- const char * e ; /* points to next conversion specifier */
460+ BuffFS buff ; /* holds last part of the result */
461+ int pushed = 0 ; /* number of strings in the stack to concatenate */
462+ const char * e ; /* points to next '%' */
463+ buff .blen = 0 ;
399464 while ((e = strchr (fmt , '%' )) != NULL ) {
400- pushstr (L , fmt , e - fmt ); /* string up to conversion specifier */
401- switch (* (e + 1 )) {
465+ pushed += addstr2buff (L , & buff , fmt , e - fmt ); /* add 'fmt' up to '%' */
466+ switch (* (e + 1 )) { /* conversion specifier */
402467 case 's' : { /* zero-terminated string */
403468 const char * s = va_arg (argp , char * );
404469 if (s == NULL ) s = "(null)" ;
405- pushstr ( L , s , strlen (s ));
470+ pushed += addstr2buff ( L , & buff , s , strlen (s ));
406471 break ;
407472 }
408473 case 'c' : { /* an 'int' as a character */
409- char buff = cast_char (va_arg (argp , int ));
410- if (lisprint (cast_uchar (buff )))
411- pushstr (L , & buff , 1 );
412- else /* non-printable character; print its code */
413- luaO_pushfstring (L , "<\\%d>" , cast_uchar (buff ));
474+ /* if non-printable character, print its code */
475+ char bf [10 ];
476+ int c = va_arg (argp , int );
477+ int l = (lisprint (c )) ? l_sprintf (bf , sizeof (bf ), "%c" , c )
478+ : l_sprintf (bf , sizeof (bf ), "<\\%u>" , c );
479+ pushed += addstr2buff (L , & buff , bf , l );
414480 break ;
415481 }
416482 case 'd' : { /* an 'int' */
417- setivalue (s2v (L -> top ), va_arg (argp , int ));
418- goto top2str ;
483+ TValue num ;
484+ setivalue (& num , va_arg (argp , int ));
485+ pushed += addnum2buff (L , & buff , & num );
486+ break ;
419487 }
420488 case 'I' : { /* a 'lua_Integer' */
421- setivalue (s2v (L -> top ), cast (lua_Integer , va_arg (argp , l_uacInt )));
422- goto top2str ;
489+ TValue num ;
490+ setivalue (& num , cast (lua_Integer , va_arg (argp , l_uacInt )));
491+ pushed += addnum2buff (L , & buff , & num );
492+ break ;
423493 }
424494 case 'f' : { /* a 'lua_Number' */
425- setfltvalue (s2v (L -> top ), cast_num (va_arg (argp , l_uacNumber )));
426- top2str : /* convert the top element to a string */
427- L -> top ++ ;
428- luaO_tostring (L , s2v (L -> top - 1 ));
495+ TValue num ;
496+ setfltvalue (& num , cast_num (va_arg (argp , l_uacNumber )));
497+ pushed += addnum2buff (L , & buff , & num );
429498 break ;
430499 }
431500 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' */
433502 void * p = va_arg (argp , void * );
434- int l = lua_pointer2str ( buff , sizeof (buff ) , p );
435- pushstr (L , buff , l );
503+ int l = l_sprintf ( bf , sizeof (bf ), "%p" , p );
504+ pushed += addstr2buff (L , & buff , bf , l );
436505 break ;
437506 }
438507 case 'U' : { /* a 'long' as a UTF-8 sequence */
439- char buff [UTF8BUFFSZ ];
440- int l = luaO_utf8esc (buff , va_arg (argp , long ));
441- pushstr (L , buff + UTF8BUFFSZ - l , l );
508+ char bf [UTF8BUFFSZ ];
509+ int l = luaO_utf8esc (bf , va_arg (argp , long ));
510+ pushed += addstr2buff (L , & buff , bf + UTF8BUFFSZ - l , l );
442511 break ;
443512 }
444513 case '%' : {
445- pushstr ( L , "%" , 1 );
514+ pushed += addstr2buff ( L , & buff , "%" , 1 );
446515 break ;
447516 }
448517 default : {
449518 luaG_runerror (L , "invalid option '%%%c' to 'lua_pushfstring'" ,
450519 * (e + 1 ));
451520 }
452521 }
453- n += 2 ;
454- if (L -> top + 2 > L -> stack_last ) { /* no free stack space? */
455- luaV_concat (L , n );
456- n = 1 ;
522+ if (pushed > 1 && L -> top + 2 > L -> stack_last ) { /* no free stack space? */
523+ luaV_concat (L , pushed ); /* join all partial results into one */
524+ pushed = 1 ;
457525 }
458- fmt = e + 2 ;
526+ fmt = e + 2 ; /* skip '%' and the specifier */
459527 }
460- pushstr (L , fmt , strlen (fmt ));
461- if (n > 0 ) luaV_concat (L , n + 1 );
528+ pushed += addstr2buff (L , & buff , fmt , strlen (fmt )); /* rest of 'fmt' */
529+ clearbuff (L , & buff ); /* empty buffer into the stack */
530+ if (pushed > 0 )
531+ luaV_concat (L , pushed + 1 ); /* join all partial results */
462532 return svalue (s2v (L -> top - 1 ));
463533}
464534
0 commit comments