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>
* 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 *).
* 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 *).
* 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_JUMPS_FUNC): Express in terms of _IO_JUMPS, and add cast to
THIS, since _IO_JUMPS no longer does it implicitly.
(_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.
(_IO_flush_all, _IO_flush_all_linebuffered, _IO_unbuffer_write):
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/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
to (struct _IO_FILE_plus *).

View File

@ -1,5 +1,5 @@
/* 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.
The GNU C Library is free software; you can redistribute it and/or
@ -30,19 +30,24 @@
static inline const STRING_TYPE *
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)
return end;
if (*grouping == '\0')
{
/* No grouping allowed. Accept all characters up to the first
thousands separator. */
while (begin < end && *begin != thousands)
++begin;
return begin;
}
#ifndef USE_WIDE_CHAR
thousands_len = strlen (thousands);
#endif
while (end > begin)
{
@ -50,8 +55,23 @@ correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
const char *gp = grouping;
/* Check first group. */
while (cp >= begin && (wchar_t) *cp != thousands)
--cp;
while (cp >= begin)
{
#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
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. */
while (cp >= begin && (wchar_t) *cp != thousands)
--cp;
while (cp >= begin)
{
#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)
/* OK, only digits followed. */
@ -105,8 +137,20 @@ correctly_grouped_prefix (const STRING_TYPE *begin, const STRING_TYPE *end,
/* Check the next group. */
const STRING_TYPE *group_end = cp;
while (cp >= begin && (wchar_t) *cp != thousands)
--cp;
while (cp >= begin)
{
#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)
/* Final group is correct. */

View File

@ -1,6 +1,6 @@
/* Read decimal floating point numbers.
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.
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. */
static inline const STRING_TYPE *
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. */
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
format of the number is correct and we have an exact number
of characters to read. */
while (*str < L_('0') || *str > L_('9'))
#ifdef USE_WIDE_CHAR
if (*str < L'0' || *str > L'9')
++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');
++cnt;
}
@ -451,12 +470,23 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
typedef unsigned int wint_t;
#endif
/* The radix character of the current locale. */
#ifdef USE_WIDE_CHAR
wchar_t decimal;
#else
const char *decimal;
size_t decimal_len;
#endif
/* The thousands character of the current locale. */
#ifdef USE_WIDE_CHAR
wchar_t thousands = L'\0';
#else
const char *thousands = NULL;
#endif
/* The numeric grouping specification of the current locale,
in the format described in <locale.h>. */
const char *grouping;
/* Used in several places. */
int cnt;
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *current = loc->__locales[LC_NUMERIC];
@ -470,21 +500,34 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
else
{
/* Figure out the thousands separator character. */
thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
if (thousands == WEOF)
thousands = L'\0';
#ifdef USE_WIDE_CHAR
thousands = _NL_CURRENT_WORD (LC_NUMERIC,
_NL_NUMERIC_THOUSANDS_SEP_WC);
if (thousands == L'\0')
grouping = NULL;
#else
thousands = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
if (*thousands == '\0')
{
thousands = NULL;
grouping = NULL;
}
#endif
}
}
else
grouping = NULL;
/* Find the locale's decimal point character. */
decimal = __btowc (*_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT));
if (decimal == WEOF)
decimal = L'.';
#ifdef USE_WIDE_CHAR
decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
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. */
exponent = 0;
@ -510,8 +553,23 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
/* Return 0.0 if no legal string is found.
No character is used even if a sign was found. */
if ((c < L_('0') || c > L_('9'))
&& ((wchar_t) c != decimal || cp[1] < L_('0') || cp[1] > L_('9')))
#ifdef USE_WIDE_CHAR
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;
/* Check for `INF' or `INFINITY'. */
@ -588,16 +646,45 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
start_of_digits = startp = cp;
/* 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;
#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.
Return current read pointer. */
if ((c < L_('0') || c > L_('9')) &&
(base == 16 && (c < TOLOWER (L_('a')) || c > TOLOWER (L_('f')))) &&
(wchar_t) c != decimal &&
(base == 16 && (cp == start_of_digits || TOLOWER (c) != L_('p'))) &&
(base != 16 && TOLOWER (c) != L_('e')))
if ((c < L_('0') || c > L_('9'))
&& (base == 16 && (c < TOLOWER (L_('a')) || c > TOLOWER (L_('f'))))
#ifdef USE_WIDE_CHAR
&& c != decimal
#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);
/* 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'))
|| (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
++dig_no;
else if (thousands == L'\0' || (wchar_t) c != thousands)
/* Not a digit or separator: end of the integer part. */
break;
else
{
#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;
}
@ -667,9 +770,19 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
/* Read the fractional digits. A special case are the 'american style'
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')) ||
(base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
{
@ -779,9 +892,24 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
if (lead_zero)
{
/* Find the decimal point */
while ((wchar_t) *startp != decimal)
#ifdef USE_WIDE_CHAR
while (*startp != decimal)
++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;
dig_no -= lead_zero;
}
@ -828,8 +956,8 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
while (--dig_no > 0 && idx >= 0)
{
while (!ISXDIGIT (*startp))
++startp;
if (!ISXDIGIT (*startp))
startp += decimal_len;
if (ISDIGIT (*startp))
val = *startp++ - L_('0');
else
@ -885,7 +1013,11 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
if (int_no > 0)
{
/* 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)
{
@ -1031,7 +1163,6 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
123e-6 gives 123 / 1000000. */
int expbit;
int cnt;
int neg_exp;
int more_bits;
mp_limb_t cy;
@ -1095,8 +1226,11 @@ INTERNAL (STRTOF) (nptr, endptr, group LOCALE_PARAM)
memcpy (den, num, densize * sizeof (mp_limb_t));
/* 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
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.
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.
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;
const STRING_TYPE *save, *end;
int overflow;
#ifndef USE_WIDE_CHAR
int cnt;
#endif
#ifdef USE_NUMBER_GROUPING
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
struct locale_data *current = loc->__locales[LC_NUMERIC];
# endif
/* The thousands character of the current locale. */
# ifdef USE_WIDE_CHAR
wchar_t thousands = L'\0';
# else
const char *thousands = NULL;
# endif
/* The numeric grouping specification of the current locale,
in the format described in <locale.h>. */
const char *grouping;
@ -262,13 +269,23 @@ INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
else
{
/* Figure out the thousands separator character. */
# if defined _LIBC || defined _HAVE_BTOWC
thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
if (thousands == WEOF)
thousands = L'\0';
# endif
# ifdef USE_WIDE_CHAR
# ifdef _LIBC
thousands = _NL_CURRENT_WORD (LC_NUMERIC,
_NL_NUMERIC_THOUSANDS_SEP_WC);
# endif
if (thousands == L'\0')
grouping = NULL;
# else
# ifdef _LIBC
thousands = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
# endif
if (*thousands == '\0')
{
thousands = NULL;
grouping = NULL;
}
# endif
}
}
else
@ -325,15 +342,33 @@ INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
{
/* Find the end of the digit string and check its grouping. */
end = s;
for (c = *end; c != L_('\0'); c = *++end)
if ((wchar_t) c != thousands
&& ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
&& (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
break;
if (*s == thousands)
end = s;
else
end = correctly_grouped_prefix (s, end, thousands, grouping);
if (
# ifdef USE_WIDE_CHAR
*s != thousands
# else
({ for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
if (thousands[cnt] != end[cnt])
break;
thousands[cnt] != '\0'; })
# 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
#endif