summaryrefslogtreecommitdiff
path: root/toke.c
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2000-05-04 15:26:37 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2000-05-04 15:26:37 +0000
commit86554af2a462f0b5e670752c0fb90061fa1f6e20 (patch)
tree6281cbed616128c3fcc7dbb8893ed96253d69471 /toke.c
parent806e78a957fcce8bc56cb2c211ffcbba23772d4c (diff)
downloadperl-86554af2a462f0b5e670752c0fb90061fa1f6e20.tar.gz
The logic of choosing strtol/strtoul/strtoll/strtoull was wrong
in natively 64-bit platforms where a long is a quad (no need for long longs). Also added bias for IVs. p4raw-id: //depot/cfgperl@6059
Diffstat (limited to 'toke.c')
-rw-r--r--toke.c88
1 files changed, 52 insertions, 36 deletions
diff --git a/toke.c b/toke.c
index 10273a0111..49a1193aae 100644
--- a/toke.c
+++ b/toke.c
@@ -6705,7 +6705,7 @@ Perl_scan_num(pTHX_ char *start)
register char *s = start; /* current position in buffer */
register char *d; /* destination in temp buffer */
register char *e; /* end of temp buffer */
- NV value; /* number read, as a double */
+ NV nv; /* number read, as a double */
SV *sv = Nullsv; /* place to put the converted number */
bool floatit; /* boolean: int or float? */
char *lastub = 0; /* position of last underbar */
@@ -6962,40 +6962,9 @@ Perl_scan_num(pTHX_ char *start)
/* make an sv from the string */
sv = NEWSV(92,0);
- /* unfortunately this monster needs to be on one line or
- makedepend will be confused. */
-#if (defined(USE_64_BIT_INT) && (!defined(HAS_STRTOLL)|| !defined(HAS_STRTOULL))) || (!defined(USE_64_BIT_INT) && (!defined(HAS_STRTOL) || !defined(HAS_STRTOUL)))
+#if defined(Strtol) && defined(Strtoul)
/*
- No working strto[u]l[l]. Since atoi() doesn't do range checks,
- we need to do this the hard way.
- */
-
- value = Atof(PL_tokenbuf);
-
- /*
- See if we can make do with an integer value without loss of
- precision. We use I_V to cast to an int, because some
- compilers have issues. Then we try casting it back and see
- if it was the same. We only do this if we know we
- specifically read an integer.
-
- Note: if floatit is true, then we don't need to do the
- conversion at all.
- */
- {
- UV tryuv = U_V(value);
- if (!floatit && (NV)tryuv == value) {
- if (tryuv <= IV_MAX)
- sv_setiv(sv, (IV)tryuv);
- else
- sv_setuv(sv, tryuv);
- }
- else
- sv_setnv(sv, value);
- }
-#else
- /*
strtol/strtoll sets errno to ERANGE if the number is too big
for an integer. We try to do an integer conversion first
if no characters indicating "float" have been found.
@@ -7010,15 +6979,62 @@ Perl_scan_num(pTHX_ char *start)
else
uv = Strtoul(PL_tokenbuf, (char**)NULL, 10);
if (errno)
- floatit = TRUE; /* probably just too large */
+ floatit = TRUE; /* Probably just too large. */
else if (*PL_tokenbuf == '-')
sv_setiv(sv, iv);
+ else if (uv <= IV_MAX)
+ sv_setiv(sv, uv); /* Prefer IVs over UVs. */
else
sv_setuv(sv, uv);
}
if (floatit) {
- value = Atof(PL_tokenbuf);
- sv_setnv(sv, value);
+ nv = Atof(PL_tokenbuf);
+ sv_setnv(sv, nv);
+ }
+#else
+ /*
+ No working strtou?ll?.
+
+ Unfortunately atol() doesn't do range checks (returning
+ LONG_MIN/LONG_MAX, and setting errno to ERANGE on overflows)
+ everywhere [1], so we cannot use use atol() (or atoll()).
+ If we could, they would be used, as Atol(), very much like
+ Strtol() and Strtoul() are used above.
+
+ [1] XXX Configure test needed to check for atol()
+ (and atoll() overflow behaviour) XXX --jhi
+
+ We need to do this the hard way. */
+
+ nv = Atof(PL_tokenbuf);
+
+ /* See if we can make do with an integer value without loss of
+ precision. We use U_V to cast to a UV, because some
+ compilers have issues. Then we try casting it back and see
+ if it was the same [1]. We only do this if we know we
+ specifically read an integer. If floatit is true, then we
+ don't need to do the conversion at all.
+
+ [1] Note that this is lossy if our NVs cannot preserve our
+ UVs. There is a metaconfig define, NV_PRESERVES_UV, but we
+ really do hope all such platforms have strtou?ll? to do a
+ lossless IV/UV conversion.
+ XXX Configure test needed to check how many UV bits
+ do our NVs preserve, really (the current test checks
+ for the roundtrip of ~0) XXX --jhi
+ Maybe do some tricks with DBL_MANT_DIG and LDBL_MANT_DIG,
+ and DBL_DIG, LDBL_DIG (this is already available as NV_DIG)?
+ */
+ {
+ UV uv = U_V(nv);
+ if (!floatit && (NV)uv == nv) {
+ if (uv <= IV_MAX)
+ sv_setiv(sv, uv); /* Prefer IVs over UVs. */
+ else
+ sv_setuv(sv, uv);
+ }
+ else
+ sv_setnv(sv, nv);
}
#endif
if ( floatit ? (PL_hints & HINT_NEW_FLOAT) :