From af119c8b55f15910df17e02633d8a5ca656b209a Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Fri, 10 Dec 2010 17:03:46 -0200
Subject: official support for floating hexa numerals

---
 lobject.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 77 insertions(+), 10 deletions(-)

(limited to 'lobject.c')

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 <math.h>
+
+
+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 */
 }
 
 
-- 
cgit v1.2.3-55-g6feb