From af119c8b55f15910df17e02633d8a5ca656b209a Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 10 Dec 2010 17:03:46 -0200 Subject: official support for floating hexa numerals --- lobject.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- lstrlib.c | 5 +++- luaconf.h | 20 +++++++++++++-- 3 files changed, 99 insertions(+), 13 deletions(-) diff --git a/lobject.c b/lobject.c index 598520ac..cb8ead92 100644 --- a/lobject.c +++ b/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.43 2010/10/29 15:54:55 roberto Exp roberto $ +** $Id: lobject.c,v 2.44 2010/12/06 21:08:36 roberto Exp roberto $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -106,20 +106,87 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { } -static int checkend (const char *s, const char *e, const char *endptr) { - if (endptr == s) return 0; /* no characters converted */ - while (lisspace(cast(unsigned char, *endptr))) endptr++; - return (endptr == e); /* OK if no trailing characters */ +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else if (lisupper(c)) return c - 'A' + 10; + else return c - 'a' + 10; } +#if !defined(lua_strx2number) + +#include + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; +} + + +static lua_Number readhexa (const char **s, lua_Number r, int *count) { + while (lisxdigit(cast_uchar(**s))) { /* read integer part */ + r = (r * 16.0) + (double)luaO_hexavalue(*(*s)++); + (*count)++; + } + return r; +} + + +/* +** convert an hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + lua_Number r = 0.0; + int e = 0, i = 0; + int neg = 0; /* 1 if number is negative */ + *endptr = cast(char *, s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + s += 2; /* skip '0x' */ + r = readhexa(&s, r, &i); /* read integer part */ + if (*s == '.') { + s++; /* skip dot */ + r = readhexa(&s, r, &e); /* read fractional part */ + } + if (i == 0 && e == 0) + return 0.0; /* invalid format (no digit) */ + e *= -4; /* each fractional digit divides value by 2^-4 */ + *endptr = cast(char *, s); /* valid up to here */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; + int neg1; + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!lisdigit(cast_uchar(*s))) + goto ret; /* must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + } + *endptr = cast(char *, s); /* valid up to here */ + ret: + if (neg) r = -r; + return ldexp(r, e); +} + +#endif + + int luaO_str2d (const char *s, size_t len, lua_Number *result) { char *endptr; - const char *e = s + len; /* string 's' ends here */ - *result = lua_str2number(s, &endptr); - if (checkend(s, e, endptr)) return 1; /* conversion OK? */ - *result = cast_num(strtoul(s, &endptr, 0)); /* try hexadecimal */ - return checkend(s, e, endptr); + if (strpbrk(s, "xX")) /* hexa? */ + *result = lua_strx2number(s, &endptr); + else + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* nothing recognized */ + while (lisspace(cast_uchar(*endptr))) endptr++; + return (endptr == s + len); /* OK if no trailing characters */ } diff --git a/lstrlib.c b/lstrlib.c index 7ca7ea39..3acaf875 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.158 2010/11/16 20:39:41 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.159 2010/11/19 16:25:51 roberto Exp roberto $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -861,6 +861,9 @@ static int str_format (lua_State *L) { break; } case 'e': case 'E': case 'f': +#if defined(LUA_USE_AFORMAT) + case 'a': case 'A': +#endif case 'g': case 'G': { addlenmod(form, LUA_FLTFRMLEN); nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); diff --git a/luaconf.h b/luaconf.h index e79421b6..f7b242f9 100644 --- a/luaconf.h +++ b/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.151 2010/11/12 15:48:30 roberto Exp roberto $ +** $Id: luaconf.h,v 1.152 2010/12/08 12:58:04 roberto Exp roberto $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -35,6 +35,7 @@ #if defined(LUA_WIN) #define LUA_DL_DLL +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #endif @@ -43,6 +44,8 @@ #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ +#define LUA_USE_HEXAFLOAT /* assume 'strtod' handles hexa formats */ +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #endif #if defined(LUA_USE_MACOSX) @@ -377,14 +380,27 @@ @@ LUA_NUMBER_FMT is the format for writing numbers. @@ lua_number2str converts a number to a string. @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. -@@ lua_str2number converts a string to a number. */ #define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_FMT "%.14g" #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ + + +/* +@@ lua_str2number converts a decimal numeric string to a number. +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' do both conversions. C89, however, has no function +** to convert floating hexadecimal strings to numbers. For these +** systems, you can leave 'lua_strx2number' undefined and Lua will +** provide its own implementation. +*/ #define lua_str2number(s,p) strtod((s), (p)) +#if defined(LUA_USE_HEXAFLOAT) +#define lua_strx2number(s,p) strtod((s), (p)) +#endif + /* @@ The luai_num* macros define the primitive operations over numbers. -- cgit v1.2.3-55-g6feb