about summary refs log tree commit diff
path: root/stdlib/strtod_l.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/strtod_l.c')
-rw-r--r--stdlib/strtod_l.c101
1 files changed, 70 insertions, 31 deletions
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index a656789f4c..bb7493bff0 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -1,5 +1,6 @@
 /* Convert string representing a number to float value, using given locale.
-   Copyright (C) 1997,98,2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1997,1998,2002,2004,2005,2006,2007
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -28,6 +29,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
    `strtof.c', `wcstod.c', `wcstold.c', and `wcstof.c' to produce the
    `long double' and `float' versions of the reader.  */
 #ifndef FLOAT
+# include <math_ldbl_opt.h>
 # define FLOAT		double
 # define FLT		DBL
 # ifdef USE_WIDE_CHAR
@@ -68,8 +70,8 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
    and _LONG_LONG_LIMB in it can take effect into gmp.h.  */
 #include <gmp-mparam.h>
 #include <gmp.h>
-#include <gmp-impl.h>
-#include <longlong.h>
+#include "gmp-impl.h"
+#include "longlong.h"
 #include "fpioconst.h"
 
 #define NDEBUG 1
@@ -100,7 +102,9 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
 # define ISDIGIT(Ch) __iswdigit_l ((Ch), loc)
 # define ISXDIGIT(Ch) __iswxdigit_l ((Ch), loc)
 # define TOLOWER(Ch) __towlower_l ((Ch), loc)
-# define STRNCASECMP(S1, S2, N) __wcsncasecmp_l ((S1), (S2), (N), loc)
+# define TOLOWER_C(Ch) __towlower_l ((Ch), _nl_C_locobj_ptr)
+# define STRNCASECMP(S1, S2, N) \
+  __wcsncasecmp_l ((S1), (S2), (N), _nl_C_locobj_ptr)
 # define STRTOULL(S, E, B) ____wcstoull_l_internal ((S), (E), (B), 0, loc)
 #else
 # define STRING_TYPE char
@@ -110,7 +114,9 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
 # define ISDIGIT(Ch) __isdigit_l ((Ch), loc)
 # define ISXDIGIT(Ch) __isxdigit_l ((Ch), loc)
 # define TOLOWER(Ch) __tolower_l ((Ch), loc)
-# define STRNCASECMP(S1, S2, N) __strncasecmp_l ((S1), (S2), (N), loc)
+# define TOLOWER_C(Ch) __tolower_l ((Ch), _nl_C_locobj_ptr)
+# define STRNCASECMP(S1, S2, N) \
+  __strncasecmp_l ((S1), (S2), (N), _nl_C_locobj_ptr)
 # define STRTOULL(S, E, B) ____strtoull_l_internal ((S), (E), (B), 0, loc)
 #endif
 
@@ -402,6 +408,9 @@ __mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count,
 
 #define INTERNAL(x) INTERNAL1(x)
 #define INTERNAL1(x) __##x##_internal
+#ifndef ____STRTOF_INTERNAL
+# define ____STRTOF_INTERNAL INTERNAL (__STRTOF)
+#endif
 
 /* This file defines a function to check for correct grouping.  */
 #include "grouping.h"
@@ -413,7 +422,7 @@ __mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count,
    return 0.0.  If the number is too big to be represented, set `errno' to
    ERANGE and return HUGE_VAL with the appropriate sign.  */
 FLOAT
-INTERNAL (__STRTOF) (nptr, endptr, group, loc)
+____STRTOF_INTERNAL (nptr, endptr, group, loc)
      const STRING_TYPE *nptr;
      STRING_TYPE **endptr;
      int group;
@@ -554,7 +563,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
   else if (c < L_('0') || c > L_('9'))
     {
       /* Check for `INF' or `INFINITY'.  */
-      if (TOLOWER (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
+      if (TOLOWER_C (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
 	{
 	  /* Return +/- infinity.  */
 	  if (endptr != NULL)
@@ -565,7 +574,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 	  return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
 	}
 
-      if (TOLOWER (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
+      if (TOLOWER_C (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
 	{
 	  /* Return NaN.  */
 	  FLOAT retval = NAN;
@@ -642,10 +651,11 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 	  if (c != '0')
 	    {
 	      for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
-		if (c != thousands[cnt])
+		if (thousands[cnt] != cp[cnt])
 		  break;
 	      if (thousands[cnt] != '\0')
 		break;
+	      cp += cnt - 1;
 	    }
 	  c = *++cp;
 	}
@@ -654,20 +664,29 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 
   /* If no other digit but a '0' is found the result is 0.0.
      Return current read pointer.  */
-  if ((c < L_('0') || c > L_('9'))
-      && (base == 16 && (c < (CHAR_TYPE) TOLOWER (L_('a'))
-			 || c > (CHAR_TYPE) TOLOWER (L_('f'))))
+  if (!((c >= L_('0') && c <= L_('9'))
+	|| (base == 16 && ((CHAR_TYPE) TOLOWER (c) >= L_('a')
+			   && (CHAR_TYPE) TOLOWER (c) <= L_('f')))
+	|| (
 #ifdef USE_WIDE_CHAR
-      && c != (wint_t) decimal
+	    c == (wint_t) decimal
 #else
-      && ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
-	      if (decimal[cnt] != cp[cnt])
-		break;
-	    decimal[cnt] != '\0'; })
+	    ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
+		 if (decimal[cnt] != cp[cnt])
+		   break;
+	       decimal[cnt] == '\0'; })
 #endif
-      && (base == 16 && (cp == start_of_digits
-			 || (CHAR_TYPE) TOLOWER (c) != L_('p')))
-      && (base != 16 && (CHAR_TYPE) TOLOWER (c) != L_('e')))
+	    /* '0x.' alone is not a valid hexadecimal number.
+	       '.' alone is not valid either, but that has been checked
+	       already earlier.  */
+	    && (base != 16
+		|| cp != start_of_digits
+		|| (cp[decimal_len] >= L_('0') && cp[decimal_len] <= L_('9'))
+		|| ((CHAR_TYPE) TOLOWER (cp[decimal_len]) >= L_('a')
+		    && (CHAR_TYPE) TOLOWER (cp[decimal_len]) <= L_('f'))))
+	|| (base == 16 && (cp != start_of_digits
+			   && (CHAR_TYPE) TOLOWER (c) == L_('p')))
+	|| (base != 16 && (CHAR_TYPE) TOLOWER (c) == L_('e'))))
     {
 #ifdef USE_WIDE_CHAR
       tp = __correctly_grouped_prefixwc (start_of_digits, cp, thousands,
@@ -707,13 +726,14 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 		  break;
 	      if (thousands[cnt] != '\0')
 		break;
+	      cp += cnt - 1;
 	    }
 #endif
 	}
       c = *++cp;
     }
 
-  if (grouping && dig_no > 0)
+  if (grouping && cp > start_of_digits)
     {
       /* Check the grouping of the digits.  */
 #ifdef USE_WIDE_CHAR
@@ -751,13 +771,15 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 	}
     }
 
-  /* We have the number digits in the integer part.  Whether these are all or
-     any is really a fractional digit will be decided later.  */
+  /* We have the number of digits in the integer part.  Whether these
+     are all or any is really a fractional digit will be decided
+     later.  */
   int_no = dig_no;
   lead_zero = int_no == 0 ? -1 : 0;
 
-  /* Read the fractional digits.  A special case are the 'american style'
-     numbers like `16.' i.e. with decimal but without trailing digits.  */
+  /* Read the fractional digits.  A special case are the 'american
+     style' numbers like `16.' i.e. with decimal point but without
+     trailing digits.  */
   if (
 #ifdef USE_WIDE_CHAR
       c == (wint_t) decimal
@@ -807,15 +829,16 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 	  if (base == 16)
 	    exp_limit = (exp_negative ?
 			 -MIN_EXP + MANT_DIG + 4 * int_no :
-			 MAX_EXP - 4 * int_no + lead_zero);
+			 MAX_EXP - 4 * int_no + 4 * lead_zero + 3);
 	  else
 	    exp_limit = (exp_negative ?
 			 -MIN_10_EXP + MANT_DIG + int_no :
-			 MAX_10_EXP - int_no + lead_zero);
+			 MAX_10_EXP - int_no + lead_zero + 1);
 
 	  do
 	    {
 	      exponent *= 10;
+	      exponent += c - L_('0');
 
 	      if (exponent > exp_limit)
 		/* The exponent is too large/small to represent a valid
@@ -845,7 +868,6 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 		  /* NOTREACHED */
 		}
 
-	      exponent += c - L_('0');
 	      c = *++cp;
 	    }
 	  while (c >= L_('0') && c <= L_('9'));
@@ -880,7 +902,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
 	--expp;
 	--dig_no;
 	--int_no;
-	++exponent;
+	exponent += base == 16 ? 4 : 1;
       }
     while (dig_no > 0 && exponent < 0);
 
@@ -1553,7 +1575,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group, loc)
   /* NOTREACHED */
 }
 #if defined _LIBC && !defined USE_WIDE_CHAR
-libc_hidden_def (INTERNAL (__STRTOF))
+libc_hidden_def (____STRTOF_INTERNAL)
 #endif
 
 /* External user entry point.  */
@@ -1567,6 +1589,23 @@ __STRTOF (nptr, endptr, loc)
      STRING_TYPE **endptr;
      __locale_t loc;
 {
-  return INTERNAL (__STRTOF) (nptr, endptr, 0, loc);
+  return ____STRTOF_INTERNAL (nptr, endptr, 0, loc);
 }
 weak_alias (__STRTOF, STRTOF)
+
+#ifdef LONG_DOUBLE_COMPAT
+# if LONG_DOUBLE_COMPAT(libc, GLIBC_2_1)
+#  ifdef USE_WIDE_CHAR
+compat_symbol (libc, __wcstod_l, __wcstold_l, GLIBC_2_1);
+#  else
+compat_symbol (libc, __strtod_l, __strtold_l, GLIBC_2_1);
+#  endif
+# endif
+# if LONG_DOUBLE_COMPAT(libc, GLIBC_2_3)
+#  ifdef USE_WIDE_CHAR
+compat_symbol (libc, wcstod_l, wcstold_l, GLIBC_2_3);
+#  else
+compat_symbol (libc, strtod_l, strtold_l, GLIBC_2_3);
+#  endif
+# endif
+#endif