lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

Roberto Ierusalimschy wrote:
> > for an explanation and a (IMHO) better/simpler patch which makes
> > hex numbers work with non-C99 libraries, too (MSVC for Windows).
> 
> Do we really need a patch? Can't we just use configuration? Something
> like this (untested...):
> 
>   #define lua_str2number(s,p)  \
>      (s[0]=='0' && s[1] == 'x') ? strtoul(s[2], p, 16) : strtod((s), (p))

This doesn't work with leading whitespace or signs. This isn't a
problem for the parser, but consistency with tonumber() is very
desirable.

And ?: with different result types is a problem, too. AFAIK
strtoul() already takes care of the 0x in base 16. Also, strtod()
does a better job with hex numbers on C99 systems, so you want to
try this first.

Ok, I've got another idea (tested):

---- luaconf.h ----
...
@@ lua_xstr2number converts a hex string to a number.
...
#define lua_xstr2number(s,p)    strtoul((s), (p), 16) 
...

---- lobject.c ----

int luaO_str2d (const char *s, lua_Number *result) {
  char *endptr;
  *result = lua_str2number(s, &endptr);
  for (;;) {
    if (endptr != s) {  /* at least one char was accepted */
      if (*endptr == '\0') return 1;  /* most common case */
      while (isspace(cast(unsigned char, *endptr))) endptr++;
      if (*endptr == '\0') return 1;  /* ok, only trailing spaces */
    }
    if (s == NULL) break;
    *result = cast_num(lua_xstr2number(s, &endptr));
    s = NULL;
  }
  return 0;  /* conversion failed. */
}

This is really only a five line change, except the logic had to
be reordered. It's a bit ugly but avoids coding the trailer check
twice. Non-C99 compliant systems will parse " +0xff" up to " +0",
so just checking for endptr != s doesn't work.

Another nice thing about it: for integer lua_Number one can use:
  #define lua_str2number(s,p)   strtoul((s), (p), 10)
Avoids the octal number pitfall and hex numbers still work
because of the fallback.

Testcases:

assert(0x10 == 16)
assert(-0x10 == -16)
assert(0xef == 239)
assert(-0xef == -239)

assert(tonumber("0xef") == 239)
assert(tonumber("+0xef") == 239)
assert(tonumber("-0xef") == -239)
assert(tonumber("\t 0xef") == 239)
assert(tonumber("0xef\t ") == 239)
assert(tonumber("\t +0xef\t ") == 239)
assert(tonumber("\t -0xef\t ") == -239)

assert(0x7fffffff == 2147483647)
assert(0xffffffff == 4294967295)               -- Really -1 with int32.
assert(tonumber("-0x7fffffff") == -2147483647)
assert(tonumber("-0xffffffff") == -4294967295) -- Really +1 with int32.

Bye,
     Mike