BUG: Integer floatifies? +PATCH: reading BIG integers with SMALL floats
Matthias Urlichs [Sat, 4 Mar 2000 12:48:42 +0000 (13:48 +0100)]
To: perl5-porters@perl.org
Message-ID: <20000304124841.A8090@noris.de>

p4raw-id: //depot/cfgperl@5521

toke.c

diff --git a/toke.c b/toke.c
index 79ee972..16e3788 100644 (file)
--- 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: