Handle numbers like 1e1, nan, -infinity. Also try harder to preserve
authorMatthias Clasen <mclasen@redhat.com>
Fri, 5 Nov 2004 03:21:24 +0000 (03:21 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Fri, 5 Nov 2004 03:21:24 +0000 (03:21 +0000)
2004-11-04  Matthias Clasen  <mclasen@redhat.com>

* glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
1e1, nan, -infinity. Also try harder to preserve errno.
(#156421, Morten Welinder)

* tests/strtod-test.c: Add testcases.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/gstrfuncs.c
tests/strtod-test.c

index e000728..690d6ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2004-11-04  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
+       1e1, nan, -infinity. Also try harder to preserve errno.  
+       (#156421, Morten Welinder)
+
+       * tests/strtod-test.c: Add testcases.
+
 2004-11-04  Tor Lillqvist  <tml@iki.fi>
 
        * glib/goption.h (enum GOptionFlags): Add G_OPTION_FLAG_REVERSE,
index e000728..690d6ae 100644 (file)
@@ -1,3 +1,11 @@
+2004-11-04  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
+       1e1, nan, -infinity. Also try harder to preserve errno.  
+       (#156421, Morten Welinder)
+
+       * tests/strtod-test.c: Add testcases.
+
 2004-11-04  Tor Lillqvist  <tml@iki.fi>
 
        * glib/goption.h (enum GOptionFlags): Add G_OPTION_FLAG_REVERSE,
index e000728..690d6ae 100644 (file)
@@ -1,3 +1,11 @@
+2004-11-04  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
+       1e1, nan, -infinity. Also try harder to preserve errno.  
+       (#156421, Morten Welinder)
+
+       * tests/strtod-test.c: Add testcases.
+
 2004-11-04  Tor Lillqvist  <tml@iki.fi>
 
        * glib/goption.h (enum GOptionFlags): Add G_OPTION_FLAG_REVERSE,
index e000728..690d6ae 100644 (file)
@@ -1,3 +1,11 @@
+2004-11-04  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
+       1e1, nan, -infinity. Also try harder to preserve errno.  
+       (#156421, Morten Welinder)
+
+       * tests/strtod-test.c: Add testcases.
+
 2004-11-04  Tor Lillqvist  <tml@iki.fi>
 
        * glib/goption.h (enum GOptionFlags): Add G_OPTION_FLAG_REVERSE,
index e000728..690d6ae 100644 (file)
@@ -1,3 +1,11 @@
+2004-11-04  Matthias Clasen  <mclasen@redhat.com>
+
+       * glib/gstrfuncs.c (g_ascii_strtod): Handle numbers like
+       1e1, nan, -infinity. Also try harder to preserve errno.  
+       (#156421, Morten Welinder)
+
+       * tests/strtod-test.c: Add testcases.
+
 2004-11-04  Tor Lillqvist  <tml@iki.fi>
 
        * glib/goption.h (enum GOptionFlags): Add G_OPTION_FLAG_REVERSE,
index a1f3123..afb0223 100644 (file)
@@ -335,6 +335,7 @@ g_ascii_strtod (const gchar *nptr,
   int decimal_point_len;
   const char *p, *decimal_point_pos;
   const char *end = NULL; /* Silence gcc */
+  int strtod_errno;
 
   g_return_val_if_fail (nptr != NULL, 0);
 
@@ -347,6 +348,8 @@ g_ascii_strtod (const gchar *nptr,
   g_assert (decimal_point_len != 0);
   
   decimal_point_pos = NULL;
+  end = NULL;
+
   if (decimal_point[0] != '.' || 
       decimal_point[1] != 0)
     {
@@ -369,48 +372,43 @@ g_ascii_strtod (const gchar *nptr,
            p++;
          
          if (*p == '.')
-           {
-             decimal_point_pos = p++;
+           decimal_point_pos = p++;
              
-             while (g_ascii_isxdigit (*p))
-               p++;
-             
-             if (*p == 'p' || *p == 'P')
-               p++;
-             if (*p == '+' || *p == '-')
-               p++;
-             while (g_ascii_isdigit (*p))
-               p++;
-           }
+         while (g_ascii_isxdigit (*p))
+           p++;
+         
+         if (*p == 'p' || *p == 'P')
+           p++;
+         if (*p == '+' || *p == '-')
+           p++;
+         while (g_ascii_isdigit (*p))
+           p++;
+
+         end = p;
        }
-      else
+      else if (g_ascii_isdigit (*p))
        {
          while (g_ascii_isdigit (*p))
            p++;
          
          if (*p == '.')
-           {
-             decimal_point_pos = p++;
-             
-             while (g_ascii_isdigit (*p))
-               p++;
-             
-             if (*p == 'e' || *p == 'E')
-               p++;
-             if (*p == '+' || *p == '-')
-               p++;
-             while (g_ascii_isdigit (*p))
-               p++;
-           }
+           decimal_point_pos = p++;
+         
+         while (g_ascii_isdigit (*p))
+           p++;
+         
+         if (*p == 'e' || *p == 'E')
+           p++;
+         if (*p == '+' || *p == '-')
+           p++;
+         while (g_ascii_isdigit (*p))
+           p++;
+
+         end = p;
        }
       /* For the other cases, we need not convert the decimal point */
-      end = p;
     }
 
-  /* Set errno to zero, so that we can distinguish zero results
-     and underflows */
-  errno = 0;
-  
   if (decimal_point_pos)
     {
       char *copy, *c;
@@ -427,7 +425,9 @@ g_ascii_strtod (const gchar *nptr,
       c += end - (decimal_point_pos + 1);
       *c = 0;
 
+      errno = 0;
       val = strtod (copy, &fail_pos);
+      strtod_errno = errno;
 
       if (fail_pos)
        {
@@ -440,8 +440,7 @@ g_ascii_strtod (const gchar *nptr,
       g_free (copy);
          
     }
-  else if (decimal_point[0] != '.' ||
-          decimal_point[1] != 0)
+  else if (end)
     {
       char *copy;
       
@@ -449,8 +448,10 @@ g_ascii_strtod (const gchar *nptr,
       memcpy (copy, nptr, end - nptr);
       *(copy + (end - (char *)nptr)) = 0;
       
+      errno = 0;
       val = strtod (copy, &fail_pos);
-      
+      strtod_errno = errno;
+
       if (fail_pos)
        {
          fail_pos = (char *)nptr + (fail_pos - copy);
@@ -460,12 +461,16 @@ g_ascii_strtod (const gchar *nptr,
     }
   else
     {
+      errno = 0;
       val = strtod (nptr, &fail_pos);
+      strtod_errno = errno;
     }
 
   if (endptr)
     *endptr = fail_pos;
-  
+
+  errno = strtod_errno;
+
   return val;
 }
 
index 7e45570..3566ffe 100644 (file)
@@ -1,15 +1,19 @@
 #undef G_DISABLE_ASSERT
 #undef G_LOG_DOMAIN
 
+/* for NAN and INFINITY */
+#define _ISOC99_SOURCE
+
 #include <glib.h>
 #include <locale.h>
 #include <string.h>
+#include <stdlib.h>
 #include <math.h>
 
 void
 test_string (char *number, double res, gboolean check_end, int correct_len)
 {
-  gdouble d;
+  double d;
   char *locales[] = {"sv_SE", "en_US", "fa_IR", "C", "ru_RU"};
   int l;
   char *end;
@@ -26,8 +30,16 @@ test_string (char *number, double res, gboolean check_end, int correct_len)
     {
       setlocale (LC_NUMERIC, locales[l]);
       d = g_ascii_strtod (number, &end);
-      if (d != res)
-       g_print ("g_ascii_strtod on \"%s\" for locale %s failed\n", number, locales[l]);
+      if ((isfinite(d) && isfinite(res) && d != res) ||
+         (isnan (d) != isnan (res)) || 
+         (isinf (d) != isinf (res)))
+       {
+         g_print ("g_ascii_strtod on \"%s\" for locale %s failed\n", number, locales[l]);
+         g_print ("expected %lf (nan %d inf %d) actual %lf (nan %d inf %d)\n", 
+                  res, isnan (res), isinf (res), 
+                  d, isnan (d), isinf (d));
+         
+       }
       if (check_end && end - number != correct_len)
        g_print ("g_ascii_strtod on \"%s\" for locale %s endptr was wrong, leftover: %s\n", number, locales[l], end);
       if (!check_end && end - number != strlen (number))
@@ -50,10 +62,15 @@ main ()
   test_string ("-123.123", -123.123, FALSE, 0);
   test_string ("-123.123e2", -123.123e2, FALSE, 0);
   test_string ("-123.123e-2", -123.123e-2, FALSE, 0);
-  test_string ("1e1", 1e1, FALSE, 0);
   test_string ("5.4", 5.4, TRUE, 3);
   test_string ("5.4,5.5", 5.4, TRUE, 3);
   test_string ("5,4", 5.0, TRUE, 1);
+  /* the following are for #156421 */
+  test_string ("1e1", 1e1, FALSE, 0); 
+  test_string ("NAN", NAN, FALSE, 0);
+  test_string ("-nan", -NAN, FALSE, 0);
+  test_string ("INF", INFINITY, FALSE, 0);
+  test_string ("-infinity", -INFINITY, FALSE, 0);
   
   d = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
   g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));