From 01c96ad12e1e45d6a36a07ae8ec97c09fd0ff913 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 19 May 2017 13:29:40 -0300 Subject: handling of inf, -inf, and NaN by string.format'%q' --- lstrlib.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'lstrlib.c') diff --git a/lstrlib.c b/lstrlib.c index 6ed2bdb8..89896fa6 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.255 2017/03/14 12:40:44 roberto Exp roberto $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -813,8 +814,6 @@ static int str_gsub (lua_State *L) { ** Hexadecimal floating-point formatter */ -#include - #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) @@ -929,14 +928,32 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) { /* -** Ensures the 'buff' string uses a dot as the radix character. +** Serialize a floating-point number in such a way that it can be +** scanned back by Lua. Use hexadecimal format for "common" numbers +** (to preserve precision); inf, -inf, and NaN are handled separately. +** (NaN cannot be expressed as a numeral, so we write '(0/0)' for it.) */ -static void checkdp (char *buff, int nb) { - if (memchr(buff, '.', nb) == NULL) { /* no dot? */ - char point = lua_getlocaledecpoint(); /* try locale point */ - char *ppoint = (char *)memchr(buff, point, nb); - if (ppoint) *ppoint = '.'; /* change it to a dot */ +static int quotefloat (lua_State *L, char *buff, lua_Number n) { + const char *s; /* for the fixed representations */ + if (n == (lua_Number)HUGE_VAL) /* inf? */ + s = "1e9999"; + else if (n == -(lua_Number)HUGE_VAL) /* -inf? */ + s = "-1e9999"; + else if (n != n) /* NaN? */ + s = "(0/0)"; + else { /* format number as hexadecimal */ + int nb = lua_number2strx(L, buff, MAX_ITEM, + "%" LUA_NUMBER_FRMLEN "a", n); + /* ensures that 'buff' string uses a dot as the radix character */ + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } + return nb; } + /* for the fixed representations */ + return l_sprintf(buff, MAX_ITEM, "%s", s); } @@ -951,11 +968,8 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { case LUA_TNUMBER: { char *buff = luaL_prepbuffsize(b, MAX_ITEM); int nb; - if (!lua_isinteger(L, arg)) { /* float? */ - lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ - nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); - checkdp(buff, nb); /* ensure it uses a dot */ - } + if (!lua_isinteger(L, arg)) /* float? */ + nb = quotefloat(L, buff, lua_tonumber(L, arg)); else { /* integers */ lua_Integer n = lua_tointeger(L, arg); const char *format = (n == LUA_MININTEGER) /* corner case? */ -- cgit v1.2.3-55-g6feb