From e966e5379195a3414c0e8f6be6e25052702305ff Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 21 May 2014 12:24:21 -0300 Subject: no more use of 'scanf' for reading numbers --- liolib.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- luaconf.h | 11 +------ 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/liolib.c b/liolib.c index 5b50bbf1..82fd49f3 100644 --- a/liolib.c +++ b/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.123 2014/05/13 19:40:28 roberto Exp roberto $ +** $Id: liolib.c,v 2.124 2014/05/15 15:21:06 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -15,7 +15,9 @@ #endif +#include #include +#include #include #include #include @@ -361,26 +363,91 @@ static int io_lines (lua_State *L) { */ -static int read_integer (lua_State *L, FILE *f) { - lua_Integer d; - if (fscanf(f, LUA_INTEGER_SCAN, &d) == 1) { - lua_pushinteger(L, d); - return 1; - } +/* maximum length of a numeral */ +#define MAXRN 200 + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[MAXRN]; +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= MAXRN) /* buffer overflow? */ + return 0; /* fail */ else { - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; } } +/* +** Accept current char if it is in 'set' (of size 1 or 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hexa)digits +*/ +static int readdigits (RN *rn, int hexa) { + int count = 0; + while ((hexa ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* access to locale "radix character" (decimal point) */ +#if !defined(getlocaledecpoint) +#define getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_strtonum' to check whether the format is correct +** and to convert it to a Lua number +*/ static int read_number (lua_State *L, FILE *f) { - lua_Number d; - if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { - lua_pushnumber(L, d); - return 1; + RN rn; + int count = 0; + int hexa = 0; + char decp[2] = "."; + rn.f = f; rn.n = 0; + decp[0] = getlocaledecpoint(); /* get decimal point from locale */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "0")) { + if (test2(&rn, "xX")) hexa = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ } - else { + count += readdigits(&rn, hexa); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hexa); /* fractionary part */ + if (count > 0 && test2(&rn, (hexa ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_strtonum(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ } @@ -456,9 +523,6 @@ static int g_read (lua_State *L, FILE *f, int first) { const char *p = luaL_checkstring(L, n); if (*p == '*') p++; /* skip optional '*' (for compatibility) */ switch (*p) { - case 'i': /* integer */ - success = read_integer(L, f); - break; case 'n': /* number */ success = read_number(L, f); break; diff --git a/luaconf.h b/luaconf.h index dd5e7280..40bb5ef5 100644 --- a/luaconf.h +++ b/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.201 2014/05/11 13:03:48 roberto Exp roberto $ +** $Id: luaconf.h,v 1.202 2014/05/15 15:24:32 roberto Exp roberto $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -431,7 +431,6 @@ @@ over a floating number. ** @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. -@@ LUA_NUMBER_SCAN is the format for reading floats. @@ LUA_NUMBER_FMT is the format for writing floats. @@ lua_number2str converts a float to a string. ** @@ -447,7 +446,6 @@ #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_SCAN "%f" #define LUA_NUMBER_FMT "%.7g" #define l_mathop(op) op##f @@ -462,7 +460,6 @@ #define LUAI_UACNUMBER long double #define LUA_NUMBER_FRMLEN "L" -#define LUA_NUMBER_SCAN "%Lf" #define LUA_NUMBER_FMT "%.19Lg" #define l_mathop(op) op##l @@ -476,7 +473,6 @@ #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_FMT "%.14g" #define l_mathop(op) op @@ -552,7 +548,6 @@ @@ LUAI_UACINT is the result of an 'usual argument conversion' @@ over a lUA_INTEGER. @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. -@@ LUA_INTEGER_SCAN is the format for reading integers. @@ LUA_INTEGER_FMT is the format for writing integers. @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. @@ -563,7 +558,6 @@ /* The following definitions are good for most cases here */ -#define LUA_INTEGER_SCAN "%" LUA_INTEGER_FRMLEN "d" #define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" #define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n)) @@ -634,9 +628,6 @@ #undef LUAI_UACINT #define LUAI_UACINT int -#undef LUA_INTEGER_SCAN -#define LUA_INTEGER_SCAN "%hd" - #undef LUAI_MAXSTACK #define LUAI_MAXSTACK 15000 -- cgit v1.2.3-55-g6feb