2000-06-29  Ulrich Drepper  <drepper@redhat.com>

	* stdlib/grouping.h: Correctly handle multibyte thousands
	separator and decimal point.
	* stdlib/stdtod.c: Likewise.
	* sysdeps/generic/strtol.c: Likewise.

	* locale/categories.def: Add entries for wide character decimal point
	and thousands separator in numeric and monetary category.

2000-06-28  Ulrich Drepper  <drepper@redhat.com>

	* stdio-common/printf_fp.c (__printf_fp): Remove unnecessary
	second definition and initialization of decimal.

	* libio/libio.h (struct _IO_cookie_file): Move struct type defintion
	out.
	* libio/libioP.h (struct _IO_cookie_file): Move struct type defintion
	in.
	(_IO_JUMPS): Don't cast THIS--expect arg to be a
	(struct _IO_FILE_plus *).
	(_IO_iter_next, _IO_iter_file): _IO_ITER is now
		(struct _IO_FILE_plus *).
	(_IO_check_libio): Set user-visible handles to
	(struct _IO_FILE_plus *).
This commit is contained in:
Ulrich Drepper 2000-06-29 08:44:37 +00:00
parent 23335dcd5f
commit a748c3c64c
4 changed files with 299 additions and 66 deletions

View File

@ -1,9 +1,27 @@
2000-06-29 Ulrich Drepper <drepper@redhat.com>
* stdlib/grouping.h: Correctly handle multibyte thousands
separator and decimal point.
* stdlib/stdtod.c: Likewise.
* sysdeps/generic/strtol.c: Likewise.
* locale/categories.def: Add entries for wide character decimal point
and thousands separator in numeric and monetary category.
2000-06-28 Ulrich Drepper <drepper@redhat.com>
* stdio-common/printf_fp.c (__printf_fp): Remove unnecessary
second definition and initialization of decimal.
2000-06-28 Greg McGary <greg@mcgary.org> 2000-06-28 Greg McGary <greg@mcgary.org>
* libio/libio.h (struct _IO_cookie_file): Move struct type defintion out. * libio/libio.h (struct _IO_cookie_file): Move struct type defintion
out.
(_IO_FILE): Declare chain as (struct _IO_FILE_plus *). (_IO_FILE): Declare chain as (struct _IO_FILE_plus *).
* libio/libioP.h (struct _IO_cookie_file): Move struct type defintion in. * libio/libioP.h (struct _IO_cookie_file): Move struct type defintion
(_IO_JUMPS): Don't cast THIS--expect arg to be a (struct _IO_FILE_plus *). in.
(_IO_JUMPS): Don't cast THIS--expect arg to be a
(struct _IO_FILE_plus *).
(_IO_JUMPS_FUNC): Express in terms of _IO_JUMPS, and add cast to (_IO_JUMPS_FUNC): Express in terms of _IO_JUMPS, and add cast to
THIS, since _IO_JUMPS no longer does it implicitly. THIS, since _IO_JUMPS no longer does it implicitly.
(_IO_file_init, _IO_old_file_init, _IO_new_file_init): Declare (_IO_file_init, _IO_old_file_init, _IO_new_file_init): Declare
@ -18,10 +36,12 @@
* libio/genops.c (_IO_link_in, _IO_un_link): Likewise. * libio/genops.c (_IO_link_in, _IO_un_link): Likewise.
(_IO_flush_all, _IO_flush_all_linebuffered, _IO_unbuffer_write): (_IO_flush_all, _IO_flush_all_linebuffered, _IO_unbuffer_write):
Declare iteration pointer as (struct _IO_FILE_plus *). Declare iteration pointer as (struct _IO_FILE_plus *).
(_IO_iter_next, _IO_iter_file): _IO_ITER is now (struct _IO_FILE_plus *). (_IO_iter_next, _IO_iter_file): _IO_ITER is now
(struct _IO_FILE_plus *).
* libio/stdfiles.c (_IO_list_all): Declare as (struct _IO_FILE_plus *). * libio/stdfiles.c (_IO_list_all): Declare as (struct _IO_FILE_plus *).
* libio/oldstdfiles.c (_IO_list_all): Likewise. * libio/oldstdfiles.c (_IO_list_all): Likewise.
(_IO_check_libio): Set user-visible handles to (struct _IO_FILE_plus *). (_IO_check_libio): Set user-visible handles to
(struct _IO_FILE_plus *).
* libio/stdio.c (stdin, stdout, stderr): Set user-visible handles * libio/stdio.c (stdin, stdout, stderr): Set user-visible handles
to (struct _IO_FILE_plus *). to (struct _IO_FILE_plus *).

View File

@ -1,5 +1,5 @@
/* Internal header for proving correct grouping in strings of numbers. /* Internal header for proving correct grouping in strings of numbers.
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -30,19 +30,24 @@
static inline const STRING_TYPE * static inline const STRING_TYPE *
correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end, correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
wchar_t thousands, const char *grouping) #ifdef USE_WIDE_CHAR
wchar_t thousands,
#else
const char *thousands,
#endif
const char *grouping)
{ {
#ifndef USE_WIDE_CHAR
size_t thousands_len;
int cnt;
#endif
if (grouping == NULL) if (grouping == NULL)
return end; return end;
if (*grouping == '\0') #ifndef USE_WIDE_CHAR
{ thousands_len = strlen (thousands);
/* No grouping allowed. Accept all characters up to the first #endif
thousands separator. */
while (begin < end && *begin != thousands)
++begin;
return begin;
}
while (end > begin) while (end > begin)
{ {
@ -50,8 +55,23 @@ correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
const char *gp = grouping; const char *gp = grouping;
/* Check first group. */ /* Check first group. */
while (cp >= begin && (wchar_t) *cp != thousands) while (cp >= begin)
--cp; {
#ifdef USE_WIDE_CHAR
if (*cp == thousands)
break;
#else
if (cp[thousands_len - 1] == *thousands)
{
for (cnt = 1; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != cp[thousands_len - 1 - cnt])
break;
if (thousands[cnt] == '\0')
break;
}
#endif
--cp;
}
/* We allow the representation to contain no grouping at all even if /* We allow the representation to contain no grouping at all even if
the locale specifies we can have grouping. */ the locale specifies we can have grouping. */
@ -93,8 +113,20 @@ correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
) )
{ {
/* No more thousands separators are allowed to follow. */ /* No more thousands separators are allowed to follow. */
while (cp >= begin && (wchar_t) *cp != thousands) while (cp >= begin)
--cp; {
#ifdef USE_WIDE_CHAR
if (*cp == thousands)
break;
#else
for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != cp[thousands_len - cnt - 1])
break;
if (thousands[cnt] == '\0')
break;
#endif
--cp;
}
if (cp < begin) if (cp < begin)
/* OK, only digits followed. */ /* OK, only digits followed. */
@ -105,8 +137,20 @@ correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
/* Check the next group. */ /* Check the next group. */
const STRING_TYPE *group_end = cp; const STRING_TYPE *group_end = cp;
while (cp >= begin && (wchar_t) *cp != thousands) while (cp >= begin)
--cp; {
#ifdef USE_WIDE_CHAR
if (*cp == thousands)
break;
#else
for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != cp[thousands_len - cnt - 1])
break;
if (thousands[cnt] == '\0')
break;
#endif
--cp;
}
if (cp < begin && group_end - cp <= (int) *gp) if (cp < begin && group_end - cp <= (int) *gp)
/* Final group is correct. */ /* Final group is correct. */

View File

@ -1,6 +1,6 @@
/* Read decimal floating point numbers. /* Read decimal floating point numbers.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
Contributed by Ulrich Drepper <drepper@gnu.org>, 1995. Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -301,7 +301,12 @@ round_and_return (mp_limb_t *retval, int exponent, int negative,
factor for the resulting number (see code) multiply by it. */ factor for the resulting number (see code) multiply by it. */
static inline const STRING_TYPE * static inline const STRING_TYPE *
str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize, str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize,
int *exponent) int *exponent
#ifndef USE_WIDE_CHAR
, const char *decimal, size_t decimal_len, const char *thousands
#endif
)
{ {
/* Number of digits for actual limb. */ /* Number of digits for actual limb. */
int cnt = 0; int cnt = 0;
@ -338,8 +343,22 @@ str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize,
the string. But these all can be ignored because we know the the string. But these all can be ignored because we know the
format of the number is correct and we have an exact number format of the number is correct and we have an exact number
of characters to read. */ of characters to read. */
while (*str < L_('0') || *str > L_('9')) #ifdef USE_WIDE_CHAR
if (*str < L'0' || *str > L'9')
++str; ++str;
#else
if (*str < '0' || *str > '9')
{
if (thousands != NULL && *str == *thousands
&& ({ for (cnt == 1; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != str[cnt])
break;
thousands[cnt] == '\0'; }))
str += cnt;
else
str += decimal_len;
}
#endif
low = low * 10 + *str++ - L_('0'); low = low * 10 + *str++ - L_('0');
++cnt; ++cnt;
} }
@ -451,12 +470,23 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
typedef unsigned int wint_t; typedef unsigned int wint_t;
#endif #endif
/* The radix character of the current locale. */ /* The radix character of the current locale. */
#ifdef USE_WIDE_CHAR
wchar_t decimal; wchar_t decimal;
#else
const char *decimal;
size_t decimal_len;
#endif
/* The thousands character of the current locale. */ /* The thousands character of the current locale. */
#ifdef USE_WIDE_CHAR
wchar_t thousands = L'\0'; wchar_t thousands = L'\0';
#else
const char *thousands = NULL;
#endif
/* The numeric grouping specification of the current locale, /* The numeric grouping specification of the current locale,
in the format described in <locale.h>. */ in the format described in <locale.h>. */
const char *grouping; const char *grouping;
/* Used in several places. */
int cnt;
#ifdef USE_IN_EXTENDED_LOCALE_MODEL #ifdef USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *current = loc->__locales[LC_NUMERIC]; struct locale_data *current = loc->__locales[LC_NUMERIC];
@ -470,21 +500,34 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
else else
{ {
/* Figure out the thousands separator character. */ /* Figure out the thousands separator character. */
thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP)); #ifdef USE_WIDE_CHAR
if (thousands == WEOF) thousands = _NL_CURRENT_WORD (LC_NUMERIC,
thousands = L'\0'; _NL_NUMERIC_THOUSANDS_SEP_WC);
if (thousands == L'\0') if (thousands == L'\0')
grouping = NULL; grouping = NULL;
#else
thousands = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
if (*thousands == '\0')
{
thousands = NULL;
grouping = NULL;
}
#endif
} }
} }
else else
grouping = NULL; grouping = NULL;
/* Find the locale's decimal point character. */ /* Find the locale's decimal point character. */
decimal = __btowc (*_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT)); #ifdef USE_WIDE_CHAR
if (decimal == WEOF) decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
decimal = L'.';
assert (decimal != L'\0'); assert (decimal != L'\0');
# define decimal_len 1
#else
decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
decimal_len = strlen (decimal);
assert (decimal_len > 0);
#endif
/* Prepare number representation. */ /* Prepare number representation. */
exponent = 0; exponent = 0;
@ -510,8 +553,23 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
/* Return 0.0 if no legal string is found. /* Return 0.0 if no legal string is found.
No character is used even if a sign was found. */ No character is used even if a sign was found. */
if ((c < L_('0') || c > L_('9')) #ifdef USE_WIDE_CHAR
&& ((wchar_t) c != decimal || cp[1] < L_('0') || cp[1] > L_('9'))) if (c == decimal && cp[1] >= L'0' && cp[1] <= L'9')
{
/* We accept it. This funny construct is here only to indent
the code directly. */
}
#else
for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
if (cp[cnt] != decimal[cnt])
break;
if (decimal[cnt] == '\0' && cp[1] >= '0' && cp[1] <= '9')
{
/* We accept it. This funny construct is here only to indent
the code directly. */
}
#endif
else if (c < L_('0') || c > L_('9'))
{ {
int matched = 0; int matched = 0;
/* Check for `INF' or `INFINITY'. */ /* Check for `INF' or `INFINITY'. */
@ -588,16 +646,45 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
start_of_digits = startp = cp; start_of_digits = startp = cp;
/* Ignore leading zeroes. This helps us to avoid useless computations. */ /* Ignore leading zeroes. This helps us to avoid useless computations. */
while (c == L_('0') || (thousands != L'\0' && (wchar_t) c == thousands)) #ifdef USE_WIDE_CHAR
while (c == L'0' || (thousands != L'\0' && c == thousands))
c = *++cp; c = *++cp;
#else
if (thousands == NULL)
while (c == '0')
c = *++cp;
else
{
/* We also have the multibyte thousands string. */
while (1)
{
if (c != '0')
{
for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (c != thousands[cnt])
break;
if (thousands[cnt] != '\0')
break;
}
c = *++cp;
}
}
#endif
/* If no other digit but a '0' is found the result is 0.0. /* If no other digit but a '0' is found the result is 0.0.
Return current read pointer. */ Return current read pointer. */
if ((c < L_('0') || c > L_('9')) && if ((c < L_('0') || c > L_('9'))
(base == 16 && (c < TOLOWER (L_('a')) || c > TOLOWER (L_('f')))) && && (base == 16 && (c < TOLOWER (L_('a')) || c > TOLOWER (L_('f'))))
(wchar_t) c != decimal && #ifdef USE_WIDE_CHAR
(base == 16 && (cp == start_of_digits || TOLOWER (c) != L_('p'))) && && c != decimal
(base != 16 && TOLOWER (c) != L_('e'))) #else
&& ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
if (decimal[cnt] != cp[cnt])
break;
decimal[cnt] != '\0'; })
#endif
&& (base == 16 && (cp == start_of_digits || TOLOWER (c) != L_('p')))
&& (base != 16 && TOLOWER (c) != L_('e')))
{ {
tp = correctly_grouped_prefix (start_of_digits, cp, thousands, grouping); tp = correctly_grouped_prefix (start_of_digits, cp, thousands, grouping);
/* If TP is at the start of the digits, there was no correctly /* If TP is at the start of the digits, there was no correctly
@ -617,9 +704,25 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
if ((c >= L_('0') && c <= L_('9')) if ((c >= L_('0') && c <= L_('9'))
|| (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f'))) || (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
++dig_no; ++dig_no;
else if (thousands == L'\0' || (wchar_t) c != thousands) else
/* Not a digit or separator: end of the integer part. */ {
break; #ifdef USE_WIDE_CHAR
if (thousands == L'\0' || c != thousands)
/* Not a digit or separator: end of the integer part. */
break;
#else
if (thousands == NULL)
break;
else
{
for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != cp[cnt])
break;
if (thousands[cnt] != '\0')
break;
}
#endif
}
c = *++cp; c = *++cp;
} }
@ -667,9 +770,19 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
/* Read the fractional digits. A special case are the 'american style' /* Read the fractional digits. A special case are the 'american style'
numbers like `16.' i.e. with decimal but without trailing digits. */ numbers like `16.' i.e. with decimal but without trailing digits. */
if ((wchar_t) c == decimal) if (
#ifdef USE_WIDE_CHAR
c == decimal
#else
({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
if (decimal[cnt] != cp[cnt])
break;
decimal[cnt] == '\0'; })
#endif
)
{ {
c = *++cp; cp += decimal_len;
c = *cp;
while ((c >= L_('0') && c <= L_('9')) || while ((c >= L_('0') && c <= L_('9')) ||
(base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f'))) (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
{ {
@ -779,9 +892,24 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
if (lead_zero) if (lead_zero)
{ {
/* Find the decimal point */ /* Find the decimal point */
while ((wchar_t) *startp != decimal) #ifdef USE_WIDE_CHAR
while (*startp != decimal)
++startp; ++startp;
startp += lead_zero + 1; #else
while (1)
{
if (*startp == decimal[0])
{
for (cnt = 1; decimal[cnt] != '\0'; ++cnt)
if (decimal[cnt] != startp[cnt])
break;
if (decimal[cnt] == '\0')
break;
}
++startp;
}
#endif
startp += lead_zero + decimal_len;
exponent -= base == 16 ? 4 * lead_zero : lead_zero; exponent -= base == 16 ? 4 * lead_zero : lead_zero;
dig_no -= lead_zero; dig_no -= lead_zero;
} }
@ -828,8 +956,8 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
while (--dig_no > 0 && idx >= 0) while (--dig_no > 0 && idx >= 0)
{ {
while (!ISXDIGIT (*startp)) if (!ISXDIGIT (*startp))
++startp; startp += decimal_len;
if (ISDIGIT (*startp)) if (ISDIGIT (*startp))
val = *startp++ - L_('0'); val = *startp++ - L_('0');
else else
@ -885,7 +1013,11 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
if (int_no > 0) if (int_no > 0)
{ {
/* Read the integer part as a multi-precision number to NUM. */ /* Read the integer part as a multi-precision number to NUM. */
startp = str_to_mpn (startp, int_no, num, &numsize, &exponent); startp = str_to_mpn (startp, int_no, num, &numsize, &exponent
#ifndef USE_WIDE_CHAR
, decimal, decimal_len, thousands
#endif
);
if (exponent > 0) if (exponent > 0)
{ {
@ -1031,7 +1163,6 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
123e-6 gives 123 / 1000000. */ 123e-6 gives 123 / 1000000. */
int expbit; int expbit;
int cnt;
int neg_exp; int neg_exp;
int more_bits; int more_bits;
mp_limb_t cy; mp_limb_t cy;
@ -1095,8 +1226,11 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
memcpy (den, num, densize * sizeof (mp_limb_t)); memcpy (den, num, densize * sizeof (mp_limb_t));
/* Read the fractional digits from the string. */ /* Read the fractional digits from the string. */
(void) str_to_mpn (startp, dig_no - int_no, num, &numsize, &exponent); (void) str_to_mpn (startp, dig_no - int_no, num, &numsize, &exponent
#ifndef USE_WIDE_CHAR
, decimal, decimal_len, thousands
#endif
);
/* We now have to shift both numbers so that the highest bit in the /* We now have to shift both numbers so that the highest bit in the
denominator is set. In the same process we copy the numerator to denominator is set. In the same process we copy the numerator to

View File

@ -1,5 +1,5 @@
/* Convert string representation of a number into an integer value. /* Convert string representation of a number into an integer value.
Copyright (C) 1991,92,94,95,96,97,98,99 Free Software Foundation, Inc. Copyright (C) 1991,92,94,95,96,97,98,99,2000 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -243,13 +243,20 @@ INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
register UCHAR_TYPE c; register UCHAR_TYPE c;
const STRING_TYPE *save, *end; const STRING_TYPE *save, *end;
int overflow; int overflow;
#ifndef USE_WIDE_CHAR
int cnt;
#endif
#ifdef USE_NUMBER_GROUPING #ifdef USE_NUMBER_GROUPING
# ifdef USE_IN_EXTENDED_LOCALE_MODEL # ifdef USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *current = loc->__locales[LC_NUMERIC]; struct locale_data *current = loc->__locales[LC_NUMERIC];
# endif # endif
/* The thousands character of the current locale. */ /* The thousands character of the current locale. */
# ifdef USE_WIDE_CHAR
wchar_t thousands = L'\0'; wchar_t thousands = L'\0';
# else
const char *thousands = NULL;
# endif
/* The numeric grouping specification of the current locale, /* The numeric grouping specification of the current locale,
in the format described in <locale.h>. */ in the format described in <locale.h>. */
const char *grouping; const char *grouping;
@ -262,13 +269,23 @@ INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
else else
{ {
/* Figure out the thousands separator character. */ /* Figure out the thousands separator character. */
# if defined _LIBC || defined _HAVE_BTOWC # ifdef USE_WIDE_CHAR
thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP)); # ifdef _LIBC
if (thousands == WEOF) thousands = _NL_CURRENT_WORD (LC_NUMERIC,
thousands = L'\0'; _NL_NUMERIC_THOUSANDS_SEP_WC);
# endif # endif
if (thousands == L'\0') if (thousands == L'\0')
grouping = NULL; grouping = NULL;
# else
# ifdef _LIBC
thousands = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
# endif
if (*thousands == '\0')
{
thousands = NULL;
grouping = NULL;
}
# endif
} }
} }
else else
@ -325,15 +342,33 @@ INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
{ {
/* Find the end of the digit string and check its grouping. */ /* Find the end of the digit string and check its grouping. */
end = s; end = s;
for (c = *end; c != L_('\0'); c = *++end) if (
if ((wchar_t) c != thousands # ifdef USE_WIDE_CHAR
&& ((wchar_t) c < L_('0') || (wchar_t) c > L_('9')) *s != thousands
&& (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base)) # else
break; ({ for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (*s == thousands) if (thousands[cnt] != end[cnt])
end = s; break;
else thousands[cnt] != '\0'; })
end = correctly_grouped_prefix (s, end, thousands, grouping); # endif
)
{
for (c = *end; c != L_('\0'); c = *++end)
if (((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
# ifdef USE_WIDE_CHAR
&& c != thousands
# else
&& ({ for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != end[cnt])
break;
thousands[cnt] != '\0'; })
# endif
&& (!ISALPHA (c)
|| (int) (TOUPPER (c) - L_('A') + 10) >= base))
break;
end = correctly_grouped_prefix (s, end, thousands, grouping);
}
} }
else else
#endif #endif