diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-19 13:29:40 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-19 13:29:40 -0300 |
| commit | 01c96ad12e1e45d6a36a07ae8ec97c09fd0ff913 (patch) | |
| tree | 9517d358c0df8f97a0f336b4dcdfdeb84ef52faa | |
| parent | 1bdc328c7542fac5101684a4ac31a25be3dff112 (diff) | |
| download | lua-01c96ad12e1e45d6a36a07ae8ec97c09fd0ff913.tar.gz lua-01c96ad12e1e45d6a36a07ae8ec97c09fd0ff913.tar.bz2 lua-01c96ad12e1e45d6a36a07ae8ec97c09fd0ff913.zip | |
handling of inf, -inf, and NaN by string.format'%q'
| -rw-r--r-- | lstrlib.c | 42 |
1 files changed, 28 insertions, 14 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.255 2017/03/14 12:40:44 roberto Exp roberto $ |
| 3 | ** Standard library for string operations and pattern-matching | 3 | ** Standard library for string operations and pattern-matching |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <float.h> | 14 | #include <float.h> |
| 15 | #include <limits.h> | 15 | #include <limits.h> |
| 16 | #include <locale.h> | 16 | #include <locale.h> |
| 17 | #include <math.h> | ||
| 17 | #include <stddef.h> | 18 | #include <stddef.h> |
| 18 | #include <stdio.h> | 19 | #include <stdio.h> |
| 19 | #include <stdlib.h> | 20 | #include <stdlib.h> |
| @@ -813,8 +814,6 @@ static int str_gsub (lua_State *L) { | |||
| 813 | ** Hexadecimal floating-point formatter | 814 | ** Hexadecimal floating-point formatter |
| 814 | */ | 815 | */ |
| 815 | 816 | ||
| 816 | #include <math.h> | ||
| 817 | |||
| 818 | #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) | 817 | #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) |
| 819 | 818 | ||
| 820 | 819 | ||
| @@ -929,14 +928,32 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) { | |||
| 929 | 928 | ||
| 930 | 929 | ||
| 931 | /* | 930 | /* |
| 932 | ** Ensures the 'buff' string uses a dot as the radix character. | 931 | ** Serialize a floating-point number in such a way that it can be |
| 932 | ** scanned back by Lua. Use hexadecimal format for "common" numbers | ||
| 933 | ** (to preserve precision); inf, -inf, and NaN are handled separately. | ||
| 934 | ** (NaN cannot be expressed as a numeral, so we write '(0/0)' for it.) | ||
| 933 | */ | 935 | */ |
| 934 | static void checkdp (char *buff, int nb) { | 936 | static int quotefloat (lua_State *L, char *buff, lua_Number n) { |
| 935 | if (memchr(buff, '.', nb) == NULL) { /* no dot? */ | 937 | const char *s; /* for the fixed representations */ |
| 936 | char point = lua_getlocaledecpoint(); /* try locale point */ | 938 | if (n == (lua_Number)HUGE_VAL) /* inf? */ |
| 937 | char *ppoint = (char *)memchr(buff, point, nb); | 939 | s = "1e9999"; |
| 938 | if (ppoint) *ppoint = '.'; /* change it to a dot */ | 940 | else if (n == -(lua_Number)HUGE_VAL) /* -inf? */ |
| 941 | s = "-1e9999"; | ||
| 942 | else if (n != n) /* NaN? */ | ||
| 943 | s = "(0/0)"; | ||
| 944 | else { /* format number as hexadecimal */ | ||
| 945 | int nb = lua_number2strx(L, buff, MAX_ITEM, | ||
| 946 | "%" LUA_NUMBER_FRMLEN "a", n); | ||
| 947 | /* ensures that 'buff' string uses a dot as the radix character */ | ||
| 948 | if (memchr(buff, '.', nb) == NULL) { /* no dot? */ | ||
| 949 | char point = lua_getlocaledecpoint(); /* try locale point */ | ||
| 950 | char *ppoint = (char *)memchr(buff, point, nb); | ||
| 951 | if (ppoint) *ppoint = '.'; /* change it to a dot */ | ||
| 952 | } | ||
| 953 | return nb; | ||
| 939 | } | 954 | } |
| 955 | /* for the fixed representations */ | ||
| 956 | return l_sprintf(buff, MAX_ITEM, "%s", s); | ||
| 940 | } | 957 | } |
| 941 | 958 | ||
| 942 | 959 | ||
| @@ -951,11 +968,8 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { | |||
| 951 | case LUA_TNUMBER: { | 968 | case LUA_TNUMBER: { |
| 952 | char *buff = luaL_prepbuffsize(b, MAX_ITEM); | 969 | char *buff = luaL_prepbuffsize(b, MAX_ITEM); |
| 953 | int nb; | 970 | int nb; |
| 954 | if (!lua_isinteger(L, arg)) { /* float? */ | 971 | if (!lua_isinteger(L, arg)) /* float? */ |
| 955 | lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ | 972 | nb = quotefloat(L, buff, lua_tonumber(L, arg)); |
| 956 | nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); | ||
| 957 | checkdp(buff, nb); /* ensure it uses a dot */ | ||
| 958 | } | ||
| 959 | else { /* integers */ | 973 | else { /* integers */ |
| 960 | lua_Integer n = lua_tointeger(L, arg); | 974 | lua_Integer n = lua_tointeger(L, arg); |
| 961 | const char *format = (n == LUA_MININTEGER) /* corner case? */ | 975 | const char *format = (n == LUA_MININTEGER) /* corner case? */ |
