diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2000-05-04 15:26:37 +0000 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2000-05-04 15:26:37 +0000 |
commit | 86554af2a462f0b5e670752c0fb90061fa1f6e20 (patch) | |
tree | 6281cbed616128c3fcc7dbb8893ed96253d69471 /toke.c | |
parent | 806e78a957fcce8bc56cb2c211ffcbba23772d4c (diff) | |
download | perl-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.c | 88 |
1 files changed, 52 insertions, 36 deletions
@@ -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) : |