|
|
@ -392,126 +392,144 @@ void luaO_tostring (lua_State *L, TValue *obj) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* size for buffer used by 'luaO_pushvfstring' */ |
|
|
|
/* size for buffer space used by 'luaO_pushvfstring' */ |
|
|
|
#define BUFVFS 400 |
|
|
|
|
|
|
|
/* buffer used by 'luaO_pushvfstring' */ |
|
|
|
typedef struct BuffFS { |
|
|
|
int blen; /* length of partial string in 'buff' */ |
|
|
|
char buff[BUFVFS]; /* holds last part of the result */ |
|
|
|
int pushed; /* number of string pieces already on the stack */ |
|
|
|
int blen; /* length of partial string in 'space' */ |
|
|
|
char space[BUFVFS]; /* holds last part of the result */ |
|
|
|
} BuffFS; |
|
|
|
|
|
|
|
|
|
|
|
static void pushstr (lua_State *L, const char *str, size_t l) { |
|
|
|
/*
|
|
|
|
** Push given string to the stack, as part of the buffer. If the stack |
|
|
|
** is almost full, join all partial strings in the stack into one. |
|
|
|
*/ |
|
|
|
static void pushstr (lua_State *L, BuffFS *buff, const char *str, size_t l) { |
|
|
|
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); |
|
|
|
L->top++; |
|
|
|
buff->pushed++; |
|
|
|
if (buff->pushed > 1 && L->top + 2 > L->stack_last) { |
|
|
|
luaV_concat(L, buff->pushed); /* join all partial results into one */ |
|
|
|
buff->pushed = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** empty the buffer into the stack |
|
|
|
** empty the buffer space into the stack |
|
|
|
*/ |
|
|
|
static void clearbuff (lua_State *L, BuffFS *buff) { |
|
|
|
pushstr(L, buff->buff, buff->blen); /* push buffer */ |
|
|
|
buff->blen = 0; /* buffer now is empty */ |
|
|
|
pushstr(L, buff, buff->space, buff->blen); /* push buffer contents */ |
|
|
|
buff->blen = 0; /* space now is empty */ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Add 'str' to the buffer. It buffer has no enough space, |
|
|
|
** empty the buffer. If string is still larger than the buffer, |
|
|
|
** push the string directly to the stack. Return number of items |
|
|
|
** pushed. |
|
|
|
** Get a space of size 'sz' in the buffer. If buffer has not enough |
|
|
|
** space, empty it. 'sz' must fit in an empty space. |
|
|
|
*/ |
|
|
|
static int addstr2buff (lua_State *L, BuffFS *buff, const char *str, |
|
|
|
size_t slen) { |
|
|
|
int pushed = 0; /* number of items pushed to the stack */ |
|
|
|
lua_assert(buff->blen <= BUFVFS); |
|
|
|
if (slen > BUFVFS - cast_sizet(buff->blen)) { /* string does not fit? */ |
|
|
|
static char *getbuff (lua_State *L, BuffFS *buff, size_t sz) { |
|
|
|
lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS); |
|
|
|
if (sz > BUFVFS - cast_sizet(buff->blen)) /* string does not fit? */ |
|
|
|
clearbuff(L, buff); |
|
|
|
pushed = 1; |
|
|
|
if (slen >= BUFVFS) { /* string still does not fit into buffer? */ |
|
|
|
pushstr(L, str, slen); /* push string */ |
|
|
|
return 2; |
|
|
|
} |
|
|
|
return buff->space + buff->blen; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#define addsize(b,sz) ((b)->blen += (sz)) |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Add 'str' to the buffer. If string is larger than the buffer space, |
|
|
|
** push the string directly to the stack. |
|
|
|
*/ |
|
|
|
static void addstr2buff (lua_State *L, BuffFS *buff, const char *str, |
|
|
|
size_t slen) { |
|
|
|
if (slen <= BUFVFS) { /* does string fit into buffer? */ |
|
|
|
char *bf = getbuff(L, buff, slen); |
|
|
|
memcpy(bf, str, slen); /* add string to buffer */ |
|
|
|
addsize(buff, slen); |
|
|
|
} |
|
|
|
else { /* string larger than buffer */ |
|
|
|
clearbuff(L, buff); /* string comes after buffer's content */ |
|
|
|
pushstr(L, buff, str, slen); /* push string */ |
|
|
|
} |
|
|
|
memcpy(buff->buff + buff->blen, str, slen); /* add string to buffer */ |
|
|
|
buff->blen += slen; |
|
|
|
return pushed; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Add a number to the buffer; return number of strings pushed into |
|
|
|
** the stack. (At most one, to free buffer space.) |
|
|
|
** Add a number to the buffer. |
|
|
|
*/ |
|
|
|
static int addnum2buff (lua_State *L, BuffFS *buff, TValue *num) { |
|
|
|
char numbuff[MAXNUMBER2STR]; |
|
|
|
static void addnum2buff (lua_State *L, BuffFS *buff, TValue *num) { |
|
|
|
char *numbuff = getbuff(L, buff, MAXNUMBER2STR); |
|
|
|
size_t len = tostringbuff(num, numbuff); /* format number into 'numbuff' */ |
|
|
|
return addstr2buff(L, buff, numbuff, len); |
|
|
|
addsize(buff, len); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** this function handles only '%d', '%c', '%f', '%p', and '%s' |
|
|
|
** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%' |
|
|
|
conventional formats, plus Lua-specific '%I' and '%U' |
|
|
|
*/ |
|
|
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { |
|
|
|
BuffFS buff; /* holds last part of the result */ |
|
|
|
int pushed = 0; /* number of strings in the stack to concatenate */ |
|
|
|
const char *e; /* points to next '%' */ |
|
|
|
buff.blen = 0; |
|
|
|
buff.pushed = buff.blen = 0; |
|
|
|
while ((e = strchr(fmt, '%')) != NULL) { |
|
|
|
pushed += addstr2buff(L, &buff, fmt, e - fmt); /* add 'fmt' up to '%' */ |
|
|
|
addstr2buff(L, &buff, fmt, e - fmt); /* add 'fmt' up to '%' */ |
|
|
|
switch (*(e + 1)) { /* conversion specifier */ |
|
|
|
case 's': { /* zero-terminated string */ |
|
|
|
const char *s = va_arg(argp, char *); |
|
|
|
if (s == NULL) s = "(null)"; |
|
|
|
pushed += addstr2buff(L, &buff, s, strlen(s)); |
|
|
|
addstr2buff(L, &buff, s, strlen(s)); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'c': { /* an 'int' as a character */ |
|
|
|
/* if non-printable character, print its code */ |
|
|
|
char bf[10]; |
|
|
|
char *bf = getbuff(L, &buff, 10); |
|
|
|
int c = va_arg(argp, int); |
|
|
|
int l = (lisprint(c)) ? l_sprintf(bf, sizeof(bf), "%c", c) |
|
|
|
: l_sprintf(bf, sizeof(bf), "<\\%u>", c); |
|
|
|
pushed += addstr2buff(L, &buff, bf, l); |
|
|
|
int len = (lisprint(c)) ? l_sprintf(bf, 10, "%c", c) |
|
|
|
: l_sprintf(bf, 10, "<\\%u>", c); |
|
|
|
addsize(&buff, len); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'd': { /* an 'int' */ |
|
|
|
TValue num; |
|
|
|
setivalue(&num, va_arg(argp, int)); |
|
|
|
pushed += addnum2buff(L, &buff, &num); |
|
|
|
addnum2buff(L, &buff, &num); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'I': { /* a 'lua_Integer' */ |
|
|
|
TValue num; |
|
|
|
setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt))); |
|
|
|
pushed += addnum2buff(L, &buff, &num); |
|
|
|
addnum2buff(L, &buff, &num); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'f': { /* a 'lua_Number' */ |
|
|
|
TValue num; |
|
|
|
setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber))); |
|
|
|
pushed += addnum2buff(L, &buff, &num); |
|
|
|
addnum2buff(L, &buff, &num); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'p': { /* a pointer */ |
|
|
|
char bf[3 * sizeof(void*) + 8]; /* should be enough space for '%p' */ |
|
|
|
const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */ |
|
|
|
char *bf = getbuff(L, &buff, sz); |
|
|
|
void *p = va_arg(argp, void *); |
|
|
|
int l = l_sprintf(bf, sizeof(bf), "%p", p); |
|
|
|
pushed += addstr2buff(L, &buff, bf, l); |
|
|
|
int len = l_sprintf(bf, sz, "%p", p); |
|
|
|
addsize(&buff, len); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 'U': { /* a 'long' as a UTF-8 sequence */ |
|
|
|
char bf[UTF8BUFFSZ]; |
|
|
|
int l = luaO_utf8esc(bf, va_arg(argp, long)); |
|
|
|
pushed += addstr2buff(L, &buff, bf + UTF8BUFFSZ - l, l); |
|
|
|
int len = luaO_utf8esc(bf, va_arg(argp, long)); |
|
|
|
addstr2buff(L, &buff, bf + UTF8BUFFSZ - len, len); |
|
|
|
break; |
|
|
|
} |
|
|
|
case '%': { |
|
|
|
pushed += addstr2buff(L, &buff, "%", 1); |
|
|
|
addstr2buff(L, &buff, "%", 1); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: { |
|
|
@ -519,16 +537,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { |
|
|
|
*(e + 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (pushed > 1 && L->top + 2 > L->stack_last) { /* no free stack space? */ |
|
|
|
luaV_concat(L, pushed); /* join all partial results into one */ |
|
|
|
pushed = 1; |
|
|
|
} |
|
|
|
fmt = e + 2; /* skip '%' and the specifier */ |
|
|
|
} |
|
|
|
pushed += addstr2buff(L, &buff, fmt, strlen(fmt)); /* rest of 'fmt' */ |
|
|
|
addstr2buff(L, &buff, fmt, strlen(fmt)); /* rest of 'fmt' */ |
|
|
|
clearbuff(L, &buff); /* empty buffer into the stack */ |
|
|
|
if (pushed > 0) |
|
|
|
luaV_concat(L, pushed + 1); /* join all partial results */ |
|
|
|
if (buff.pushed > 1) |
|
|
|
luaV_concat(L, buff.pushed); /* join all partial results */ |
|
|
|
return svalue(s2v(L->top - 1)); |
|
|
|
} |
|
|
|
|
|
|
|