|
@ -1090,13 +1090,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* valid flags in a format specification */ |
|
|
/* valid flags in a format specification */ |
|
|
#if !defined(L_FMTFLAGS) |
|
|
#if !defined(L_FMTFLAGSF) |
|
|
#define L_FMTFLAGS "-+ #0" |
|
|
|
|
|
|
|
|
/* valid flags for a, A, e, E, f, F, g, and G conversions */ |
|
|
|
|
|
#define L_FMTFLAGSF "-+#0 " |
|
|
|
|
|
|
|
|
|
|
|
/* valid flags for o, x, and X conversions */ |
|
|
|
|
|
#define L_FMTFLAGSX "-#0" |
|
|
|
|
|
|
|
|
|
|
|
/* valid flags for d and i conversions */ |
|
|
|
|
|
#define L_FMTFLAGSI "-+0 " |
|
|
|
|
|
|
|
|
|
|
|
/* valid flags for u conversions */ |
|
|
|
|
|
#define L_FMTFLAGSU "-0" |
|
|
|
|
|
|
|
|
|
|
|
/* valid flags for c, p, and s conversions */ |
|
|
|
|
|
#define L_FMTFLAGSC "-" |
|
|
|
|
|
|
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
/*
|
|
|
** maximum size of each format specification (such as "%-099.99d") |
|
|
** Maximum size of each format specification (such as "%-099.99d"): |
|
|
|
|
|
** Initial '%', flags (up to 5), width (2), period, precision (2), |
|
|
|
|
|
** length modifier (8), conversion specifier, and final '\0', plus some |
|
|
|
|
|
** extra. |
|
|
*/ |
|
|
*/ |
|
|
#define MAX_FORMAT 32 |
|
|
#define MAX_FORMAT 32 |
|
|
|
|
|
|
|
@ -1189,25 +1207,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { |
|
|
static const char *get2digits (const char *s) { |
|
|
const char *p = strfrmt; |
|
|
if (isdigit(uchar(*s))) { |
|
|
while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */ |
|
|
s++; |
|
|
if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char)) |
|
|
if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ |
|
|
luaL_error(L, "invalid format (repeated flags)"); |
|
|
} |
|
|
if (isdigit(uchar(*p))) p++; /* skip width */ |
|
|
return s; |
|
|
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ |
|
|
} |
|
|
if (*p == '.') { |
|
|
|
|
|
p++; |
|
|
|
|
|
if (isdigit(uchar(*p))) p++; /* skip precision */ |
|
|
/*
|
|
|
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ |
|
|
** Chech whether a conversion specification is valid. When called, |
|
|
|
|
|
** first character in 'form' must be '%' and last character must |
|
|
|
|
|
** be a valid conversion specifier. 'flags' are the accepted flags; |
|
|
|
|
|
** 'precision' signals whether to accept a precision. |
|
|
|
|
|
*/ |
|
|
|
|
|
static void checkformat (lua_State *L, const char *form, const char *flags, |
|
|
|
|
|
int precision) { |
|
|
|
|
|
const char *spec = form + 1; /* skip '%' */ |
|
|
|
|
|
spec += strspn(spec, flags); /* skip flags */ |
|
|
|
|
|
if (*spec != '0') { /* a width cannot start with '0' */ |
|
|
|
|
|
spec = get2digits(spec); /* skip width */ |
|
|
|
|
|
if (*spec == '.' && precision) { |
|
|
|
|
|
spec++; |
|
|
|
|
|
spec = get2digits(spec); /* skip precision */ |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
if (isdigit(uchar(*p))) |
|
|
if (!isalpha(uchar(*spec))) /* did not go to the end? */ |
|
|
luaL_error(L, "invalid format (width or precision too long)"); |
|
|
luaL_error(L, "invalid conversion specification: '%s'", form); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
** Get a conversion specification and copy it to 'form'. |
|
|
|
|
|
** Return the address of its last character. |
|
|
|
|
|
*/ |
|
|
|
|
|
static const char *getformat (lua_State *L, const char *strfrmt, |
|
|
|
|
|
char *form) { |
|
|
|
|
|
/* spans flags, width, and precision ('0' is included as a flag) */ |
|
|
|
|
|
size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); |
|
|
|
|
|
len++; /* adds following character (should be the specifier) */ |
|
|
|
|
|
/* still needs space for '%', '\0', plus a length modifier */ |
|
|
|
|
|
if (len >= MAX_FORMAT - 10) |
|
|
|
|
|
luaL_error(L, "invalid format (too long)"); |
|
|
*(form++) = '%'; |
|
|
*(form++) = '%'; |
|
|
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); |
|
|
memcpy(form, strfrmt, len * sizeof(char)); |
|
|
form += (p - strfrmt) + 1; |
|
|
*(form + len) = '\0'; |
|
|
*form = '\0'; |
|
|
return strfrmt + len - 1; |
|
|
return p; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1230,6 +1276,7 @@ static int str_format (lua_State *L) { |
|
|
size_t sfl; |
|
|
size_t sfl; |
|
|
const char *strfrmt = luaL_checklstring(L, arg, &sfl); |
|
|
const char *strfrmt = luaL_checklstring(L, arg, &sfl); |
|
|
const char *strfrmt_end = strfrmt+sfl; |
|
|
const char *strfrmt_end = strfrmt+sfl; |
|
|
|
|
|
const char *flags; |
|
|
luaL_Buffer b; |
|
|
luaL_Buffer b; |
|
|
luaL_buffinit(L, &b); |
|
|
luaL_buffinit(L, &b); |
|
|
while (strfrmt < strfrmt_end) { |
|
|
while (strfrmt < strfrmt_end) { |
|
@ -1239,25 +1286,35 @@ static int str_format (lua_State *L) { |
|
|
luaL_addchar(&b, *strfrmt++); /* %% */ |
|
|
luaL_addchar(&b, *strfrmt++); /* %% */ |
|
|
else { /* format item */ |
|
|
else { /* format item */ |
|
|
char form[MAX_FORMAT]; /* to store the format ('%...') */ |
|
|
char form[MAX_FORMAT]; /* to store the format ('%...') */ |
|
|
int maxitem = MAX_ITEM; |
|
|
int maxitem = MAX_ITEM; /* maximum length for the result */ |
|
|
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ |
|
|
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ |
|
|
int nb = 0; /* number of bytes in added item */ |
|
|
int nb = 0; /* number of bytes in result */ |
|
|
if (++arg > top) |
|
|
if (++arg > top) |
|
|
return luaL_argerror(L, arg, "no value"); |
|
|
return luaL_argerror(L, arg, "no value"); |
|
|
strfrmt = scanformat(L, strfrmt, form); |
|
|
strfrmt = getformat(L, strfrmt, form); |
|
|
switch (*strfrmt++) { |
|
|
switch (*strfrmt++) { |
|
|
case 'c': { |
|
|
case 'c': { |
|
|
|
|
|
checkformat(L, form, L_FMTFLAGSC, 0); |
|
|
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); |
|
|
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case 'd': case 'i': |
|
|
case 'd': case 'i': |
|
|
case 'o': case 'u': case 'x': case 'X': { |
|
|
flags = L_FMTFLAGSI; |
|
|
|
|
|
goto intcase; |
|
|
|
|
|
case 'u': |
|
|
|
|
|
flags = L_FMTFLAGSU; |
|
|
|
|
|
goto intcase; |
|
|
|
|
|
case 'o': case 'x': case 'X': |
|
|
|
|
|
flags = L_FMTFLAGSX; |
|
|
|
|
|
intcase: { |
|
|
lua_Integer n = luaL_checkinteger(L, arg); |
|
|
lua_Integer n = luaL_checkinteger(L, arg); |
|
|
|
|
|
checkformat(L, form, flags, 1); |
|
|
addlenmod(form, LUA_INTEGER_FRMLEN); |
|
|
addlenmod(form, LUA_INTEGER_FRMLEN); |
|
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); |
|
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case 'a': case 'A': |
|
|
case 'a': case 'A': |
|
|
|
|
|
checkformat(L, form, L_FMTFLAGSF, 1); |
|
|
addlenmod(form, LUA_NUMBER_FRMLEN); |
|
|
addlenmod(form, LUA_NUMBER_FRMLEN); |
|
|
nb = lua_number2strx(L, buff, maxitem, form, |
|
|
nb = lua_number2strx(L, buff, maxitem, form, |
|
|
luaL_checknumber(L, arg)); |
|
|
luaL_checknumber(L, arg)); |
|
@ -1268,12 +1325,14 @@ static int str_format (lua_State *L) { |
|
|
/* FALLTHROUGH */ |
|
|
/* FALLTHROUGH */ |
|
|
case 'e': case 'E': case 'g': case 'G': { |
|
|
case 'e': case 'E': case 'g': case 'G': { |
|
|
lua_Number n = luaL_checknumber(L, arg); |
|
|
lua_Number n = luaL_checknumber(L, arg); |
|
|
|
|
|
checkformat(L, form, L_FMTFLAGSF, 1); |
|
|
addlenmod(form, LUA_NUMBER_FRMLEN); |
|
|
addlenmod(form, LUA_NUMBER_FRMLEN); |
|
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); |
|
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
case 'p': { |
|
|
case 'p': { |
|
|
const void *p = lua_topointer(L, arg); |
|
|
const void *p = lua_topointer(L, arg); |
|
|
|
|
|
checkformat(L, form, L_FMTFLAGSC, 0); |
|
|
if (p == NULL) { /* avoid calling 'printf' with argument NULL */ |
|
|
if (p == NULL) { /* avoid calling 'printf' with argument NULL */ |
|
|
p = "(null)"; /* result */ |
|
|
p = "(null)"; /* result */ |
|
|
form[strlen(form) - 1] = 's'; /* format it as a string */ |
|
|
form[strlen(form) - 1] = 's'; /* format it as a string */ |
|
@ -1294,7 +1353,8 @@ static int str_format (lua_State *L) { |
|
|
luaL_addvalue(&b); /* keep entire string */ |
|
|
luaL_addvalue(&b); /* keep entire string */ |
|
|
else { |
|
|
else { |
|
|
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); |
|
|
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); |
|
|
if (!strchr(form, '.') && l >= 100) { |
|
|
checkformat(L, form, L_FMTFLAGSC, 1); |
|
|
|
|
|
if (strchr(form, '.') == NULL && l >= 100) { |
|
|
/* no precision and string is too long to be formatted */ |
|
|
/* no precision and string is too long to be formatted */ |
|
|
luaL_addvalue(&b); /* keep entire string */ |
|
|
luaL_addvalue(&b); /* keep entire string */ |
|
|
} |
|
|
} |
|
|