summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Urlichs <smurf@noris.net>2000-03-04 13:48:42 +0100
committerJarkko Hietaniemi <jhi@iki.fi>2000-03-04 16:35:48 +0000
commit0b7fceb9e0ed2836bae4cb25eb0618064f63af24 (patch)
tree76f3221081a17259786460fb6134baf4bc854d14
parent90ea4f4d7613f41c4c0e536a45aa1927a77c23d5 (diff)
downloadperl-0b7fceb9e0ed2836bae4cb25eb0618064f63af24.tar.gz
BUG: Integer floatifies? +PATCH: reading BIG integers with SMALL floats
To: perl5-porters@perl.org Message-ID: <20000304124841.A8090@noris.de> p4raw-id: //depot/cfgperl@5521
-rw-r--r--toke.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/toke.c b/toke.c
index 79ee972e02..16e3788b8b 100644
--- a/toke.c
+++ b/toke.c
@@ -6684,7 +6684,10 @@ 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 */
+#if (defined(USE_64_BIT_INT) && (!defined(HAS_STRTOLL)|| !defined(HAS_STRTOULL))) || \
+ (!defined(USE_64_BIT_INT) && (!defined(HAS_STRTOL) || !defined(HAS_STRTOUL)))
IV tryiv; /* used to see if it can be an IV */
+#endif
NV value; /* number read, as a double */
SV *sv = Nullsv; /* place to put the converted number */
bool floatit; /* boolean: int or float? */
@@ -6942,6 +6945,14 @@ Perl_scan_num(pTHX_ char *start)
/* make an sv from the string */
sv = NEWSV(92,0);
+#if (defined(USE_64_BIT_INT) && (!defined(HAS_STRTOLL)|| !defined(HAS_STRTOULL))) || \
+ (!defined(USE_64_BIT_INT) && (!defined(HAS_STRTOL) || !defined(HAS_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);
/*
@@ -6959,12 +6970,55 @@ Perl_scan_num(pTHX_ char *start)
sv_setiv(sv, tryiv);
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.
+ */
+
+ if (!floatit) {
+ char *tp;
+ IV iv;
+ UV uv;
+ errno = 0;
+#ifdef USE_64_BIT_INT
+ iv = (*PL_tokenbuf == '-') ?
+ strtoll(PL_tokenbuf,&tp,10) :
+ (IV)strtoull(PL_tokenbuf,&tp,10);
+#else
+ iv = (*PL_tokenbuf == '-') ?
+ strtol(PL_tokenbuf,&tp,10) :
+ (IV)strtoul(PL_tokenbuf,&tp,10);
+#endif
+ if (*tp || errno)
+ floatit = TRUE; /* probably just too large */
+ else if (*PL_tokenbuf == '-')
+ sv_setiv(sv, iv);
+ else
+ sv_setuv(sv, (UV)iv);
+ }
+ if (floatit) {
+ char *tp;
+ errno = 0;
+#ifdef USE_LONG_DOUBLE
+ value = strtold(PL_tokenbuf,&tp);
+#else
+ value = strtod(PL_tokenbuf,&tp);
+#endif
+ if (*tp || errno)
+ Perl_die(aTHX_ "unparseable float");
+ else
+ sv_setnv(sv, value);
+ }
+#endif
if ( floatit ? (PL_hints & HINT_NEW_FLOAT) :
(PL_hints & HINT_NEW_INTEGER) )
sv = new_constant(PL_tokenbuf, d - PL_tokenbuf,
(floatit ? "float" : "integer"),
sv, Nullsv, NULL);
break;
+
/* if it starts with a v, it could be a version number */
case 'v':
vstring: