[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: parse hex numerals [PATCH]
- From: Mike Pall <mikelu-0602@...>
- Date: Thu, 9 Feb 2006 15:01:03 +0100
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