aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-03-14 21:12:06 +0000
committerUlrich Drepper <drepper@redhat.com>2004-03-14 21:12:06 +0000
commitccadf7b5346a3e21c692dfcbfcf38a63433bc36a (patch)
treea1e826af3345eee581925387513b1b6c76629c31
parentOptimize a bit. It's better to get a reference to the current locale and the... (diff)
downloadglibc-ccadf7b5346a3e21c692dfcbfcf38a63433bc36a.tar.gz
glibc-ccadf7b5346a3e21c692dfcbfcf38a63433bc36a.tar.bz2
glibc-ccadf7b5346a3e21c692dfcbfcf38a63433bc36a.zip
Update.
2004-03-14 Ulrich Drepper <drepper@redhat.com> Make the non-_l functions wrappers around the _l functions. * include/monetary.h: Declare __vstrmon_l. * include/string.h: Add libc_hidden_proto for __strcoll_l and __strxfrm_l. * include/time.h: Define ptime_locale_status. Declare __strptime_internal. * include/wchar.h: Add libc_hidden_proto for __wcscoll_l and __wcsxfrm_l. * stdlib/strfmon.c: Move the code to strfmon_l.c. Add little wrapper around __vstrfmon_l. * stdlib/strfmon_l.c: Add real implementation. Split into new function __vstrfmon_l to allow calling it from strfmon. * stdlib/strtod.c: Move real code to strtod_l.c and add wrapper. * stdlib/strtod_l.c: Add real implementation. * stdlib/strtof.c: Adjust to changed strtod.c. * stdlib/strtof_l.c: Include strtod_l.c now. * stdlib/strtold.c: New file. * stdlib/strtold_l.c: Removed. * string/strcoll.c: Move real code to strcoll_l.c: Add wrapper. * string/strcoll_l.c: Add real implementation. * string/strxfrm.c: Move real code to strxfrm_l.c: Add wrapper. * string/strxfrm_l.c: Add real implementation. * sysdeps/generic/strtol.c: Move real implementation to strtol_l.c. Add wrappers. * sysdeps/generic/strtol_l.c: Add real implementation. * sysdeps/generic/strtold.c: Removed. * sysdeps/generic/strtold_l.c: New file. * sysdeps/generic/strtoll_l.c: Include strtol_l.c now. Adjust #defines. * sysdeps/generic/strtoul_l.c: Likewise. * sysdeps/generic/strtoull_l.c: Likewise. * sysdeps/generic/wcstol_l.c: Likewise. * sysdeps/generic/wcstoll_l.c: Likewise. * sysdeps/generic/wcstoul_l.c: Likewise. * sysdeps/generic/wcstoull_l.c: Likewise. * sysdeps/ieee754/ldbl-128/strtold.c: Removed. * sysdeps/ieee754/ldbl-128/strtold_l.c: New file. * sysdeps/ieee754/ldbl-96/strtold.c: Removed. * sysdeps/ieee754/ldbl-96/strtold_l.c: New file. * sysdeps/m68k/strtold.c: Removed. * sysdeps/m68k/strtold_l.c: New file. * time/strftime.c: Move real code to strftime_l.c. Add wrapper. * time/strftime_l.c: Add real implementation. * time/strptime.c: Move real code to strptime_l.c. Add wrapper. * time/strptime_l.c: Add real implementation. * time/wcsftime.c: Simplify since only wrappers are defined in strftime.c. * time/wcsftime_l.c: Include strftime_l.c. * wcsmbs/wcscoll.c: Simplify since the file is not used by wcscoll_l.c anymore. * wcsmbs/wcscoll_l.c: Include strcoll_l.c. * wcsmbs/wcsxfrm.c: Simplify since the file is not used by wcsxfrm_l.c anymore. * wcsmbs/wcsxfrm_l.c: Include strxfrm_l.c. * wcsmbs/wcstod.c: Prepare to include new strtod.c. * wcsmbs/wcstod_l.c: Include strtod_l.c. * wcsmbs/wcstof.c: Prepare to include new strtof.c. * wcsmbs/wcstof_l.c: Include strtof_l.c. * wcsmbs/wcstold.c: Prepare to include new strtold.c. * wcsmbs/wcstold_l.c: Include strtold_l.c. * locale/uselocale.c: Use _NL_CURRENT_LOCALE instead of __libc_tsd_get. * sysdeps/generic/strcasecmp.c: Optimize a bit. It's better to get a reference to the current locale and then use the _l functions. * sysdeps/generic/strncase.c: Likewise.
-rw-r--r--ChangeLog69
-rw-r--r--include/monetary.h4
-rw-r--r--include/string.h2
-rw-r--r--include/time.h13
-rw-r--r--include/wchar.h3
-rw-r--r--locale/uselocale.c4
-rw-r--r--stdlib/strfmon.c632
-rw-r--r--stdlib/strfmon_l.c636
-rw-r--r--stdlib/strtod.c1560
-rw-r--r--stdlib/strtod_l.c1551
-rw-r--r--stdlib/strtof.c37
-rw-r--r--stdlib/strtof_l.c28
-rw-r--r--stdlib/strtold.c35
-rw-r--r--stdlib/strtold_l.c53
-rw-r--r--string/strcoll.c528
-rw-r--r--string/strcoll_l.c514
-rw-r--r--string/strxfrm.c444
-rw-r--r--string/strxfrm_l.c429
-rw-r--r--sysdeps/generic/strtol.c533
-rw-r--r--sysdeps/generic/strtol_l.c493
-rw-r--r--sysdeps/generic/strtold_l.c (renamed from sysdeps/generic/strtold.c)18
-rw-r--r--sysdeps/generic/strtoll_l.c8
-rw-r--r--sysdeps/generic/strtoul_l.c8
-rw-r--r--sysdeps/generic/strtoull_l.c9
-rw-r--r--sysdeps/generic/wcstol_l.c8
-rw-r--r--sysdeps/generic/wcstoll_l.c8
-rw-r--r--sysdeps/generic/wcstoul_l.c8
-rw-r--r--sysdeps/generic/wcstoull_l.c8
-rw-r--r--sysdeps/ieee754/ldbl-128/strtold_l.c (renamed from sysdeps/ieee754/ldbl-128/strtold.c)26
-rw-r--r--sysdeps/ieee754/ldbl-96/strtold_l.c (renamed from sysdeps/ieee754/ldbl-96/strtold.c)26
-rw-r--r--sysdeps/m68k/strtold.c2
-rw-r--r--sysdeps/m68k/strtold_l.c2
-rw-r--r--time/strftime.c1421
-rw-r--r--time/strftime_l.c1426
-rw-r--r--time/strptime.c1066
-rw-r--r--time/strptime_l.c1052
-rw-r--r--time/wcsftime.c32
-rw-r--r--time/wcsftime_l.c8
-rw-r--r--wcsmbs/wcscoll.c15
-rw-r--r--wcsmbs/wcscoll_l.c19
-rw-r--r--wcsmbs/wcstod.c8
-rw-r--r--wcsmbs/wcstod_l.c10
-rw-r--r--wcsmbs/wcstof.c29
-rw-r--r--wcsmbs/wcstof_l.c12
-rw-r--r--wcsmbs/wcstold.c48
-rw-r--r--wcsmbs/wcstold_l.c32
-rw-r--r--wcsmbs/wcsxfrm.c17
-rw-r--r--wcsmbs/wcsxfrm_l.c19
48 files changed, 6501 insertions, 6412 deletions
diff --git a/ChangeLog b/ChangeLog
index 372a32262b..3e41a14db2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,72 @@
+2004-03-14 Ulrich Drepper <drepper@redhat.com>
+
+ Make the non-_l functions wrappers around the _l functions.
+ * include/monetary.h: Declare __vstrmon_l.
+ * include/string.h: Add libc_hidden_proto for __strcoll_l and
+ __strxfrm_l.
+ * include/time.h: Define ptime_locale_status. Declare
+ __strptime_internal.
+ * include/wchar.h: Add libc_hidden_proto for __wcscoll_l and
+ __wcsxfrm_l.
+ * stdlib/strfmon.c: Move the code to strfmon_l.c. Add little
+ wrapper around __vstrfmon_l.
+ * stdlib/strfmon_l.c: Add real implementation. Split into new
+ function __vstrfmon_l to allow calling it from strfmon.
+ * stdlib/strtod.c: Move real code to strtod_l.c and add wrapper.
+ * stdlib/strtod_l.c: Add real implementation.
+ * stdlib/strtof.c: Adjust to changed strtod.c.
+ * stdlib/strtof_l.c: Include strtod_l.c now.
+ * stdlib/strtold.c: New file.
+ * stdlib/strtold_l.c: Removed.
+ * string/strcoll.c: Move real code to strcoll_l.c: Add wrapper.
+ * string/strcoll_l.c: Add real implementation.
+ * string/strxfrm.c: Move real code to strxfrm_l.c: Add wrapper.
+ * string/strxfrm_l.c: Add real implementation.
+ * sysdeps/generic/strtol.c: Move real implementation to strtol_l.c.
+ Add wrappers.
+ * sysdeps/generic/strtol_l.c: Add real implementation.
+ * sysdeps/generic/strtold.c: Removed.
+ * sysdeps/generic/strtold_l.c: New file.
+ * sysdeps/generic/strtoll_l.c: Include strtol_l.c now. Adjust
+ #defines.
+ * sysdeps/generic/strtoul_l.c: Likewise.
+ * sysdeps/generic/strtoull_l.c: Likewise.
+ * sysdeps/generic/wcstol_l.c: Likewise.
+ * sysdeps/generic/wcstoll_l.c: Likewise.
+ * sysdeps/generic/wcstoul_l.c: Likewise.
+ * sysdeps/generic/wcstoull_l.c: Likewise.
+ * sysdeps/ieee754/ldbl-128/strtold.c: Removed.
+ * sysdeps/ieee754/ldbl-128/strtold_l.c: New file.
+ * sysdeps/ieee754/ldbl-96/strtold.c: Removed.
+ * sysdeps/ieee754/ldbl-96/strtold_l.c: New file.
+ * sysdeps/m68k/strtold.c: Removed.
+ * sysdeps/m68k/strtold_l.c: New file.
+ * time/strftime.c: Move real code to strftime_l.c. Add wrapper.
+ * time/strftime_l.c: Add real implementation.
+ * time/strptime.c: Move real code to strptime_l.c. Add wrapper.
+ * time/strptime_l.c: Add real implementation.
+ * time/wcsftime.c: Simplify since only wrappers are defined in
+ strftime.c.
+ * time/wcsftime_l.c: Include strftime_l.c.
+ * wcsmbs/wcscoll.c: Simplify since the file is not used by wcscoll_l.c
+ anymore.
+ * wcsmbs/wcscoll_l.c: Include strcoll_l.c.
+ * wcsmbs/wcsxfrm.c: Simplify since the file is not used by wcsxfrm_l.c
+ anymore.
+ * wcsmbs/wcsxfrm_l.c: Include strxfrm_l.c.
+ * wcsmbs/wcstod.c: Prepare to include new strtod.c.
+ * wcsmbs/wcstod_l.c: Include strtod_l.c.
+ * wcsmbs/wcstof.c: Prepare to include new strtof.c.
+ * wcsmbs/wcstof_l.c: Include strtof_l.c.
+ * wcsmbs/wcstold.c: Prepare to include new strtold.c.
+ * wcsmbs/wcstold_l.c: Include strtold_l.c.
+
+ * locale/uselocale.c: Use _NL_CURRENT_LOCALE instead of __libc_tsd_get.
+
+ * sysdeps/generic/strcasecmp.c: Optimize a bit. It's better to get
+ a reference to the current locale and then use the _l functions.
+ * sysdeps/generic/strncase.c: Likewise.
+
2004-03-11 Jeroen Dekkers <jeroen@dekkers.cx>
* cppflags-iterator.mk: Change libof-$(cpp-src) to
diff --git a/include/monetary.h b/include/monetary.h
index 4735dc6c8a..98b3dbf294 100644
--- a/include/monetary.h
+++ b/include/monetary.h
@@ -1 +1,5 @@
#include <stdlib/monetary.h>
+#include <stdarg.h>
+
+extern ssize_t __vstrfmon_l (char *s, size_t maxsize, __locale_t loc,
+ const char *format, va_list ap);
diff --git a/include/string.h b/include/string.h
index 041590b1db..42d9362dfc 100644
--- a/include/string.h
+++ b/include/string.h
@@ -78,6 +78,8 @@ libc_hidden_proto (__strerror_r)
libc_hidden_proto (__strverscmp)
libc_hidden_proto (basename)
libc_hidden_proto (strcoll)
+libc_hidden_proto (__strcoll_l)
+libc_hidden_proto (__strxfrm_l)
libc_hidden_builtin_proto (memchr)
libc_hidden_builtin_proto (memcpy)
diff --git a/include/time.h b/include/time.h
index 87e0f08f8d..5a95be5a4e 100644
--- a/include/time.h
+++ b/include/time.h
@@ -3,6 +3,7 @@
# include <time/time.h>
#else
# include <time/time.h>
+# include <xlocale.h>
extern __typeof (strftime_l) __strftime_l;
libc_hidden_proto (__strftime_l)
@@ -84,6 +85,18 @@ extern int __getdate_r (__const char *__string, struct tm *__resbufp);
extern int __getclktck (void);
+/* strptime support. */
+/* Status of lookup: do we use the locale data or the raw data? */
+enum ptime_locale_status { not, loc, raw };
+
+extern char * __strptime_internal (const char *rp, const char *fmt,
+ struct tm *tm,
+ enum ptime_locale_status *decided,
+ int era_cnt, __locale_t loc)
+ internal_function;
+
+
+
/* Use in the clock_* functions. Size of the field representing the
actual clock ID. */
#ifndef _ISOMAC
diff --git a/include/wchar.h b/include/wchar.h
index f69463f57a..73bd4a8fef 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -29,6 +29,9 @@ libc_hidden_proto (__wcstoull_internal)
libc_hidden_proto (__wcscasecmp_l)
libc_hidden_proto (__wcsncasecmp_l)
+libc_hidden_proto (__wcscoll_l)
+libc_hidden_proto (__wcsxfrm_l)
+
libc_hidden_proto (fputws_unlocked)
libc_hidden_proto (putwc_unlocked)
libc_hidden_proto (putwc)
diff --git a/locale/uselocale.c b/locale/uselocale.c
index e2f38c10ba..4e63dabd8e 100644
--- a/locale/uselocale.c
+++ b/locale/uselocale.c
@@ -1,5 +1,5 @@
/* uselocale -- fetch and set the current per-thread locale
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004 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
@@ -29,7 +29,7 @@
locale_t
__uselocale (locale_t newloc)
{
- locale_t oldloc = __libc_tsd_get (LOCALE);
+ locale_t oldloc = _NL_CURRENT_LOCALE;
if (newloc != NULL)
{
diff --git a/stdlib/strfmon.c b/stdlib/strfmon.c
index b17dc9823c..b11f95c9ac 100644
--- a/stdlib/strfmon.c
+++ b/stdlib/strfmon.c
@@ -19,645 +19,21 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <ctype.h>
-#include <errno.h>
-#include <langinfo.h>
-#include <locale.h>
#include <monetary.h>
-#ifdef USE_IN_LIBIO
-# include "../libio/libioP.h"
-# include "../libio/strfile.h"
-#endif
-#include <printf.h>
#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include "../locale/localeinfo.h"
+#include <locale/localeinfo.h>
-#define out_char(Ch) \
- do { \
- if (dest >= s + maxsize - 1) \
- { \
- __set_errno (E2BIG); \
- va_end (ap); \
- return -1; \
- } \
- *dest++ = (Ch); \
- } while (0)
-
-#define out_string(String) \
- do { \
- const char *_s = (String); \
- while (*_s) \
- out_char (*_s++); \
- } while (0)
-
-#define out_nstring(String, N) \
- do { \
- int _n = (N); \
- const char *_s = (String); \
- while (_n-- > 0) \
- out_char (*_s++); \
- } while (0)
-
-#define to_digit(Ch) ((Ch) - '0')
-
-
-/* We use this code also for the extended locale handling where the
- function gets as an additional argument the locale which has to be
- used. To access the values we have to redefine the _NL_CURRENT
- macro. */
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# undef _NL_CURRENT
-# define _NL_CURRENT(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].string)
-#endif
-
-extern int __printf_fp (FILE *, const struct printf_info *,
- const void *const *);
-libc_hidden_proto (__printf_fp)
-/* This function determines the number of digit groups in the output.
- The definition is in printf_fp.c. */
-extern unsigned int __guess_grouping (unsigned int intdig_max,
- const char *grouping, wchar_t sepchar);
-
-
-/* We have to overcome some problems with this implementation. On the
- one hand the strfmon() function is specified in XPG4 and of course
- it has to follow this. But on the other hand POSIX.2 specifies
- some information in the LC_MONETARY category which should be used,
- too. Some of the information contradicts the information which can
- be specified in format string. */
-#ifndef USE_IN_EXTENDED_LOCALE_MODEL
ssize_t
strfmon (char *s, size_t maxsize, const char *format, ...)
-#else
-ssize_t
-__strfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format, ...)
-#endif
{
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
- struct locale_data *current = loc->__locales[LC_MONETARY];
-#endif
-#ifdef USE_IN_LIBIO
- _IO_strfile f;
-# ifdef _IO_MTSAFE_IO
- _IO_lock_t lock;
-# endif
-#else
- FILE f;
-#endif
- struct printf_info info;
- va_list ap; /* Scan through the varargs. */
- char *dest; /* Pointer so copy the output. */
- const char *fmt; /* Pointer that walks through format. */
+ va_list ap;
va_start (ap, format);
- dest = s;
- fmt = format;
-
- /* Loop through the format-string. */
- while (*fmt != '\0')
- {
- /* The floating-point value to output. */
- union
- {
- double dbl;
- __long_double_t ldbl;
- }
- fpnum;
- int int_format;
- int print_curr_symbol;
- int left_prec;
- int left_pad;
- int right_prec;
- int group;
- char pad;
- int is_long_double;
- int p_sign_posn;
- int n_sign_posn;
- int sign_posn;
- int other_sign_posn;
- int left;
- int is_negative;
- int sep_by_space;
- int other_sep_by_space;
- int cs_precedes;
- int other_cs_precedes;
- const char *sign_string;
- const char *other_sign_string;
- int done;
- const char *currency_symbol;
- size_t currency_symbol_len;
- int width;
- char *startp;
- const void *ptr;
- char space_char;
-
- /* Process all character which do not introduce a format
- specification. */
- if (*fmt != '%')
- {
- out_char (*fmt++);
- continue;
- }
-
- /* "%%" means a single '%' character. */
- if (fmt[1] == '%')
- {
- out_char (*++fmt);
- ++fmt;
- continue;
- }
-
- /* Defaults for formatting. */
- int_format = 0; /* Use international curr. symbol */
- print_curr_symbol = 1; /* Print the currency symbol. */
- left_prec = -1; /* No left precision specified. */
- right_prec = -1; /* No right precision specified. */
- group = 1; /* Print digits grouped. */
- pad = ' '; /* Fill character is <SP>. */
- is_long_double = 0; /* Double argument by default. */
- p_sign_posn = -1; /* This indicates whether the */
- n_sign_posn = -1; /* '(' flag is given. */
- width = -1; /* No width specified so far. */
- left = 0; /* Right justified by default. */
-
- /* Parse group characters. */
- while (1)
- {
- switch (*++fmt)
- {
- case '=': /* Set fill character. */
- pad = *++fmt;
- if (pad == '\0')
- {
- /* Premature EOS. */
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
- continue;
- case '^': /* Don't group digits. */
- group = 0;
- continue;
- case '+': /* Use +/- for sign of number. */
- if (n_sign_posn != -1)
- {
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
- p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
- n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
- continue;
- case '(': /* Use ( ) for negative sign. */
- if (n_sign_posn != -1)
- {
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
- p_sign_posn = 0;
- n_sign_posn = 0;
- continue;
- case '!': /* Don't print the currency symbol. */
- print_curr_symbol = 0;
- continue;
- case '-': /* Print left justified. */
- left = 1;
- continue;
- default:
- /* Will stop the loop. */;
- }
- break;
- }
-
- if (isdigit (*fmt))
- {
- /* Parse field width. */
- width = to_digit (*fmt);
-
- while (isdigit (*++fmt))
- {
- width *= 10;
- width += to_digit (*fmt);
- }
-
- /* If we don't have enough room for the demanded width we
- can stop now and return an error. */
- if (dest + width >= s + maxsize)
- {
- __set_errno (E2BIG);
- va_end (ap);
- return -1;
- }
- }
-
- /* Recognize left precision. */
- if (*fmt == '#')
- {
- if (!isdigit (*++fmt))
- {
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
- left_prec = to_digit (*fmt);
-
- while (isdigit (*++fmt))
- {
- left_prec *= 10;
- left_prec += to_digit (*fmt);
- }
- }
-
- /* Recognize right precision. */
- if (*fmt == '.')
- {
- if (!isdigit (*++fmt))
- {
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
- right_prec = to_digit (*fmt);
-
- while (isdigit (*++fmt))
- {
- right_prec *= 10;
- right_prec += to_digit (*fmt);
- }
- }
-
- /* Handle modifier. This is an extension. */
- if (*fmt == 'L')
- {
- ++fmt;
- is_long_double = 1;
- }
-
- /* Handle format specifier. */
- char int_symbol[4];
- switch (*fmt++)
- {
- case 'i': { /* Use international currency symbol. */
- const char *int_curr_symbol;
-
- int_curr_symbol = _NL_CURRENT (LC_MONETARY, INT_CURR_SYMBOL);
- strncpy(int_symbol, int_curr_symbol, 3);
- int_symbol[3] = '\0';
-
- currency_symbol_len = 3;
- currency_symbol = &int_symbol[0];
- space_char = int_curr_symbol[3];
- int_format = 1;
- break;
- }
- case 'n': /* Use national currency symbol. */
- currency_symbol = _NL_CURRENT (LC_MONETARY, CURRENCY_SYMBOL);
- currency_symbol_len = strlen (currency_symbol);
- space_char = ' ';
- int_format = 0;
- break;
- default: /* Any unrecognized format is an error. */
- __set_errno (EINVAL);
- va_end (ap);
- return -1;
- }
-
- /* If not specified by the format string now find the values for
- the format specification. */
- if (p_sign_posn == -1)
- p_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SIGN_POSN : P_SIGN_POSN);
- if (n_sign_posn == -1)
- n_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SIGN_POSN : N_SIGN_POSN);
-
- if (right_prec == -1)
- {
- right_prec = *_NL_CURRENT (LC_MONETARY, int_format ? INT_FRAC_DIGITS : FRAC_DIGITS);
-
- if (right_prec == CHAR_MAX)
- right_prec = 2;
- }
-
- /* If we have to print the digits grouped determine how many
- extra characters this means. */
- if (group && left_prec != -1)
- left_prec += __guess_grouping (left_prec,
- _NL_CURRENT (LC_MONETARY, MON_GROUPING),
- *_NL_CURRENT (LC_MONETARY,
- MON_THOUSANDS_SEP));
-
- /* Now it's time to get the value. */
- if (is_long_double == 1)
- {
- fpnum.ldbl = va_arg (ap, long double);
- is_negative = fpnum.ldbl < 0;
- if (is_negative)
- fpnum.ldbl = -fpnum.ldbl;
- }
- else
- {
- fpnum.dbl = va_arg (ap, double);
- is_negative = fpnum.dbl < 0;
- if (is_negative)
- fpnum.dbl = -fpnum.dbl;
- }
-
- /* We now know the sign of the value and can determine the format. */
- if (is_negative)
- {
- sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
- /* If the locale does not specify a character for the
- negative sign we use a '-'. */
- if (*sign_string == '\0')
- sign_string = (const char *) "-";
- cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
- sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
- sign_posn = n_sign_posn;
-
- other_sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
- other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
- other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
- other_sign_posn = p_sign_posn;
- }
- else
- {
- sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
- cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
- sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
- sign_posn = p_sign_posn;
-
- other_sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
- if (*other_sign_string == '\0')
- other_sign_string = (const char *) "-";
- other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
- other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
- other_sign_posn = n_sign_posn;
- }
-
- /* Set default values for unspecified information. */
- if (cs_precedes != 0)
- cs_precedes = 1;
- if (other_cs_precedes != 0)
- other_cs_precedes = 1;
- if (sep_by_space == CHAR_MAX)
- sep_by_space = 0;
- if (other_sep_by_space == CHAR_MAX)
- other_sep_by_space = 0;
- if (sign_posn == CHAR_MAX)
- sign_posn = 1;
- if (other_sign_posn == CHAR_MAX)
- other_sign_posn = 1;
-
- /* Check for degenerate cases */
- if (sep_by_space == 2)
- {
- if (sign_posn == 0 ||
- (sign_posn == 1 && !cs_precedes) ||
- (sign_posn == 2 && cs_precedes))
- /* sign and symbol are not adjacent, so no separator */
- sep_by_space = 0;
- }
- if (other_sep_by_space == 2)
- {
- if (other_sign_posn == 0 ||
- (other_sign_posn == 1 && !other_cs_precedes) ||
- (other_sign_posn == 2 && other_cs_precedes))
- /* sign and symbol are not adjacent, so no separator */
- other_sep_by_space = 0;
- }
-
- /* Set the left precision and padding needed for alignment */
- if (left_prec == -1)
- {
- left_prec = 0;
- left_pad = 0;
- }
- else
- {
- /* Set left_pad to number of spaces needed to align positive
- and negative formats */
-
- int left_bytes = 0;
- int other_left_bytes = 0;
-
- /* Work out number of bytes for currency string and separator
- preceding the value */
- if (cs_precedes)
- {
- left_bytes += currency_symbol_len;
- if (sep_by_space != 0)
- ++left_bytes;
- }
-
- if (other_cs_precedes)
- {
- other_left_bytes += currency_symbol_len;
- if (other_sep_by_space != 0)
- ++other_left_bytes;
- }
-
- /* Work out number of bytes for the sign (or left parenthesis)
- preceding the value */
- if (sign_posn == 0 && is_negative)
- ++left_bytes;
- else if (sign_posn == 1)
- left_bytes += strlen (sign_string);
- else if (cs_precedes && (sign_posn == 3 || sign_posn == 4))
- left_bytes += strlen (sign_string);
-
- if (other_sign_posn == 0 && !is_negative)
- ++other_left_bytes;
- else if (other_sign_posn == 1)
- other_left_bytes += strlen (other_sign_string);
- else if (other_cs_precedes &&
- (other_sign_posn == 3 || other_sign_posn == 4))
- other_left_bytes += strlen (other_sign_string);
-
- /* Compare the number of bytes preceding the value for
- each format, and set the padding accordingly */
- if (other_left_bytes > left_bytes)
- left_pad = other_left_bytes - left_bytes;
- else
- left_pad = 0;
- }
-
- /* Perhaps we'll someday make these things configurable so
- better start using symbolic names now. */
-#define left_paren '('
-#define right_paren ')'
-
- startp = dest; /* Remember start so we can compute length. */
-
- while (left_pad-- > 0)
- out_char (' ');
-
- if (sign_posn == 0 && is_negative)
- out_char (left_paren);
-
- if (cs_precedes)
- {
- if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
- && sign_posn != 5)
- {
- out_string (sign_string);
- if (sep_by_space == 2)
- out_char (' ');
- }
-
- if (print_curr_symbol)
- {
- out_string (currency_symbol);
-
- if (sign_posn == 4)
- {
- if (sep_by_space == 2)
- out_char (space_char);
- out_string (sign_string);
- if (sep_by_space == 1)
- /* POSIX.2 and SUS are not clear on this case, but C99
- says a space follows the adjacent-symbol-and-sign */
- out_char (' ');
- }
- else
- if (sep_by_space == 1)
- out_char (space_char);
- }
- }
- else
- if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
- && sign_posn != 4 && sign_posn != 5)
- out_string (sign_string);
-
- /* Print the number. */
-#ifdef USE_IN_LIBIO
-# ifdef _IO_MTSAFE_IO
- f._sbf._f._lock = &lock;
-# endif
- INTUSE(_IO_init) ((_IO_FILE *) &f, 0);
- _IO_JUMPS ((struct _IO_FILE_plus *) &f) = &_IO_str_jumps;
- INTUSE(_IO_str_init_static) ((_IO_strfile *) &f, dest,
- (s + maxsize) - dest, dest);
-#else
- memset ((void *) &f, 0, sizeof (f));
- f.__magic = _IOMAGIC;
- f.__mode.__write = 1;
- /* The buffer size is one less than MAXLEN
- so we have space for the null terminator. */
- f.__bufp = f.__buffer = (char *) dest;
- f.__bufsize = (s + maxsize) - dest;
- f.__put_limit = f.__buffer + f.__bufsize;
- f.__get_limit = f.__buffer;
- /* After the buffer is full (MAXLEN characters have been written),
- any more characters written will go to the bit bucket. */
- f.__room_funcs = __default_room_functions;
- f.__io_funcs.__write = NULL;
- f.__seen = 1;
-#endif
- /* We clear the last available byte so we can find out whether
- the numeric representation is too long. */
- s[maxsize - 1] = '\0';
-
- info.prec = right_prec;
- info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
- info.spec = 'f';
- info.is_long_double = is_long_double;
- info.is_short = 0;
- info.is_long = 0;
- info.alt = 0;
- info.space = 0;
- info.left = 0;
- info.showsign = 0;
- info.group = group;
- info.pad = pad;
- info.extra = 1; /* This means use values from LC_MONETARY. */
- info.wide = 0;
-
- ptr = &fpnum;
- done = __printf_fp ((FILE *) &f, &info, &ptr);
- if (done < 0)
- {
- va_end (ap);
- return -1;
- }
-
- if (s[maxsize - 1] != '\0')
- {
- __set_errno (E2BIG);
- return -1;
- }
-
- dest += done;
-
- if (!cs_precedes)
- {
- if (sign_posn == 3)
- {
- if (sep_by_space == 1)
- out_char (' ');
- out_string (sign_string);
- }
-
- if (print_curr_symbol)
- {
- if ((sign_posn == 3 && sep_by_space == 2)
- || (sign_posn == 4 && sep_by_space == 1)
- || (sign_posn == 2 && sep_by_space == 1)
- || (sign_posn == 1 && sep_by_space == 1)
- || (sign_posn == 0 && sep_by_space == 1))
- out_char (space_char);
- out_nstring (currency_symbol, currency_symbol_len);
- if (sign_posn == 4)
- {
- if (sep_by_space == 2)
- out_char (' ');
- out_string (sign_string);
- }
- }
- }
-
- if (sign_posn == 2)
- {
- if (sep_by_space == 2)
- out_char (' ');
- out_string (sign_string);
- }
-
- if (sign_posn == 0 && is_negative)
- out_char (right_paren);
-
- /* Now test whether the output width is filled. */
- if (dest - startp < width)
- {
- if (left)
- /* We simply have to fill using spaces. */
- do
- out_char (' ');
- while (dest - startp < width);
- else
- {
- int dist = width - (dest - startp);
- char *cp;
- for (cp = dest - 1; cp >= startp; --cp)
- cp[dist] = cp[0];
-
- dest += dist;
-
- do
- startp[--dist] = ' ';
- while (dist > 0);
- }
- }
- }
-
- /* Terminate the string. */
- *dest = '\0';
+ ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
va_end (ap);
- return dest - s;
+ return res;
}
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index b0c82a337e..90076afc45 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -1,5 +1,5 @@
/* Formatting a monetary value according to the given locale.
- Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -18,7 +18,637 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <strfmon.c>
+#include <ctype.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <monetary.h>
+#ifdef USE_IN_LIBIO
+# include "../libio/libioP.h"
+# include "../libio/strfile.h"
+#endif
+#include <printf.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "../locale/localeinfo.h"
+
+#define out_char(Ch) \
+ do { \
+ if (dest >= s + maxsize - 1) \
+ { \
+ __set_errno (E2BIG); \
+ va_end (ap); \
+ return -1; \
+ } \
+ *dest++ = (Ch); \
+ } while (0)
+
+#define out_string(String) \
+ do { \
+ const char *_s = (String); \
+ while (*_s) \
+ out_char (*_s++); \
+ } while (0)
+
+#define out_nstring(String, N) \
+ do { \
+ int _n = (N); \
+ const char *_s = (String); \
+ while (_n-- > 0) \
+ out_char (*_s++); \
+ } while (0)
+
+#define to_digit(Ch) ((Ch) - '0')
+
+
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+#undef _NL_CURRENT
+#define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+
+extern int __printf_fp (FILE *, const struct printf_info *,
+ const void *const *);
+libc_hidden_proto (__printf_fp)
+/* This function determines the number of digit groups in the output.
+ The definition is in printf_fp.c. */
+extern unsigned int __guess_grouping (unsigned int intdig_max,
+ const char *grouping, wchar_t sepchar);
+
+
+/* We have to overcome some problems with this implementation. On the
+ one hand the strfmon() function is specified in XPG4 and of course
+ it has to follow this. But on the other hand POSIX.2 specifies
+ some information in the LC_MONETARY category which should be used,
+ too. Some of the information contradicts the information which can
+ be specified in format string. */
+ssize_t
+__vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format,
+ va_list ap)
+{
+ struct locale_data *current = loc->__locales[LC_MONETARY];
+#ifdef USE_IN_LIBIO
+ _IO_strfile f;
+# ifdef _IO_MTSAFE_IO
+ _IO_lock_t lock;
+# endif
+#else
+ FILE f;
+#endif
+ struct printf_info info;
+ char *dest; /* Pointer so copy the output. */
+ const char *fmt; /* Pointer that walks through format. */
+
+ dest = s;
+ fmt = format;
+
+ /* Loop through the format-string. */
+ while (*fmt != '\0')
+ {
+ /* The floating-point value to output. */
+ union
+ {
+ double dbl;
+ __long_double_t ldbl;
+ }
+ fpnum;
+ int int_format;
+ int print_curr_symbol;
+ int left_prec;
+ int left_pad;
+ int right_prec;
+ int group;
+ char pad;
+ int is_long_double;
+ int p_sign_posn;
+ int n_sign_posn;
+ int sign_posn;
+ int other_sign_posn;
+ int left;
+ int is_negative;
+ int sep_by_space;
+ int other_sep_by_space;
+ int cs_precedes;
+ int other_cs_precedes;
+ const char *sign_string;
+ const char *other_sign_string;
+ int done;
+ const char *currency_symbol;
+ size_t currency_symbol_len;
+ int width;
+ char *startp;
+ const void *ptr;
+ char space_char;
+
+ /* Process all character which do not introduce a format
+ specification. */
+ if (*fmt != '%')
+ {
+ out_char (*fmt++);
+ continue;
+ }
+
+ /* "%%" means a single '%' character. */
+ if (fmt[1] == '%')
+ {
+ out_char (*++fmt);
+ ++fmt;
+ continue;
+ }
+
+ /* Defaults for formatting. */
+ int_format = 0; /* Use international curr. symbol */
+ print_curr_symbol = 1; /* Print the currency symbol. */
+ left_prec = -1; /* No left precision specified. */
+ right_prec = -1; /* No right precision specified. */
+ group = 1; /* Print digits grouped. */
+ pad = ' '; /* Fill character is <SP>. */
+ is_long_double = 0; /* Double argument by default. */
+ p_sign_posn = -1; /* This indicates whether the */
+ n_sign_posn = -1; /* '(' flag is given. */
+ width = -1; /* No width specified so far. */
+ left = 0; /* Right justified by default. */
+
+ /* Parse group characters. */
+ while (1)
+ {
+ switch (*++fmt)
+ {
+ case '=': /* Set fill character. */
+ pad = *++fmt;
+ if (pad == '\0')
+ {
+ /* Premature EOS. */
+ __set_errno (EINVAL);
+ return -1;
+ }
+ continue;
+ case '^': /* Don't group digits. */
+ group = 0;
+ continue;
+ case '+': /* Use +/- for sign of number. */
+ if (n_sign_posn != -1)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
+ n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
+ continue;
+ case '(': /* Use ( ) for negative sign. */
+ if (n_sign_posn != -1)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ p_sign_posn = 0;
+ n_sign_posn = 0;
+ continue;
+ case '!': /* Don't print the currency symbol. */
+ print_curr_symbol = 0;
+ continue;
+ case '-': /* Print left justified. */
+ left = 1;
+ continue;
+ default:
+ /* Will stop the loop. */;
+ }
+ break;
+ }
+
+ if (isdigit (*fmt))
+ {
+ /* Parse field width. */
+ width = to_digit (*fmt);
+
+ while (isdigit (*++fmt))
+ {
+ width *= 10;
+ width += to_digit (*fmt);
+ }
+
+ /* If we don't have enough room for the demanded width we
+ can stop now and return an error. */
+ if (dest + width >= s + maxsize)
+ {
+ __set_errno (E2BIG);
+ return -1;
+ }
+ }
+
+ /* Recognize left precision. */
+ if (*fmt == '#')
+ {
+ if (!isdigit (*++fmt))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ left_prec = to_digit (*fmt);
+
+ while (isdigit (*++fmt))
+ {
+ left_prec *= 10;
+ left_prec += to_digit (*fmt);
+ }
+ }
+
+ /* Recognize right precision. */
+ if (*fmt == '.')
+ {
+ if (!isdigit (*++fmt))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ right_prec = to_digit (*fmt);
+
+ while (isdigit (*++fmt))
+ {
+ right_prec *= 10;
+ right_prec += to_digit (*fmt);
+ }
+ }
+
+ /* Handle modifier. This is an extension. */
+ if (*fmt == 'L')
+ {
+ ++fmt;
+ is_long_double = 1;
+ }
+
+ /* Handle format specifier. */
+ char int_symbol[4];
+ switch (*fmt++)
+ {
+ case 'i': { /* Use international currency symbol. */
+ const char *int_curr_symbol;
+
+ int_curr_symbol = _NL_CURRENT (LC_MONETARY, INT_CURR_SYMBOL);
+ strncpy(int_symbol, int_curr_symbol, 3);
+ int_symbol[3] = '\0';
+
+ currency_symbol_len = 3;
+ currency_symbol = &int_symbol[0];
+ space_char = int_curr_symbol[3];
+ int_format = 1;
+ break;
+ }
+ case 'n': /* Use national currency symbol. */
+ currency_symbol = _NL_CURRENT (LC_MONETARY, CURRENCY_SYMBOL);
+ currency_symbol_len = strlen (currency_symbol);
+ space_char = ' ';
+ int_format = 0;
+ break;
+ default: /* Any unrecognized format is an error. */
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* If not specified by the format string now find the values for
+ the format specification. */
+ if (p_sign_posn == -1)
+ p_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SIGN_POSN : P_SIGN_POSN);
+ if (n_sign_posn == -1)
+ n_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SIGN_POSN : N_SIGN_POSN);
+
+ if (right_prec == -1)
+ {
+ right_prec = *_NL_CURRENT (LC_MONETARY, int_format ? INT_FRAC_DIGITS : FRAC_DIGITS);
+
+ if (right_prec == CHAR_MAX)
+ right_prec = 2;
+ }
+
+ /* If we have to print the digits grouped determine how many
+ extra characters this means. */
+ if (group && left_prec != -1)
+ left_prec += __guess_grouping (left_prec,
+ _NL_CURRENT (LC_MONETARY, MON_GROUPING),
+ *_NL_CURRENT (LC_MONETARY,
+ MON_THOUSANDS_SEP));
+
+ /* Now it's time to get the value. */
+ if (is_long_double == 1)
+ {
+ fpnum.ldbl = va_arg (ap, long double);
+ is_negative = fpnum.ldbl < 0;
+ if (is_negative)
+ fpnum.ldbl = -fpnum.ldbl;
+ }
+ else
+ {
+ fpnum.dbl = va_arg (ap, double);
+ is_negative = fpnum.dbl < 0;
+ if (is_negative)
+ fpnum.dbl = -fpnum.dbl;
+ }
+
+ /* We now know the sign of the value and can determine the format. */
+ if (is_negative)
+ {
+ sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
+ /* If the locale does not specify a character for the
+ negative sign we use a '-'. */
+ if (*sign_string == '\0')
+ sign_string = (const char *) "-";
+ cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
+ sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
+ sign_posn = n_sign_posn;
+
+ other_sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
+ other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
+ other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
+ other_sign_posn = p_sign_posn;
+ }
+ else
+ {
+ sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
+ cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
+ sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
+ sign_posn = p_sign_posn;
+
+ other_sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
+ if (*other_sign_string == '\0')
+ other_sign_string = (const char *) "-";
+ other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
+ other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
+ other_sign_posn = n_sign_posn;
+ }
+
+ /* Set default values for unspecified information. */
+ if (cs_precedes != 0)
+ cs_precedes = 1;
+ if (other_cs_precedes != 0)
+ other_cs_precedes = 1;
+ if (sep_by_space == CHAR_MAX)
+ sep_by_space = 0;
+ if (other_sep_by_space == CHAR_MAX)
+ other_sep_by_space = 0;
+ if (sign_posn == CHAR_MAX)
+ sign_posn = 1;
+ if (other_sign_posn == CHAR_MAX)
+ other_sign_posn = 1;
+
+ /* Check for degenerate cases */
+ if (sep_by_space == 2)
+ {
+ if (sign_posn == 0 ||
+ (sign_posn == 1 && !cs_precedes) ||
+ (sign_posn == 2 && cs_precedes))
+ /* sign and symbol are not adjacent, so no separator */
+ sep_by_space = 0;
+ }
+ if (other_sep_by_space == 2)
+ {
+ if (other_sign_posn == 0 ||
+ (other_sign_posn == 1 && !other_cs_precedes) ||
+ (other_sign_posn == 2 && other_cs_precedes))
+ /* sign and symbol are not adjacent, so no separator */
+ other_sep_by_space = 0;
+ }
+
+ /* Set the left precision and padding needed for alignment */
+ if (left_prec == -1)
+ {
+ left_prec = 0;
+ left_pad = 0;
+ }
+ else
+ {
+ /* Set left_pad to number of spaces needed to align positive
+ and negative formats */
+
+ int left_bytes = 0;
+ int other_left_bytes = 0;
+
+ /* Work out number of bytes for currency string and separator
+ preceding the value */
+ if (cs_precedes)
+ {
+ left_bytes += currency_symbol_len;
+ if (sep_by_space != 0)
+ ++left_bytes;
+ }
+
+ if (other_cs_precedes)
+ {
+ other_left_bytes += currency_symbol_len;
+ if (other_sep_by_space != 0)
+ ++other_left_bytes;
+ }
+
+ /* Work out number of bytes for the sign (or left parenthesis)
+ preceding the value */
+ if (sign_posn == 0 && is_negative)
+ ++left_bytes;
+ else if (sign_posn == 1)
+ left_bytes += strlen (sign_string);
+ else if (cs_precedes && (sign_posn == 3 || sign_posn == 4))
+ left_bytes += strlen (sign_string);
+
+ if (other_sign_posn == 0 && !is_negative)
+ ++other_left_bytes;
+ else if (other_sign_posn == 1)
+ other_left_bytes += strlen (other_sign_string);
+ else if (other_cs_precedes &&
+ (other_sign_posn == 3 || other_sign_posn == 4))
+ other_left_bytes += strlen (other_sign_string);
+
+ /* Compare the number of bytes preceding the value for
+ each format, and set the padding accordingly */
+ if (other_left_bytes > left_bytes)
+ left_pad = other_left_bytes - left_bytes;
+ else
+ left_pad = 0;
+ }
+
+ /* Perhaps we'll someday make these things configurable so
+ better start using symbolic names now. */
+#define left_paren '('
+#define right_paren ')'
+
+ startp = dest; /* Remember start so we can compute length. */
+
+ while (left_pad-- > 0)
+ out_char (' ');
+
+ if (sign_posn == 0 && is_negative)
+ out_char (left_paren);
+
+ if (cs_precedes)
+ {
+ if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
+ && sign_posn != 5)
+ {
+ out_string (sign_string);
+ if (sep_by_space == 2)
+ out_char (' ');
+ }
+
+ if (print_curr_symbol)
+ {
+ out_string (currency_symbol);
+
+ if (sign_posn == 4)
+ {
+ if (sep_by_space == 2)
+ out_char (space_char);
+ out_string (sign_string);
+ if (sep_by_space == 1)
+ /* POSIX.2 and SUS are not clear on this case, but C99
+ says a space follows the adjacent-symbol-and-sign */
+ out_char (' ');
+ }
+ else
+ if (sep_by_space == 1)
+ out_char (space_char);
+ }
+ }
+ else
+ if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
+ && sign_posn != 4 && sign_posn != 5)
+ out_string (sign_string);
+
+ /* Print the number. */
+#ifdef USE_IN_LIBIO
+# ifdef _IO_MTSAFE_IO
+ f._sbf._f._lock = &lock;
+# endif
+ INTUSE(_IO_init) ((_IO_FILE *) &f, 0);
+ _IO_JUMPS ((struct _IO_FILE_plus *) &f) = &_IO_str_jumps;
+ INTUSE(_IO_str_init_static) ((_IO_strfile *) &f, dest,
+ (s + maxsize) - dest, dest);
+#else
+ memset ((void *) &f, 0, sizeof (f));
+ f.__magic = _IOMAGIC;
+ f.__mode.__write = 1;
+ /* The buffer size is one less than MAXLEN
+ so we have space for the null terminator. */
+ f.__bufp = f.__buffer = (char *) dest;
+ f.__bufsize = (s + maxsize) - dest;
+ f.__put_limit = f.__buffer + f.__bufsize;
+ f.__get_limit = f.__buffer;
+ /* After the buffer is full (MAXLEN characters have been written),
+ any more characters written will go to the bit bucket. */
+ f.__room_funcs = __default_room_functions;
+ f.__io_funcs.__write = NULL;
+ f.__seen = 1;
+#endif
+ /* We clear the last available byte so we can find out whether
+ the numeric representation is too long. */
+ s[maxsize - 1] = '\0';
+
+ info.prec = right_prec;
+ info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
+ info.spec = 'f';
+ info.is_long_double = is_long_double;
+ info.is_short = 0;
+ info.is_long = 0;
+ info.alt = 0;
+ info.space = 0;
+ info.left = 0;
+ info.showsign = 0;
+ info.group = group;
+ info.pad = pad;
+ info.extra = 1; /* This means use values from LC_MONETARY. */
+ info.wide = 0;
+
+ ptr = &fpnum;
+ done = __printf_fp ((FILE *) &f, &info, &ptr);
+ if (done < 0)
+ return -1;
+
+ if (s[maxsize - 1] != '\0')
+ {
+ __set_errno (E2BIG);
+ return -1;
+ }
+
+ dest += done;
+
+ if (!cs_precedes)
+ {
+ if (sign_posn == 3)
+ {
+ if (sep_by_space == 1)
+ out_char (' ');
+ out_string (sign_string);
+ }
+
+ if (print_curr_symbol)
+ {
+ if ((sign_posn == 3 && sep_by_space == 2)
+ || (sign_posn == 4 && sep_by_space == 1)
+ || (sign_posn == 2 && sep_by_space == 1)
+ || (sign_posn == 1 && sep_by_space == 1)
+ || (sign_posn == 0 && sep_by_space == 1))
+ out_char (space_char);
+ out_nstring (currency_symbol, currency_symbol_len);
+ if (sign_posn == 4)
+ {
+ if (sep_by_space == 2)
+ out_char (' ');
+ out_string (sign_string);
+ }
+ }
+ }
+
+ if (sign_posn == 2)
+ {
+ if (sep_by_space == 2)
+ out_char (' ');
+ out_string (sign_string);
+ }
+
+ if (sign_posn == 0 && is_negative)
+ out_char (right_paren);
+
+ /* Now test whether the output width is filled. */
+ if (dest - startp < width)
+ {
+ if (left)
+ /* We simply have to fill using spaces. */
+ do
+ out_char (' ');
+ while (dest - startp < width);
+ else
+ {
+ int dist = width - (dest - startp);
+ char *cp;
+ for (cp = dest - 1; cp >= startp; --cp)
+ cp[dist] = cp[0];
+
+ dest += dist;
+
+ do
+ startp[--dist] = ' ';
+ while (dist > 0);
+ }
+ }
+ }
+
+ /* Terminate the string. */
+ *dest = '\0';
+
+ return dest - s;
+}
+
+ssize_t
+__strfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+
+ ssize_t res = __vstrfmon_l (s, maxsize, loc, format, ap);
+
+ va_end (ap);
+
+ return res;
+}
weak_alias (__strfmon_l, strfmon_l)
diff --git a/stdlib/strtod.c b/stdlib/strtod.c
index 63d7a4d5bb..1d4e4a4c29 100644
--- a/stdlib/strtod.c
+++ b/stdlib/strtod.c
@@ -1,6 +1,6 @@
/* Read decimal floating point numbers.
This file is part of the GNU C Library.
- Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002, 2003, 2004 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
@@ -18,1579 +18,53 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-/* Configuration part. These macros are defined by `strtold.c',
- `strtof.c', `wcstod.c', `wcstold.c', and `wcstof.c' to produce the
- `long double' and `float' versions of the reader. */
+#include <stdlib.h>
+#include <wchar.h>
+#include <locale/localeinfo.h>
+
+
#ifndef FLOAT
-# define FLOAT double
-# define FLT DBL
+# define FLOAT double
# ifdef USE_WIDE_CHAR
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __wcstod_l
-# else
-# define STRTOF wcstod
-# endif
+# define STRTOF wcstod
+# define STRTOF_L __wcstod_l
# else
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __strtod_l
-# else
-# define STRTOF strtod
-# endif
+# define STRTOF strtod
+# define STRTOF_L __strtod_l
# endif
-# define MPN2FLOAT __mpn_construct_double
-# define FLOAT_HUGE_VAL HUGE_VAL
-# define SET_MANTISSA(flt, mant) \
- do { union ieee754_double u; \
- u.d = (flt); \
- if ((mant & 0xfffffffffffffULL) == 0) \
- mant = 0x8000000000000ULL; \
- u.ieee.mantissa0 = ((mant) >> 32) & 0xfffff; \
- u.ieee.mantissa1 = (mant) & 0xffffffff; \
- (flt) = u.d; \
- } while (0)
-#endif
-/* End of configuration part. */
-
-#include <ctype.h>
-#include <errno.h>
-#include <float.h>
-#include <ieee754.h>
-#include "../locale/localeinfo.h"
-#include <locale.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* The gmp headers need some configuration frobs. */
-#define HAVE_ALLOCA 1
-
-/* Include gmp-mparam.h first, such that definitions of _SHORT_LIMB
- 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 "fpioconst.h"
-
-#define NDEBUG 1
-#include <assert.h>
-
-
-/* We use this code also for the extended locale handling where the
- function gets as an additional argument the locale which has to be
- used. To access the values we have to redefine the _NL_CURRENT
- macro. */
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# undef _NL_CURRENT
-# define _NL_CURRENT(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].string)
-# define LOCALE_PARAM , loc
-# define LOCALE_PARAM_DECL __locale_t loc;
-#else
-# define LOCALE_PARAM
-# define LOCALE_PARAM_DECL
-#endif
-
-#if defined _LIBC || defined HAVE_WCHAR_H
-# include <wchar.h>
#endif
#ifdef USE_WIDE_CHAR
# include <wctype.h>
# define STRING_TYPE wchar_t
-# define CHAR_TYPE wint_t
-# define L_(Ch) L##Ch
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
-# 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 STRTOULL(S, E, B) ____wcstoull_l_internal ((S), (E), (B), 0, loc)
-# else
-# define ISSPACE(Ch) iswspace (Ch)
-# define ISDIGIT(Ch) iswdigit (Ch)
-# define ISXDIGIT(Ch) iswxdigit (Ch)
-# define TOLOWER(Ch) towlower (Ch)
-# define STRNCASECMP(S1, S2, N) __wcsncasecmp ((S1), (S2), (N))
-# define STRTOULL(S, E, B) __wcstoull_internal ((S), (E), (B), 0)
-# endif
#else
# define STRING_TYPE char
-# define CHAR_TYPE char
-# define L_(Ch) Ch
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define ISSPACE(Ch) __isspace_l ((Ch), loc)
-# 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 STRTOULL(S, E, B) ____strtoull_l_internal ((S), (E), (B), 0, loc)
-# else
-# define ISSPACE(Ch) isspace (Ch)
-# define ISDIGIT(Ch) isdigit (Ch)
-# define ISXDIGIT(Ch) isxdigit (Ch)
-# define TOLOWER(Ch) tolower (Ch)
-# define STRNCASECMP(S1, S2, N) __strncasecmp ((S1), (S2), (N))
-# define STRTOULL(S, E, B) __strtoull_internal ((S), (E), 0, (B))
-# endif
-#endif
-
-
-/* Constants we need from float.h; select the set for the FLOAT precision. */
-#define MANT_DIG PASTE(FLT,_MANT_DIG)
-#define DIG PASTE(FLT,_DIG)
-#define MAX_EXP PASTE(FLT,_MAX_EXP)
-#define MIN_EXP PASTE(FLT,_MIN_EXP)
-#define MAX_10_EXP PASTE(FLT,_MAX_10_EXP)
-#define MIN_10_EXP PASTE(FLT,_MIN_10_EXP)
-
-/* Extra macros required to get FLT expanded before the pasting. */
-#define PASTE(a,b) PASTE1(a,b)
-#define PASTE1(a,b) a##b
-
-/* Function to construct a floating point number from an MP integer
- containing the fraction bits, a base 2 exponent, and a sign flag. */
-extern FLOAT MPN2FLOAT (mp_srcptr mpn, int exponent, int negative);
-
-/* Definitions according to limb size used. */
-#if BITS_PER_MP_LIMB == 32
-# define MAX_DIG_PER_LIMB 9
-# define MAX_FAC_PER_LIMB 1000000000UL
-#elif BITS_PER_MP_LIMB == 64
-# define MAX_DIG_PER_LIMB 19
-# define MAX_FAC_PER_LIMB 10000000000000000000ULL
-#else
-# error "mp_limb_t size " BITS_PER_MP_LIMB "not accounted for"
#endif
-
-/* Local data structure. */
-static const mp_limb_t _tens_in_limb[MAX_DIG_PER_LIMB + 1] =
-{ 0, 10, 100,
- 1000, 10000, 100000L,
- 1000000L, 10000000L, 100000000L,
- 1000000000L
-#if BITS_PER_MP_LIMB > 32
- , 10000000000ULL, 100000000000ULL,
- 1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
- 1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL,
- 1000000000000000000ULL, 10000000000000000000ULL
-#endif
-#if BITS_PER_MP_LIMB > 64
- #error "Need to expand tens_in_limb table to" MAX_DIG_PER_LIMB
-#endif
-};
-
-#ifndef howmany
-#define howmany(x,y) (((x)+((y)-1))/(y))
-#endif
-#define SWAP(x, y) ({ typeof(x) _tmp = x; x = y; y = _tmp; })
-
-#define NDIG (MAX_10_EXP - MIN_10_EXP + 2 * MANT_DIG)
-#define HEXNDIG ((MAX_EXP - MIN_EXP + 7) / 8 + 2 * MANT_DIG)
-#define RETURN_LIMB_SIZE howmany (MANT_DIG, BITS_PER_MP_LIMB)
-
-#define RETURN(val,end) \
- do { if (endptr != NULL) *endptr = (STRING_TYPE *) (end); \
- return val; } while (0)
-
-/* Maximum size necessary for mpn integers to hold floating point numbers. */
-#define MPNSIZE (howmany (MAX_EXP + 2 * MANT_DIG, BITS_PER_MP_LIMB) \
- + 2)
-/* Declare an mpn integer variable that big. */
-#define MPN_VAR(name) mp_limb_t name[MPNSIZE]; mp_size_t name##size
-/* Copy an mpn integer value. */
-#define MPN_ASSIGN(dst, src) \
- memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb_t))
-
-
-/* Return a floating point number of the needed type according to the given
- multi-precision number after possible rounding. */
-static FLOAT
-round_and_return (mp_limb_t *retval, int exponent, int negative,
- mp_limb_t round_limb, mp_size_t round_bit, int more_bits)
-{
- if (exponent < MIN_EXP - 1)
- {
- mp_size_t shift = MIN_EXP - 1 - exponent;
-
- if (shift > MANT_DIG)
- {
- __set_errno (EDOM);
- return 0.0;
- }
-
- more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
- if (shift == MANT_DIG)
- /* This is a special case to handle the very seldom case where
- the mantissa will be empty after the shift. */
- {
- int i;
-
- round_limb = retval[RETURN_LIMB_SIZE - 1];
- round_bit = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
- for (i = 0; i < RETURN_LIMB_SIZE; ++i)
- more_bits |= retval[i] != 0;
- MPN_ZERO (retval, RETURN_LIMB_SIZE);
- }
- else if (shift >= BITS_PER_MP_LIMB)
- {
- int i;
-
- round_limb = retval[(shift - 1) / BITS_PER_MP_LIMB];
- round_bit = (shift - 1) % BITS_PER_MP_LIMB;
- for (i = 0; i < (shift - 1) / BITS_PER_MP_LIMB; ++i)
- more_bits |= retval[i] != 0;
- more_bits |= ((round_limb & ((((mp_limb_t) 1) << round_bit) - 1))
- != 0);
-
- (void) __mpn_rshift (retval, &retval[shift / BITS_PER_MP_LIMB],
- RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB),
- shift % BITS_PER_MP_LIMB);
- MPN_ZERO (&retval[RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB)],
- shift / BITS_PER_MP_LIMB);
- }
- else if (shift > 0)
- {
- round_limb = retval[0];
- round_bit = shift - 1;
- (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
- }
- /* This is a hook for the m68k long double format, where the
- exponent bias is the same for normalized and denormalized
- numbers. */
-#ifndef DENORM_EXP
-# define DENORM_EXP (MIN_EXP - 2)
-#endif
- exponent = DENORM_EXP;
- }
-
- if ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
- && (more_bits || (retval[0] & 1) != 0
- || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
- {
- mp_limb_t cy = __mpn_add_1 (retval, retval, RETURN_LIMB_SIZE, 1);
-
- if (((MANT_DIG % BITS_PER_MP_LIMB) == 0 && cy) ||
- ((MANT_DIG % BITS_PER_MP_LIMB) != 0 &&
- (retval[RETURN_LIMB_SIZE - 1]
- & (((mp_limb_t) 1) << (MANT_DIG % BITS_PER_MP_LIMB))) != 0))
- {
- ++exponent;
- (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, 1);
- retval[RETURN_LIMB_SIZE - 1]
- |= ((mp_limb_t) 1) << ((MANT_DIG - 1) % BITS_PER_MP_LIMB);
- }
- else if (exponent == DENORM_EXP
- && (retval[RETURN_LIMB_SIZE - 1]
- & (((mp_limb_t) 1) << ((MANT_DIG - 1) % BITS_PER_MP_LIMB)))
- != 0)
- /* The number was denormalized but now normalized. */
- exponent = MIN_EXP - 1;
- }
-
- if (exponent > MAX_EXP)
- return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
-
- return MPN2FLOAT (retval, exponent, negative);
-}
-
-
-/* Read a multi-precision integer starting at STR with exactly DIGCNT digits
- into N. Return the size of the number limbs in NSIZE at the first
- character od the string that is not part of the integer as the function
- value. If the EXPONENT is small enough to be taken as an additional
- factor for the resulting number (see code) multiply by it. */
-static const STRING_TYPE *
-str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize,
- 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;
- mp_limb_t low = 0;
- mp_limb_t start;
-
- *nsize = 0;
- assert (digcnt > 0);
- do
- {
- if (cnt == MAX_DIG_PER_LIMB)
- {
- if (*nsize == 0)
- {
- n[0] = low;
- *nsize = 1;
- }
- else
- {
- mp_limb_t cy;
- cy = __mpn_mul_1 (n, n, *nsize, MAX_FAC_PER_LIMB);
- cy += __mpn_add_1 (n, n, *nsize, low);
- if (cy != 0)
- {
- n[*nsize] = cy;
- ++(*nsize);
- }
- }
- cnt = 0;
- low = 0;
- }
-
- /* There might be thousands separators or radix characters in
- 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. */
-#ifdef USE_WIDE_CHAR
- if (*str < L'0' || *str > L'9')
- ++str;
-#else
- if (*str < '0' || *str > '9')
- {
- int inner = 0;
- if (thousands != NULL && *str == *thousands
- && ({ for (inner = 1; thousands[inner] != '\0'; ++inner)
- if (thousands[inner] != str[inner])
- break;
- thousands[inner] == '\0'; }))
- str += inner;
- else
- str += decimal_len;
- }
-#endif
- low = low * 10 + *str++ - L_('0');
- ++cnt;
- }
- while (--digcnt > 0);
-
- if (*exponent > 0 && cnt + *exponent <= MAX_DIG_PER_LIMB)
- {
- low *= _tens_in_limb[*exponent];
- start = _tens_in_limb[cnt + *exponent];
- *exponent = 0;
- }
- else
- start = _tens_in_limb[cnt];
-
- if (*nsize == 0)
- {
- n[0] = low;
- *nsize = 1;
- }
- else
- {
- mp_limb_t cy;
- cy = __mpn_mul_1 (n, n, *nsize, start);
- cy += __mpn_add_1 (n, n, *nsize, low);
- if (cy != 0)
- n[(*nsize)++] = cy;
- }
-
- return str;
-}
-
-
-/* Shift {PTR, SIZE} COUNT bits to the left, and fill the vacated bits
- with the COUNT most significant bits of LIMB.
-
- Tege doesn't like this function so I have to write it here myself. :)
- --drepper */
-static inline void
-__attribute ((always_inline))
-__mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count,
- mp_limb_t limb)
-{
- if (__builtin_constant_p (count) && count == BITS_PER_MP_LIMB)
- {
- /* Optimize the case of shifting by exactly a word:
- just copy words, with no actual bit-shifting. */
- mp_size_t i;
- for (i = size - 1; i > 0; --i)
- ptr[i] = ptr[i - 1];
- ptr[0] = limb;
- }
- else
- {
- (void) __mpn_lshift (ptr, ptr, size, count);
- ptr[0] |= limb >> (BITS_PER_MP_LIMB - count);
- }
-}
-
-
#define INTERNAL(x) INTERNAL1(x)
#define INTERNAL1(x) __##x##_internal
-/* This file defines a function to check for correct grouping. */
-#include "grouping.h"
-
-/* Return a floating point number with the value of the given string NPTR.
- Set *ENDPTR to the character after the last used one. If the number is
- smaller than the smallest representable number, set `errno' to ERANGE and
- 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 LOCALE_PARAM)
+INTERNAL (STRTOF) (nptr, endptr, group)
const STRING_TYPE *nptr;
STRING_TYPE **endptr;
int group;
- LOCALE_PARAM_DECL
{
- int negative; /* The sign of the number. */
- MPN_VAR (num); /* MP representation of the number. */
- int exponent; /* Exponent of the number. */
-
- /* Numbers starting `0X' or `0x' have to be processed with base 16. */
- int base = 10;
-
- /* When we have to compute fractional digits we form a fraction with a
- second multi-precision number (and we sometimes need a second for
- temporary results). */
- MPN_VAR (den);
-
- /* Representation for the return value. */
- mp_limb_t retval[RETURN_LIMB_SIZE];
- /* Number of bits currently in result value. */
- int bits;
-
- /* Running pointer after the last character processed in the string. */
- const STRING_TYPE *cp, *tp;
- /* Start of significant part of the number. */
- const STRING_TYPE *startp, *start_of_digits;
- /* Points at the character following the integer and fractional digits. */
- const STRING_TYPE *expp;
- /* Total number of digit and number of digits in integer part. */
- int dig_no, int_no, lead_zero;
- /* Contains the last character read. */
- CHAR_TYPE c;
-
-/* We should get wint_t from <stddef.h>, but not all GCC versions define it
- there. So define it ourselves if it remains undefined. */
-#ifndef _WINT_T
- 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];
-#endif
-
- if (group)
- {
- grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
- if (*grouping <= 0 || *grouping == CHAR_MAX)
- grouping = NULL;
- else
- {
- /* Figure out the thousands separator character. */
-#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. */
-#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;
- negative = 0;
- bits = 0;
-
- /* Parse string to get maximal legal prefix. We need the number of
- characters of the integer part, the fractional part and the exponent. */
- cp = nptr - 1;
- /* Ignore leading white space. */
- do
- c = *++cp;
- while (ISSPACE (c));
-
- /* Get sign of the result. */
- if (c == L_('-'))
- {
- negative = 1;
- c = *++cp;
- }
- else if (c == L_('+'))
- c = *++cp;
-
- /* Return 0.0 if no legal string is found.
- No character is used even if a sign was found. */
-#ifdef USE_WIDE_CHAR
- if (c == (wint_t) decimal
- && (wint_t) cp[1] >= L'0' && (wint_t) 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[cnt] >= '0' && cp[cnt] <= '9')
- {
- /* We accept it. This funny construct is here only to indent
- the code directly. */
- }
-#endif
- else if (c < L_('0') || c > L_('9'))
- {
- /* Check for `INF' or `INFINITY'. */
- if (TOLOWER (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
- {
- /* Return +/- infinity. */
- if (endptr != NULL)
- *endptr = (STRING_TYPE *)
- (cp + (STRNCASECMP (cp + 3, L_("inity"), 5) == 0
- ? 8 : 3));
-
- return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
- }
-
- if (TOLOWER (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
- {
- /* Return NaN. */
- FLOAT retval = NAN;
-
- cp += 3;
-
- /* Match `(n-char-sequence-digit)'. */
- if (*cp == L_('('))
- {
- const STRING_TYPE *startp = cp;
- do
- ++cp;
- while ((*cp >= L_('0') && *cp <= L_('9'))
- || (TOLOWER (*cp) >= L_('a') && TOLOWER (*cp) <= L_('z'))
- || *cp == L_('_'));
-
- if (*cp != L_(')'))
- /* The closing brace is missing. Only match the NAN
- part. */
- cp = startp;
- else
- {
- /* This is a system-dependent way to specify the
- bitmask used for the NaN. We expect it to be
- a number which is put in the mantissa of the
- number. */
- STRING_TYPE *endp;
- unsigned long long int mant;
-
- mant = STRTOULL (startp + 1, &endp, 0);
- if (endp == cp)
- SET_MANTISSA (retval, mant);
- }
- }
-
- if (endptr != NULL)
- *endptr = (STRING_TYPE *) cp;
-
- return retval;
- }
-
- /* It is really a text we do not recognize. */
- RETURN (0.0, nptr);
- }
-
- /* First look whether we are faced with a hexadecimal number. */
- if (c == L_('0') && TOLOWER (cp[1]) == L_('x'))
- {
- /* Okay, it is a hexa-decimal number. Remember this and skip
- the characters. BTW: hexadecimal numbers must not be
- grouped. */
- base = 16;
- cp += 2;
- c = *cp;
- grouping = NULL;
- }
-
- /* Record the start of the digits, in case we will check their grouping. */
- start_of_digits = startp = cp;
-
- /* Ignore leading zeroes. This helps us to avoid useless computations. */
-#ifdef USE_WIDE_CHAR
- while (c == L'0' || ((wint_t) thousands != L'\0' && c == (wint_t) 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 < (CHAR_TYPE) TOLOWER (L_('a'))
- || c > (CHAR_TYPE) TOLOWER (L_('f'))))
-#ifdef USE_WIDE_CHAR
- && c != (wint_t) 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
- || (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,
- grouping);
-#else
- tp = __correctly_grouped_prefixmb (start_of_digits, cp, thousands,
- grouping);
-#endif
- /* If TP is at the start of the digits, there was no correctly
- grouped prefix of the string; so no number found. */
- RETURN (0.0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
- }
-
- /* Remember first significant digit and read following characters until the
- decimal point, exponent character or any non-FP number character. */
- startp = cp;
- dig_no = 0;
- while (1)
- {
- if ((c >= L_('0') && c <= L_('9'))
- || (base == 16 && (wint_t) TOLOWER (c) >= L_('a')
- && (wint_t) TOLOWER (c) <= L_('f')))
- ++dig_no;
- else
- {
-#ifdef USE_WIDE_CHAR
- if ((wint_t) thousands == L'\0' || c != (wint_t) 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;
- }
-
- if (grouping && dig_no > 0)
- {
- /* Check the grouping of the digits. */
-#ifdef USE_WIDE_CHAR
- tp = __correctly_grouped_prefixwc (start_of_digits, cp, thousands,
- grouping);
-#else
- tp = __correctly_grouped_prefixmb (start_of_digits, cp, thousands,
- grouping);
-#endif
- if (cp != tp)
- {
- /* Less than the entire string was correctly grouped. */
-
- if (tp == start_of_digits)
- /* No valid group of numbers at all: no valid number. */
- RETURN (0.0, nptr);
-
- if (tp < startp)
- /* The number is validly grouped, but consists
- only of zeroes. The whole value is zero. */
- RETURN (0.0, tp);
-
- /* Recompute DIG_NO so we won't read more digits than
- are properly grouped. */
- cp = tp;
- dig_no = 0;
- for (tp = startp; tp < cp; ++tp)
- if (*tp >= L_('0') && *tp <= L_('9'))
- ++dig_no;
-
- int_no = dig_no;
- lead_zero = 0;
-
- goto number_parsed;
- }
- }
-
- /* We have the number 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. */
- if (
-#ifdef USE_WIDE_CHAR
- c == (wint_t) decimal
-#else
- ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
- if (decimal[cnt] != cp[cnt])
- break;
- decimal[cnt] == '\0'; })
-#endif
- )
- {
- cp += decimal_len;
- c = *cp;
- while ((c >= L_('0') && c <= L_('9')) ||
- (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
- {
- if (c != L_('0') && lead_zero == -1)
- lead_zero = dig_no - int_no;
- ++dig_no;
- c = *++cp;
- }
- }
-
- /* Remember start of exponent (if any). */
- expp = cp;
-
- /* Read exponent. */
- if ((base == 16 && TOLOWER (c) == L_('p'))
- || (base != 16 && TOLOWER (c) == L_('e')))
- {
- int exp_negative = 0;
-
- c = *++cp;
- if (c == L_('-'))
- {
- exp_negative = 1;
- c = *++cp;
- }
- else if (c == L_('+'))
- c = *++cp;
-
- if (c >= L_('0') && c <= L_('9'))
- {
- int exp_limit;
-
- /* Get the exponent limit. */
- if (base == 16)
- exp_limit = (exp_negative ?
- -MIN_EXP + MANT_DIG + 4 * int_no :
- MAX_EXP - 4 * int_no + lead_zero);
- else
- exp_limit = (exp_negative ?
- -MIN_10_EXP + MANT_DIG + int_no :
- MAX_10_EXP - int_no + lead_zero);
-
- do
- {
- exponent *= 10;
-
- if (exponent > exp_limit)
- /* The exponent is too large/small to represent a valid
- number. */
- {
- FLOAT result;
-
- /* We have to take care for special situation: a joker
- might have written "0.0e100000" which is in fact
- zero. */
- if (lead_zero == -1)
- result = negative ? -0.0 : 0.0;
- else
- {
- /* Overflow or underflow. */
- __set_errno (ERANGE);
- result = (exp_negative ? 0.0 :
- negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL);
- }
-
- /* Accept all following digits as part of the exponent. */
- do
- ++cp;
- while (*cp >= L_('0') && *cp <= L_('9'));
-
- RETURN (result, cp);
- /* NOTREACHED */
- }
-
- exponent += c - L_('0');
- c = *++cp;
- }
- while (c >= L_('0') && c <= L_('9'));
-
- if (exp_negative)
- exponent = -exponent;
- }
- else
- cp = expp;
- }
-
- /* We don't want to have to work with trailing zeroes after the radix. */
- if (dig_no > int_no)
- {
- while (expp[-1] == L_('0'))
- {
- --expp;
- --dig_no;
- }
- assert (dig_no >= int_no);
- }
-
- if (dig_no == int_no && dig_no > 0 && exponent < 0)
- do
- {
- while (! (base == 16 ? ISXDIGIT (expp[-1]) : ISDIGIT (expp[-1])))
- --expp;
-
- if (expp[-1] != L_('0'))
- break;
-
- --expp;
- --dig_no;
- --int_no;
- ++exponent;
- }
- while (dig_no > 0 && exponent < 0);
-
- number_parsed:
-
- /* The whole string is parsed. Store the address of the next character. */
- if (endptr)
- *endptr = (STRING_TYPE *) cp;
-
- if (dig_no == 0)
- return negative ? -0.0 : 0.0;
-
- if (lead_zero)
- {
- /* Find the decimal point */
-#ifdef USE_WIDE_CHAR
- while (*startp != decimal)
- ++startp;
-#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;
- }
-
- /* If the BASE is 16 we can use a simpler algorithm. */
- if (base == 16)
- {
- static const int nbits[16] = { 0, 1, 2, 2, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4 };
- int idx = (MANT_DIG - 1) / BITS_PER_MP_LIMB;
- int pos = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
- mp_limb_t val;
-
- while (!ISXDIGIT (*startp))
- ++startp;
- while (*startp == L_('0'))
- ++startp;
- if (ISDIGIT (*startp))
- val = *startp++ - L_('0');
- else
- val = 10 + TOLOWER (*startp++) - L_('a');
- bits = nbits[val];
- /* We cannot have a leading zero. */
- assert (bits != 0);
-
- if (pos + 1 >= 4 || pos + 1 >= bits)
- {
- /* We don't have to care for wrapping. This is the normal
- case so we add the first clause in the `if' expression as
- an optimization. It is a compile-time constant and so does
- not cost anything. */
- retval[idx] = val << (pos - bits + 1);
- pos -= bits;
- }
- else
- {
- retval[idx--] = val >> (bits - pos - 1);
- retval[idx] = val << (BITS_PER_MP_LIMB - (bits - pos - 1));
- pos = BITS_PER_MP_LIMB - 1 - (bits - pos - 1);
- }
-
- /* Adjust the exponent for the bits we are shifting in. */
- exponent += bits - 1 + (int_no - 1) * 4;
-
- while (--dig_no > 0 && idx >= 0)
- {
- if (!ISXDIGIT (*startp))
- startp += decimal_len;
- if (ISDIGIT (*startp))
- val = *startp++ - L_('0');
- else
- val = 10 + TOLOWER (*startp++) - L_('a');
-
- if (pos + 1 >= 4)
- {
- retval[idx] |= val << (pos - 4 + 1);
- pos -= 4;
- }
- else
- {
- retval[idx--] |= val >> (4 - pos - 1);
- val <<= BITS_PER_MP_LIMB - (4 - pos - 1);
- if (idx < 0)
- return round_and_return (retval, exponent, negative, val,
- BITS_PER_MP_LIMB - 1, dig_no > 0);
-
- retval[idx] = val;
- pos = BITS_PER_MP_LIMB - 1 - (4 - pos - 1);
- }
- }
-
- /* We ran out of digits. */
- MPN_ZERO (retval, idx);
-
- return round_and_return (retval, exponent, negative, 0, 0, 0);
- }
-
- /* Now we have the number of digits in total and the integer digits as well
- as the exponent and its sign. We can decide whether the read digits are
- really integer digits or belong to the fractional part; i.e. we normalize
- 123e-2 to 1.23. */
- {
- register int incr = (exponent < 0 ? MAX (-int_no, exponent)
- : MIN (dig_no - int_no, exponent));
- int_no += incr;
- exponent -= incr;
- }
-
- if (int_no + exponent > MAX_10_EXP + 1)
- {
- __set_errno (ERANGE);
- return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
- }
-
- if (exponent < MIN_10_EXP - (DIG + 1))
- {
- __set_errno (ERANGE);
- return 0.0;
- }
-
- 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
-#ifndef USE_WIDE_CHAR
- , decimal, decimal_len, thousands
-#endif
- );
-
- if (exponent > 0)
- {
- /* We now multiply the gained number by the given power of ten. */
- mp_limb_t *psrc = num;
- mp_limb_t *pdest = den;
- int expbit = 1;
- const struct mp_power *ttab = &_fpioconst_pow10[0];
-
- do
- {
- if ((exponent & expbit) != 0)
- {
- size_t size = ttab->arraysize - _FPIO_CONST_OFFSET;
- mp_limb_t cy;
- exponent ^= expbit;
-
- /* FIXME: not the whole multiplication has to be
- done. If we have the needed number of bits we
- only need the information whether more non-zero
- bits follow. */
- if (numsize >= ttab->arraysize - _FPIO_CONST_OFFSET)
- cy = __mpn_mul (pdest, psrc, numsize,
- &__tens[ttab->arrayoff
- + _FPIO_CONST_OFFSET],
- size);
- else
- cy = __mpn_mul (pdest, &__tens[ttab->arrayoff
- + _FPIO_CONST_OFFSET],
- size, psrc, numsize);
- numsize += size;
- if (cy == 0)
- --numsize;
- (void) SWAP (psrc, pdest);
- }
- expbit <<= 1;
- ++ttab;
- }
- while (exponent != 0);
-
- if (psrc == den)
- memcpy (num, den, numsize * sizeof (mp_limb_t));
- }
-
- /* Determine how many bits of the result we already have. */
- count_leading_zeros (bits, num[numsize - 1]);
- bits = numsize * BITS_PER_MP_LIMB - bits;
-
- /* Now we know the exponent of the number in base two.
- Check it against the maximum possible exponent. */
- if (bits > MAX_EXP)
- {
- __set_errno (ERANGE);
- return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
- }
-
- /* We have already the first BITS bits of the result. Together with
- the information whether more non-zero bits follow this is enough
- to determine the result. */
- if (bits > MANT_DIG)
- {
- int i;
- const mp_size_t least_idx = (bits - MANT_DIG) / BITS_PER_MP_LIMB;
- const mp_size_t least_bit = (bits - MANT_DIG) % BITS_PER_MP_LIMB;
- const mp_size_t round_idx = least_bit == 0 ? least_idx - 1
- : least_idx;
- const mp_size_t round_bit = least_bit == 0 ? BITS_PER_MP_LIMB - 1
- : least_bit - 1;
-
- if (least_bit == 0)
- memcpy (retval, &num[least_idx],
- RETURN_LIMB_SIZE * sizeof (mp_limb_t));
- else
- {
- for (i = least_idx; i < numsize - 1; ++i)
- retval[i - least_idx] = (num[i] >> least_bit)
- | (num[i + 1]
- << (BITS_PER_MP_LIMB - least_bit));
- if (i - least_idx < RETURN_LIMB_SIZE)
- retval[RETURN_LIMB_SIZE - 1] = num[i] >> least_bit;
- }
-
- /* Check whether any limb beside the ones in RETVAL are non-zero. */
- for (i = 0; num[i] == 0; ++i)
- ;
-
- return round_and_return (retval, bits - 1, negative,
- num[round_idx], round_bit,
- int_no < dig_no || i < round_idx);
- /* NOTREACHED */
- }
- else if (dig_no == int_no)
- {
- const mp_size_t target_bit = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
- const mp_size_t is_bit = (bits - 1) % BITS_PER_MP_LIMB;
-
- if (target_bit == is_bit)
- {
- memcpy (&retval[RETURN_LIMB_SIZE - numsize], num,
- numsize * sizeof (mp_limb_t));
- /* FIXME: the following loop can be avoided if we assume a
- maximal MANT_DIG value. */
- MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize);
- }
- else if (target_bit > is_bit)
- {
- (void) __mpn_lshift (&retval[RETURN_LIMB_SIZE - numsize],
- num, numsize, target_bit - is_bit);
- /* FIXME: the following loop can be avoided if we assume a
- maximal MANT_DIG value. */
- MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize);
- }
- else
- {
- mp_limb_t cy;
- assert (numsize < RETURN_LIMB_SIZE);
-
- cy = __mpn_rshift (&retval[RETURN_LIMB_SIZE - numsize],
- num, numsize, is_bit - target_bit);
- retval[RETURN_LIMB_SIZE - numsize - 1] = cy;
- /* FIXME: the following loop can be avoided if we assume a
- maximal MANT_DIG value. */
- MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize - 1);
- }
-
- return round_and_return (retval, bits - 1, negative, 0, 0, 0);
- /* NOTREACHED */
- }
-
- /* Store the bits we already have. */
- memcpy (retval, num, numsize * sizeof (mp_limb_t));
-#if RETURN_LIMB_SIZE > 1
- if (numsize < RETURN_LIMB_SIZE)
- retval[numsize] = 0;
-#endif
- }
-
- /* We have to compute at least some of the fractional digits. */
- {
- /* We construct a fraction and the result of the division gives us
- the needed digits. The denominator is 1.0 multiplied by the
- exponent of the lowest digit; i.e. 0.123 gives 123 / 1000 and
- 123e-6 gives 123 / 1000000. */
-
- int expbit;
- int neg_exp;
- int more_bits;
- mp_limb_t cy;
- mp_limb_t *psrc = den;
- mp_limb_t *pdest = num;
- const struct mp_power *ttab = &_fpioconst_pow10[0];
-
- assert (dig_no > int_no && exponent <= 0);
-
-
- /* For the fractional part we need not process too many digits. One
- decimal digits gives us log_2(10) ~ 3.32 bits. If we now compute
- ceil(BITS / 3) =: N
- digits we should have enough bits for the result. The remaining
- decimal digits give us the information that more bits are following.
- This can be used while rounding. (Two added as a safety margin.) */
- if (dig_no - int_no > (MANT_DIG - bits + 2) / 3 + 2)
- {
- dig_no = int_no + (MANT_DIG - bits + 2) / 3 + 2;
- more_bits = 1;
- }
- else
- more_bits = 0;
-
- neg_exp = dig_no - int_no - exponent;
-
- /* Construct the denominator. */
- densize = 0;
- expbit = 1;
- do
- {
- if ((neg_exp & expbit) != 0)
- {
- mp_limb_t cy;
- neg_exp ^= expbit;
-
- if (densize == 0)
- {
- densize = ttab->arraysize - _FPIO_CONST_OFFSET;
- memcpy (psrc, &__tens[ttab->arrayoff + _FPIO_CONST_OFFSET],
- densize * sizeof (mp_limb_t));
- }
- else
- {
- cy = __mpn_mul (pdest, &__tens[ttab->arrayoff
- + _FPIO_CONST_OFFSET],
- ttab->arraysize - _FPIO_CONST_OFFSET,
- psrc, densize);
- densize += ttab->arraysize - _FPIO_CONST_OFFSET;
- if (cy == 0)
- --densize;
- (void) SWAP (psrc, pdest);
- }
- }
- expbit <<= 1;
- ++ttab;
- }
- while (neg_exp != 0);
-
- if (psrc == num)
- 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
-#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
- a high place in the array so that the division constructs the wanted
- digits. This is done by a "quasi fix point" number representation.
-
- num: ddddddddddd . 0000000000000000000000
- |--- m ---|
- den: ddddddddddd n >= m
- |--- n ---|
- */
-
- count_leading_zeros (cnt, den[densize - 1]);
-
- if (cnt > 0)
- {
- /* Don't call `mpn_shift' with a count of zero since the specification
- does not allow this. */
- (void) __mpn_lshift (den, den, densize, cnt);
- cy = __mpn_lshift (num, num, numsize, cnt);
- if (cy != 0)
- num[numsize++] = cy;
- }
-
- /* Now we are ready for the division. But it is not necessary to
- do a full multi-precision division because we only need a small
- number of bits for the result. So we do not use __mpn_divmod
- here but instead do the division here by hand and stop whenever
- the needed number of bits is reached. The code itself comes
- from the GNU MP Library by Torbj\"orn Granlund. */
-
- exponent = bits;
-
- switch (densize)
- {
- case 1:
- {
- mp_limb_t d, n, quot;
- int used = 0;
-
- n = num[0];
- d = den[0];
- assert (numsize == 1 && n < d);
-
- do
- {
- udiv_qrnnd (quot, n, n, 0, d);
-
-#define got_limb \
- if (bits == 0) \
- { \
- register int cnt; \
- if (quot == 0) \
- cnt = BITS_PER_MP_LIMB; \
- else \
- count_leading_zeros (cnt, quot); \
- exponent -= cnt; \
- if (BITS_PER_MP_LIMB - cnt > MANT_DIG) \
- { \
- used = MANT_DIG + cnt; \
- retval[0] = quot >> (BITS_PER_MP_LIMB - used); \
- bits = MANT_DIG + 1; \
- } \
- else \
- { \
- /* Note that we only clear the second element. */ \
- /* The conditional is determined at compile time. */ \
- if (RETURN_LIMB_SIZE > 1) \
- retval[1] = 0; \
- retval[0] = quot; \
- bits = -cnt; \
- } \
- } \
- else if (bits + BITS_PER_MP_LIMB <= MANT_DIG) \
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, BITS_PER_MP_LIMB, \
- quot); \
- else \
- { \
- used = MANT_DIG - bits; \
- if (used > 0) \
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, quot); \
- } \
- bits += BITS_PER_MP_LIMB
-
- got_limb;
- }
- while (bits <= MANT_DIG);
-
- return round_and_return (retval, exponent - 1, negative,
- quot, BITS_PER_MP_LIMB - 1 - used,
- more_bits || n != 0);
- }
- case 2:
- {
- mp_limb_t d0, d1, n0, n1;
- mp_limb_t quot = 0;
- int used = 0;
-
- d0 = den[0];
- d1 = den[1];
-
- if (numsize < densize)
- {
- if (num[0] >= d1)
- {
- /* The numerator of the number occupies fewer bits than
- the denominator but the one limb is bigger than the
- high limb of the numerator. */
- n1 = 0;
- n0 = num[0];
- }
- else
- {
- if (bits <= 0)
- exponent -= BITS_PER_MP_LIMB;
- else
- {
- if (bits + BITS_PER_MP_LIMB <= MANT_DIG)
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE,
- BITS_PER_MP_LIMB, 0);
- else
- {
- used = MANT_DIG - bits;
- if (used > 0)
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0);
- }
- bits += BITS_PER_MP_LIMB;
- }
- n1 = num[0];
- n0 = 0;
- }
- }
- else
- {
- n1 = num[1];
- n0 = num[0];
- }
-
- while (bits <= MANT_DIG)
- {
- mp_limb_t r;
-
- if (n1 == d1)
- {
- /* QUOT should be either 111..111 or 111..110. We need
- special treatment of this rare case as normal division
- would give overflow. */
- quot = ~(mp_limb_t) 0;
-
- r = n0 + d1;
- if (r < d1) /* Carry in the addition? */
- {
- add_ssaaaa (n1, n0, r - d0, 0, 0, d0);
- goto have_quot;
- }
- n1 = d0 - (d0 != 0);
- n0 = -d0;
- }
- else
- {
- udiv_qrnnd (quot, r, n1, n0, d1);
- umul_ppmm (n1, n0, d0, quot);
- }
-
- q_test:
- if (n1 > r || (n1 == r && n0 > 0))
- {
- /* The estimated QUOT was too large. */
- --quot;
-
- sub_ddmmss (n1, n0, n1, n0, 0, d0);
- r += d1;
- if (r >= d1) /* If not carry, test QUOT again. */
- goto q_test;
- }
- sub_ddmmss (n1, n0, r, 0, n1, n0);
-
- have_quot:
- got_limb;
- }
-
- return round_and_return (retval, exponent - 1, negative,
- quot, BITS_PER_MP_LIMB - 1 - used,
- more_bits || n1 != 0 || n0 != 0);
- }
- default:
- {
- int i;
- mp_limb_t cy, dX, d1, n0, n1;
- mp_limb_t quot = 0;
- int used = 0;
-
- dX = den[densize - 1];
- d1 = den[densize - 2];
-
- /* The division does not work if the upper limb of the two-limb
- numerator is greater than the denominator. */
- if (__mpn_cmp (num, &den[densize - numsize], numsize) > 0)
- num[numsize++] = 0;
-
- if (numsize < densize)
- {
- mp_size_t empty = densize - numsize;
-
- if (bits <= 0)
- {
- register int i;
- for (i = numsize; i > 0; --i)
- num[i + empty] = num[i - 1];
- MPN_ZERO (num, empty + 1);
- exponent -= empty * BITS_PER_MP_LIMB;
- }
- else
- {
- if (bits + empty * BITS_PER_MP_LIMB <= MANT_DIG)
- {
- /* We make a difference here because the compiler
- cannot optimize the `else' case that good and
- this reflects all currently used FLOAT types
- and GMP implementations. */
- register int i;
-#if RETURN_LIMB_SIZE <= 2
- assert (empty == 1);
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE,
- BITS_PER_MP_LIMB, 0);
-#else
- for (i = RETURN_LIMB_SIZE; i > empty; --i)
- retval[i] = retval[i - empty];
-#endif
- for (i = numsize; i > 0; --i)
- num[i + empty] = num[i - 1];
- MPN_ZERO (num, empty + 1);
- }
- else
- {
- used = MANT_DIG - bits;
- if (used >= BITS_PER_MP_LIMB)
- {
- register int i;
- (void) __mpn_lshift (&retval[used
- / BITS_PER_MP_LIMB],
- retval, RETURN_LIMB_SIZE,
- used % BITS_PER_MP_LIMB);
- for (i = used / BITS_PER_MP_LIMB; i >= 0; --i)
- retval[i] = 0;
- }
- else if (used > 0)
- __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0);
- }
- bits += empty * BITS_PER_MP_LIMB;
- }
- }
- else
- {
- int i;
- assert (numsize == densize);
- for (i = numsize; i > 0; --i)
- num[i] = num[i - 1];
- }
-
- den[densize] = 0;
- n0 = num[densize];
-
- while (bits <= MANT_DIG)
- {
- if (n0 == dX)
- /* This might over-estimate QUOT, but it's probably not
- worth the extra code here to find out. */
- quot = ~(mp_limb_t) 0;
- else
- {
- mp_limb_t r;
-
- udiv_qrnnd (quot, r, n0, num[densize - 1], dX);
- umul_ppmm (n1, n0, d1, quot);
-
- while (n1 > r || (n1 == r && n0 > num[densize - 2]))
- {
- --quot;
- r += dX;
- if (r < dX) /* I.e. "carry in previous addition?" */
- break;
- n1 -= n0 < d1;
- n0 -= d1;
- }
- }
-
- /* Possible optimization: We already have (q * n0) and (1 * n1)
- after the calculation of QUOT. Taking advantage of this, we
- could make this loop make two iterations less. */
-
- cy = __mpn_submul_1 (num, den, densize + 1, quot);
-
- if (num[densize] != cy)
- {
- cy = __mpn_add_n (num, num, den, densize);
- assert (cy != 0);
- --quot;
- }
- n0 = num[densize] = num[densize - 1];
- for (i = densize - 1; i > 0; --i)
- num[i] = num[i - 1];
-
- got_limb;
- }
-
- for (i = densize; num[i] == 0 && i >= 0; --i)
- ;
- return round_and_return (retval, exponent - 1, negative,
- quot, BITS_PER_MP_LIMB - 1 - used,
- more_bits || i >= 0);
- }
- }
- }
-
- /* NOTREACHED */
+ return INTERNAL(STRTOF_L) (nptr, endptr, group, _NL_CURRENT_LOCALE);
}
-#if defined _LIBC \
- && !(defined USE_IN_EXTENDED_LOCALE_MODEL && defined USE_WIDE_CHAR)
+#if defined _LIBC
libc_hidden_def (INTERNAL (STRTOF))
#endif
-
-/* External user entry point. */
+
FLOAT
#ifdef weak_function
weak_function
#endif
-STRTOF (nptr, endptr LOCALE_PARAM)
+STRTOF (nptr, endptr)
const STRING_TYPE *nptr;
STRING_TYPE **endptr;
- LOCALE_PARAM_DECL
{
- return INTERNAL (STRTOF) (nptr, endptr, 0 LOCALE_PARAM);
+ return INTERNAL(STRTOF_L) (nptr, endptr, 0, _NL_CURRENT_LOCALE);
}
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index e8449050d3..89d30b435b 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to float value, using given locale.
- Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Copyright (C) 1997,98,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,14 +18,1555 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-
#include <xlocale.h>
extern double ____strtod_l_internal (const char *, char **, int, __locale_t);
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
int, int, __locale_t);
-#include <strtod.c>
+/* Configuration part. These macros are defined by `strtold.c',
+ `strtof.c', `wcstod.c', `wcstold.c', and `wcstof.c' to produce the
+ `long double' and `float' versions of the reader. */
+#ifndef FLOAT
+# define FLOAT double
+# define FLT DBL
+# ifdef USE_WIDE_CHAR
+# define STRTOF wcstod_l
+# define __STRTOF __wcstod_l
+# else
+# define STRTOF strtod_l
+# define __STRTOF __strtod_l
+# endif
+# define MPN2FLOAT __mpn_construct_double
+# define FLOAT_HUGE_VAL HUGE_VAL
+# define SET_MANTISSA(flt, mant) \
+ do { union ieee754_double u; \
+ u.d = (flt); \
+ if ((mant & 0xfffffffffffffULL) == 0) \
+ mant = 0x8000000000000ULL; \
+ u.ieee.mantissa0 = ((mant) >> 32) & 0xfffff; \
+ u.ieee.mantissa1 = (mant) & 0xffffffff; \
+ (flt) = u.d; \
+ } while (0)
+#endif
+/* End of configuration part. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <ieee754.h>
+#include "../locale/localeinfo.h"
+#include <locale.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* The gmp headers need some configuration frobs. */
+#define HAVE_ALLOCA 1
+
+/* Include gmp-mparam.h first, such that definitions of _SHORT_LIMB
+ 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 "fpioconst.h"
+
+#define NDEBUG 1
+#include <assert.h>
+
+
+/* We use this code for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT and
+ _NL_CURRENT_WORD macros. */
+#undef _NL_CURRENT
+#define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+#undef _NL_CURRENT_WORD
+#define _NL_CURRENT_WORD(category, item) \
+ ((uint32_t) current->values[_NL_ITEM_INDEX (item)].word)
+
+#if defined _LIBC || defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef USE_WIDE_CHAR
+# include <wctype.h>
+# define STRING_TYPE wchar_t
+# define CHAR_TYPE wint_t
+# define L_(Ch) L##Ch
+# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
+# 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 STRTOULL(S, E, B) ____wcstoull_l_internal ((S), (E), (B), 0, loc)
+#else
+# define STRING_TYPE char
+# define CHAR_TYPE char
+# define L_(Ch) Ch
+# define ISSPACE(Ch) __isspace_l ((Ch), loc)
+# 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 STRTOULL(S, E, B) ____strtoull_l_internal ((S), (E), (B), 0, loc)
+#endif
+
+
+/* Constants we need from float.h; select the set for the FLOAT precision. */
+#define MANT_DIG PASTE(FLT,_MANT_DIG)
+#define DIG PASTE(FLT,_DIG)
+#define MAX_EXP PASTE(FLT,_MAX_EXP)
+#define MIN_EXP PASTE(FLT,_MIN_EXP)
+#define MAX_10_EXP PASTE(FLT,_MAX_10_EXP)
+#define MIN_10_EXP PASTE(FLT,_MIN_10_EXP)
+
+/* Extra macros required to get FLT expanded before the pasting. */
+#define PASTE(a,b) PASTE1(a,b)
+#define PASTE1(a,b) a##b
+
+/* Function to construct a floating point number from an MP integer
+ containing the fraction bits, a base 2 exponent, and a sign flag. */
+extern FLOAT MPN2FLOAT (mp_srcptr mpn, int exponent, int negative);
+
+/* Definitions according to limb size used. */
+#if BITS_PER_MP_LIMB == 32
+# define MAX_DIG_PER_LIMB 9
+# define MAX_FAC_PER_LIMB 1000000000UL
+#elif BITS_PER_MP_LIMB == 64
+# define MAX_DIG_PER_LIMB 19
+# define MAX_FAC_PER_LIMB 10000000000000000000ULL
+#else
+# error "mp_limb_t size " BITS_PER_MP_LIMB "not accounted for"
+#endif
+
+
+/* Local data structure. */
+static const mp_limb_t _tens_in_limb[MAX_DIG_PER_LIMB + 1] =
+{ 0, 10, 100,
+ 1000, 10000, 100000L,
+ 1000000L, 10000000L, 100000000L,
+ 1000000000L
+#if BITS_PER_MP_LIMB > 32
+ , 10000000000ULL, 100000000000ULL,
+ 1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
+ 1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL,
+ 1000000000000000000ULL, 10000000000000000000ULL
+#endif
+#if BITS_PER_MP_LIMB > 64
+ #error "Need to expand tens_in_limb table to" MAX_DIG_PER_LIMB
+#endif
+};
+
+#ifndef howmany
+#define howmany(x,y) (((x)+((y)-1))/(y))
+#endif
+#define SWAP(x, y) ({ typeof(x) _tmp = x; x = y; y = _tmp; })
+
+#define NDIG (MAX_10_EXP - MIN_10_EXP + 2 * MANT_DIG)
+#define HEXNDIG ((MAX_EXP - MIN_EXP + 7) / 8 + 2 * MANT_DIG)
+#define RETURN_LIMB_SIZE howmany (MANT_DIG, BITS_PER_MP_LIMB)
+
+#define RETURN(val,end) \
+ do { if (endptr != NULL) *endptr = (STRING_TYPE *) (end); \
+ return val; } while (0)
+
+/* Maximum size necessary for mpn integers to hold floating point numbers. */
+#define MPNSIZE (howmany (MAX_EXP + 2 * MANT_DIG, BITS_PER_MP_LIMB) \
+ + 2)
+/* Declare an mpn integer variable that big. */
+#define MPN_VAR(name) mp_limb_t name[MPNSIZE]; mp_size_t name##size
+/* Copy an mpn integer value. */
+#define MPN_ASSIGN(dst, src) \
+ memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb_t))
+
+
+/* Return a floating point number of the needed type according to the given
+ multi-precision number after possible rounding. */
+static FLOAT
+round_and_return (mp_limb_t *retval, int exponent, int negative,
+ mp_limb_t round_limb, mp_size_t round_bit, int more_bits)
+{
+ if (exponent < MIN_EXP - 1)
+ {
+ mp_size_t shift = MIN_EXP - 1 - exponent;
+
+ if (shift > MANT_DIG)
+ {
+ __set_errno (EDOM);
+ return 0.0;
+ }
+
+ more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
+ if (shift == MANT_DIG)
+ /* This is a special case to handle the very seldom case where
+ the mantissa will be empty after the shift. */
+ {
+ int i;
+
+ round_limb = retval[RETURN_LIMB_SIZE - 1];
+ round_bit = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
+ for (i = 0; i < RETURN_LIMB_SIZE; ++i)
+ more_bits |= retval[i] != 0;
+ MPN_ZERO (retval, RETURN_LIMB_SIZE);
+ }
+ else if (shift >= BITS_PER_MP_LIMB)
+ {
+ int i;
+
+ round_limb = retval[(shift - 1) / BITS_PER_MP_LIMB];
+ round_bit = (shift - 1) % BITS_PER_MP_LIMB;
+ for (i = 0; i < (shift - 1) / BITS_PER_MP_LIMB; ++i)
+ more_bits |= retval[i] != 0;
+ more_bits |= ((round_limb & ((((mp_limb_t) 1) << round_bit) - 1))
+ != 0);
+
+ (void) __mpn_rshift (retval, &retval[shift / BITS_PER_MP_LIMB],
+ RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB),
+ shift % BITS_PER_MP_LIMB);
+ MPN_ZERO (&retval[RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB)],
+ shift / BITS_PER_MP_LIMB);
+ }
+ else if (shift > 0)
+ {
+ round_limb = retval[0];
+ round_bit = shift - 1;
+ (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
+ }
+ /* This is a hook for the m68k long double format, where the
+ exponent bias is the same for normalized and denormalized
+ numbers. */
+#ifndef DENORM_EXP
+# define DENORM_EXP (MIN_EXP - 2)
+#endif
+ exponent = DENORM_EXP;
+ }
+
+ if ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
+ && (more_bits || (retval[0] & 1) != 0
+ || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
+ {
+ mp_limb_t cy = __mpn_add_1 (retval, retval, RETURN_LIMB_SIZE, 1);
+
+ if (((MANT_DIG % BITS_PER_MP_LIMB) == 0 && cy) ||
+ ((MANT_DIG % BITS_PER_MP_LIMB) != 0 &&
+ (retval[RETURN_LIMB_SIZE - 1]
+ & (((mp_limb_t) 1) << (MANT_DIG % BITS_PER_MP_LIMB))) != 0))
+ {
+ ++exponent;
+ (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, 1);
+ retval[RETURN_LIMB_SIZE - 1]
+ |= ((mp_limb_t) 1) << ((MANT_DIG - 1) % BITS_PER_MP_LIMB);
+ }
+ else if (exponent == DENORM_EXP
+ && (retval[RETURN_LIMB_SIZE - 1]
+ & (((mp_limb_t) 1) << ((MANT_DIG - 1) % BITS_PER_MP_LIMB)))
+ != 0)
+ /* The number was denormalized but now normalized. */
+ exponent = MIN_EXP - 1;
+ }
+
+ if (exponent > MAX_EXP)
+ return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
+
+ return MPN2FLOAT (retval, exponent, negative);
+}
+
+
+/* Read a multi-precision integer starting at STR with exactly DIGCNT digits
+ into N. Return the size of the number limbs in NSIZE at the first
+ character od the string that is not part of the integer as the function
+ value. If the EXPONENT is small enough to be taken as an additional
+ factor for the resulting number (see code) multiply by it. */
+static const STRING_TYPE *
+str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize,
+ 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;
+ mp_limb_t low = 0;
+ mp_limb_t start;
+
+ *nsize = 0;
+ assert (digcnt > 0);
+ do
+ {
+ if (cnt == MAX_DIG_PER_LIMB)
+ {
+ if (*nsize == 0)
+ {
+ n[0] = low;
+ *nsize = 1;
+ }
+ else
+ {
+ mp_limb_t cy;
+ cy = __mpn_mul_1 (n, n, *nsize, MAX_FAC_PER_LIMB);
+ cy += __mpn_add_1 (n, n, *nsize, low);
+ if (cy != 0)
+ {
+ n[*nsize] = cy;
+ ++(*nsize);
+ }
+ }
+ cnt = 0;
+ low = 0;
+ }
+
+ /* There might be thousands separators or radix characters in
+ 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. */
+#ifdef USE_WIDE_CHAR
+ if (*str < L'0' || *str > L'9')
+ ++str;
+#else
+ if (*str < '0' || *str > '9')
+ {
+ int inner = 0;
+ if (thousands != NULL && *str == *thousands
+ && ({ for (inner = 1; thousands[inner] != '\0'; ++inner)
+ if (thousands[inner] != str[inner])
+ break;
+ thousands[inner] == '\0'; }))
+ str += inner;
+ else
+ str += decimal_len;
+ }
+#endif
+ low = low * 10 + *str++ - L_('0');
+ ++cnt;
+ }
+ while (--digcnt > 0);
+
+ if (*exponent > 0 && cnt + *exponent <= MAX_DIG_PER_LIMB)
+ {
+ low *= _tens_in_limb[*exponent];
+ start = _tens_in_limb[cnt + *exponent];
+ *exponent = 0;
+ }
+ else
+ start = _tens_in_limb[cnt];
+
+ if (*nsize == 0)
+ {
+ n[0] = low;
+ *nsize = 1;
+ }
+ else
+ {
+ mp_limb_t cy;
+ cy = __mpn_mul_1 (n, n, *nsize, start);
+ cy += __mpn_add_1 (n, n, *nsize, low);
+ if (cy != 0)
+ n[(*nsize)++] = cy;
+ }
+
+ return str;
+}
+
+
+/* Shift {PTR, SIZE} COUNT bits to the left, and fill the vacated bits
+ with the COUNT most significant bits of LIMB.
+
+ Tege doesn't like this function so I have to write it here myself. :)
+ --drepper */
+static inline void
+__attribute ((always_inline))
+__mpn_lshift_1 (mp_limb_t *ptr, mp_size_t size, unsigned int count,
+ mp_limb_t limb)
+{
+ if (__builtin_constant_p (count) && count == BITS_PER_MP_LIMB)
+ {
+ /* Optimize the case of shifting by exactly a word:
+ just copy words, with no actual bit-shifting. */
+ mp_size_t i;
+ for (i = size - 1; i > 0; --i)
+ ptr[i] = ptr[i - 1];
+ ptr[0] = limb;
+ }
+ else
+ {
+ (void) __mpn_lshift (ptr, ptr, size, count);
+ ptr[0] |= limb >> (BITS_PER_MP_LIMB - count);
+ }
+}
+
+
+#define INTERNAL(x) INTERNAL1(x)
+#define INTERNAL1(x) __##x##_internal
+
+/* This file defines a function to check for correct grouping. */
+#include "grouping.h"
+
+
+/* Return a floating point number with the value of the given string NPTR.
+ Set *ENDPTR to the character after the last used one. If the number is
+ smaller than the smallest representable number, set `errno' to ERANGE and
+ 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)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int group;
+ __locale_t loc;
+{
+ int negative; /* The sign of the number. */
+ MPN_VAR (num); /* MP representation of the number. */
+ int exponent; /* Exponent of the number. */
+
+ /* Numbers starting `0X' or `0x' have to be processed with base 16. */
+ int base = 10;
+
+ /* When we have to compute fractional digits we form a fraction with a
+ second multi-precision number (and we sometimes need a second for
+ temporary results). */
+ MPN_VAR (den);
+
+ /* Representation for the return value. */
+ mp_limb_t retval[RETURN_LIMB_SIZE];
+ /* Number of bits currently in result value. */
+ int bits;
+
+ /* Running pointer after the last character processed in the string. */
+ const STRING_TYPE *cp, *tp;
+ /* Start of significant part of the number. */
+ const STRING_TYPE *startp, *start_of_digits;
+ /* Points at the character following the integer and fractional digits. */
+ const STRING_TYPE *expp;
+ /* Total number of digit and number of digits in integer part. */
+ int dig_no, int_no, lead_zero;
+ /* Contains the last character read. */
+ CHAR_TYPE c;
+
+/* We should get wint_t from <stddef.h>, but not all GCC versions define it
+ there. So define it ourselves if it remains undefined. */
+#ifndef _WINT_T
+ 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;
+
+ struct locale_data *current = loc->__locales[LC_NUMERIC];
+
+ if (group)
+ {
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+ else
+ {
+ /* Figure out the thousands separator character. */
+#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. */
+#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;
+ negative = 0;
+ bits = 0;
+
+ /* Parse string to get maximal legal prefix. We need the number of
+ characters of the integer part, the fractional part and the exponent. */
+ cp = nptr - 1;
+ /* Ignore leading white space. */
+ do
+ c = *++cp;
+ while (ISSPACE (c));
+
+ /* Get sign of the result. */
+ if (c == L_('-'))
+ {
+ negative = 1;
+ c = *++cp;
+ }
+ else if (c == L_('+'))
+ c = *++cp;
+
+ /* Return 0.0 if no legal string is found.
+ No character is used even if a sign was found. */
+#ifdef USE_WIDE_CHAR
+ if (c == (wint_t) decimal
+ && (wint_t) cp[1] >= L'0' && (wint_t) 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[cnt] >= '0' && cp[cnt] <= '9')
+ {
+ /* We accept it. This funny construct is here only to indent
+ the code directly. */
+ }
+#endif
+ else if (c < L_('0') || c > L_('9'))
+ {
+ /* Check for `INF' or `INFINITY'. */
+ if (TOLOWER (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
+ {
+ /* Return +/- infinity. */
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *)
+ (cp + (STRNCASECMP (cp + 3, L_("inity"), 5) == 0
+ ? 8 : 3));
+
+ return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
+ }
+
+ if (TOLOWER (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
+ {
+ /* Return NaN. */
+ FLOAT retval = NAN;
+
+ cp += 3;
+
+ /* Match `(n-char-sequence-digit)'. */
+ if (*cp == L_('('))
+ {
+ const STRING_TYPE *startp = cp;
+ do
+ ++cp;
+ while ((*cp >= L_('0') && *cp <= L_('9'))
+ || (TOLOWER (*cp) >= L_('a') && TOLOWER (*cp) <= L_('z'))
+ || *cp == L_('_'));
+
+ if (*cp != L_(')'))
+ /* The closing brace is missing. Only match the NAN
+ part. */
+ cp = startp;
+ else
+ {
+ /* This is a system-dependent way to specify the
+ bitmask used for the NaN. We expect it to be
+ a number which is put in the mantissa of the
+ number. */
+ STRING_TYPE *endp;
+ unsigned long long int mant;
+
+ mant = STRTOULL (startp + 1, &endp, 0);
+ if (endp == cp)
+ SET_MANTISSA (retval, mant);
+ }
+ }
+
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *) cp;
+
+ return retval;
+ }
+
+ /* It is really a text we do not recognize. */
+ RETURN (0.0, nptr);
+ }
+
+ /* First look whether we are faced with a hexadecimal number. */
+ if (c == L_('0') && TOLOWER (cp[1]) == L_('x'))
+ {
+ /* Okay, it is a hexa-decimal number. Remember this and skip
+ the characters. BTW: hexadecimal numbers must not be
+ grouped. */
+ base = 16;
+ cp += 2;
+ c = *cp;
+ grouping = NULL;
+ }
+
+ /* Record the start of the digits, in case we will check their grouping. */
+ start_of_digits = startp = cp;
+
+ /* Ignore leading zeroes. This helps us to avoid useless computations. */
+#ifdef USE_WIDE_CHAR
+ while (c == L'0' || ((wint_t) thousands != L'\0' && c == (wint_t) 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 < (CHAR_TYPE) TOLOWER (L_('a'))
+ || c > (CHAR_TYPE) TOLOWER (L_('f'))))
+#ifdef USE_WIDE_CHAR
+ && c != (wint_t) 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
+ || (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,
+ grouping);
+#else
+ tp = __correctly_grouped_prefixmb (start_of_digits, cp, thousands,
+ grouping);
+#endif
+ /* If TP is at the start of the digits, there was no correctly
+ grouped prefix of the string; so no number found. */
+ RETURN (0.0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
+ }
+
+ /* Remember first significant digit and read following characters until the
+ decimal point, exponent character or any non-FP number character. */
+ startp = cp;
+ dig_no = 0;
+ while (1)
+ {
+ if ((c >= L_('0') && c <= L_('9'))
+ || (base == 16 && (wint_t) TOLOWER (c) >= L_('a')
+ && (wint_t) TOLOWER (c) <= L_('f')))
+ ++dig_no;
+ else
+ {
+#ifdef USE_WIDE_CHAR
+ if ((wint_t) thousands == L'\0' || c != (wint_t) 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;
+ }
+
+ if (grouping && dig_no > 0)
+ {
+ /* Check the grouping of the digits. */
+#ifdef USE_WIDE_CHAR
+ tp = __correctly_grouped_prefixwc (start_of_digits, cp, thousands,
+ grouping);
+#else
+ tp = __correctly_grouped_prefixmb (start_of_digits, cp, thousands,
+ grouping);
+#endif
+ if (cp != tp)
+ {
+ /* Less than the entire string was correctly grouped. */
+
+ if (tp == start_of_digits)
+ /* No valid group of numbers at all: no valid number. */
+ RETURN (0.0, nptr);
+
+ if (tp < startp)
+ /* The number is validly grouped, but consists
+ only of zeroes. The whole value is zero. */
+ RETURN (0.0, tp);
+
+ /* Recompute DIG_NO so we won't read more digits than
+ are properly grouped. */
+ cp = tp;
+ dig_no = 0;
+ for (tp = startp; tp < cp; ++tp)
+ if (*tp >= L_('0') && *tp <= L_('9'))
+ ++dig_no;
+
+ int_no = dig_no;
+ lead_zero = 0;
+
+ goto number_parsed;
+ }
+ }
+
+ /* We have the number 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. */
+ if (
+#ifdef USE_WIDE_CHAR
+ c == (wint_t) decimal
+#else
+ ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
+ if (decimal[cnt] != cp[cnt])
+ break;
+ decimal[cnt] == '\0'; })
+#endif
+ )
+ {
+ cp += decimal_len;
+ c = *cp;
+ while ((c >= L_('0') && c <= L_('9')) ||
+ (base == 16 && TOLOWER (c) >= L_('a') && TOLOWER (c) <= L_('f')))
+ {
+ if (c != L_('0') && lead_zero == -1)
+ lead_zero = dig_no - int_no;
+ ++dig_no;
+ c = *++cp;
+ }
+ }
+
+ /* Remember start of exponent (if any). */
+ expp = cp;
+
+ /* Read exponent. */
+ if ((base == 16 && TOLOWER (c) == L_('p'))
+ || (base != 16 && TOLOWER (c) == L_('e')))
+ {
+ int exp_negative = 0;
+
+ c = *++cp;
+ if (c == L_('-'))
+ {
+ exp_negative = 1;
+ c = *++cp;
+ }
+ else if (c == L_('+'))
+ c = *++cp;
+
+ if (c >= L_('0') && c <= L_('9'))
+ {
+ int exp_limit;
+
+ /* Get the exponent limit. */
+ if (base == 16)
+ exp_limit = (exp_negative ?
+ -MIN_EXP + MANT_DIG + 4 * int_no :
+ MAX_EXP - 4 * int_no + lead_zero);
+ else
+ exp_limit = (exp_negative ?
+ -MIN_10_EXP + MANT_DIG + int_no :
+ MAX_10_EXP - int_no + lead_zero);
+
+ do
+ {
+ exponent *= 10;
+
+ if (exponent > exp_limit)
+ /* The exponent is too large/small to represent a valid
+ number. */
+ {
+ FLOAT result;
+
+ /* We have to take care for special situation: a joker
+ might have written "0.0e100000" which is in fact
+ zero. */
+ if (lead_zero == -1)
+ result = negative ? -0.0 : 0.0;
+ else
+ {
+ /* Overflow or underflow. */
+ __set_errno (ERANGE);
+ result = (exp_negative ? 0.0 :
+ negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL);
+ }
+
+ /* Accept all following digits as part of the exponent. */
+ do
+ ++cp;
+ while (*cp >= L_('0') && *cp <= L_('9'));
+
+ RETURN (result, cp);
+ /* NOTREACHED */
+ }
+
+ exponent += c - L_('0');
+ c = *++cp;
+ }
+ while (c >= L_('0') && c <= L_('9'));
+
+ if (exp_negative)
+ exponent = -exponent;
+ }
+ else
+ cp = expp;
+ }
+
+ /* We don't want to have to work with trailing zeroes after the radix. */
+ if (dig_no > int_no)
+ {
+ while (expp[-1] == L_('0'))
+ {
+ --expp;
+ --dig_no;
+ }
+ assert (dig_no >= int_no);
+ }
+
+ if (dig_no == int_no && dig_no > 0 && exponent < 0)
+ do
+ {
+ while (! (base == 16 ? ISXDIGIT (expp[-1]) : ISDIGIT (expp[-1])))
+ --expp;
+
+ if (expp[-1] != L_('0'))
+ break;
+
+ --expp;
+ --dig_no;
+ --int_no;
+ ++exponent;
+ }
+ while (dig_no > 0 && exponent < 0);
+
+ number_parsed:
+
+ /* The whole string is parsed. Store the address of the next character. */
+ if (endptr)
+ *endptr = (STRING_TYPE *) cp;
+
+ if (dig_no == 0)
+ return negative ? -0.0 : 0.0;
+
+ if (lead_zero)
+ {
+ /* Find the decimal point */
+#ifdef USE_WIDE_CHAR
+ while (*startp != decimal)
+ ++startp;
+#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;
+ }
+
+ /* If the BASE is 16 we can use a simpler algorithm. */
+ if (base == 16)
+ {
+ static const int nbits[16] = { 0, 1, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4 };
+ int idx = (MANT_DIG - 1) / BITS_PER_MP_LIMB;
+ int pos = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
+ mp_limb_t val;
+
+ while (!ISXDIGIT (*startp))
+ ++startp;
+ while (*startp == L_('0'))
+ ++startp;
+ if (ISDIGIT (*startp))
+ val = *startp++ - L_('0');
+ else
+ val = 10 + TOLOWER (*startp++) - L_('a');
+ bits = nbits[val];
+ /* We cannot have a leading zero. */
+ assert (bits != 0);
+
+ if (pos + 1 >= 4 || pos + 1 >= bits)
+ {
+ /* We don't have to care for wrapping. This is the normal
+ case so we add the first clause in the `if' expression as
+ an optimization. It is a compile-time constant and so does
+ not cost anything. */
+ retval[idx] = val << (pos - bits + 1);
+ pos -= bits;
+ }
+ else
+ {
+ retval[idx--] = val >> (bits - pos - 1);
+ retval[idx] = val << (BITS_PER_MP_LIMB - (bits - pos - 1));
+ pos = BITS_PER_MP_LIMB - 1 - (bits - pos - 1);
+ }
+
+ /* Adjust the exponent for the bits we are shifting in. */
+ exponent += bits - 1 + (int_no - 1) * 4;
+
+ while (--dig_no > 0 && idx >= 0)
+ {
+ if (!ISXDIGIT (*startp))
+ startp += decimal_len;
+ if (ISDIGIT (*startp))
+ val = *startp++ - L_('0');
+ else
+ val = 10 + TOLOWER (*startp++) - L_('a');
+
+ if (pos + 1 >= 4)
+ {
+ retval[idx] |= val << (pos - 4 + 1);
+ pos -= 4;
+ }
+ else
+ {
+ retval[idx--] |= val >> (4 - pos - 1);
+ val <<= BITS_PER_MP_LIMB - (4 - pos - 1);
+ if (idx < 0)
+ return round_and_return (retval, exponent, negative, val,
+ BITS_PER_MP_LIMB - 1, dig_no > 0);
+
+ retval[idx] = val;
+ pos = BITS_PER_MP_LIMB - 1 - (4 - pos - 1);
+ }
+ }
+
+ /* We ran out of digits. */
+ MPN_ZERO (retval, idx);
+
+ return round_and_return (retval, exponent, negative, 0, 0, 0);
+ }
+
+ /* Now we have the number of digits in total and the integer digits as well
+ as the exponent and its sign. We can decide whether the read digits are
+ really integer digits or belong to the fractional part; i.e. we normalize
+ 123e-2 to 1.23. */
+ {
+ register int incr = (exponent < 0 ? MAX (-int_no, exponent)
+ : MIN (dig_no - int_no, exponent));
+ int_no += incr;
+ exponent -= incr;
+ }
+
+ if (int_no + exponent > MAX_10_EXP + 1)
+ {
+ __set_errno (ERANGE);
+ return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
+ }
+
+ if (exponent < MIN_10_EXP - (DIG + 1))
+ {
+ __set_errno (ERANGE);
+ return 0.0;
+ }
+
+ 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
+#ifndef USE_WIDE_CHAR
+ , decimal, decimal_len, thousands
+#endif
+ );
+
+ if (exponent > 0)
+ {
+ /* We now multiply the gained number by the given power of ten. */
+ mp_limb_t *psrc = num;
+ mp_limb_t *pdest = den;
+ int expbit = 1;
+ const struct mp_power *ttab = &_fpioconst_pow10[0];
+
+ do
+ {
+ if ((exponent & expbit) != 0)
+ {
+ size_t size = ttab->arraysize - _FPIO_CONST_OFFSET;
+ mp_limb_t cy;
+ exponent ^= expbit;
+
+ /* FIXME: not the whole multiplication has to be
+ done. If we have the needed number of bits we
+ only need the information whether more non-zero
+ bits follow. */
+ if (numsize >= ttab->arraysize - _FPIO_CONST_OFFSET)
+ cy = __mpn_mul (pdest, psrc, numsize,
+ &__tens[ttab->arrayoff
+ + _FPIO_CONST_OFFSET],
+ size);
+ else
+ cy = __mpn_mul (pdest, &__tens[ttab->arrayoff
+ + _FPIO_CONST_OFFSET],
+ size, psrc, numsize);
+ numsize += size;
+ if (cy == 0)
+ --numsize;
+ (void) SWAP (psrc, pdest);
+ }
+ expbit <<= 1;
+ ++ttab;
+ }
+ while (exponent != 0);
+
+ if (psrc == den)
+ memcpy (num, den, numsize * sizeof (mp_limb_t));
+ }
+
+ /* Determine how many bits of the result we already have. */
+ count_leading_zeros (bits, num[numsize - 1]);
+ bits = numsize * BITS_PER_MP_LIMB - bits;
+
+ /* Now we know the exponent of the number in base two.
+ Check it against the maximum possible exponent. */
+ if (bits > MAX_EXP)
+ {
+ __set_errno (ERANGE);
+ return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
+ }
+
+ /* We have already the first BITS bits of the result. Together with
+ the information whether more non-zero bits follow this is enough
+ to determine the result. */
+ if (bits > MANT_DIG)
+ {
+ int i;
+ const mp_size_t least_idx = (bits - MANT_DIG) / BITS_PER_MP_LIMB;
+ const mp_size_t least_bit = (bits - MANT_DIG) % BITS_PER_MP_LIMB;
+ const mp_size_t round_idx = least_bit == 0 ? least_idx - 1
+ : least_idx;
+ const mp_size_t round_bit = least_bit == 0 ? BITS_PER_MP_LIMB - 1
+ : least_bit - 1;
+
+ if (least_bit == 0)
+ memcpy (retval, &num[least_idx],
+ RETURN_LIMB_SIZE * sizeof (mp_limb_t));
+ else
+ {
+ for (i = least_idx; i < numsize - 1; ++i)
+ retval[i - least_idx] = (num[i] >> least_bit)
+ | (num[i + 1]
+ << (BITS_PER_MP_LIMB - least_bit));
+ if (i - least_idx < RETURN_LIMB_SIZE)
+ retval[RETURN_LIMB_SIZE - 1] = num[i] >> least_bit;
+ }
+
+ /* Check whether any limb beside the ones in RETVAL are non-zero. */
+ for (i = 0; num[i] == 0; ++i)
+ ;
+
+ return round_and_return (retval, bits - 1, negative,
+ num[round_idx], round_bit,
+ int_no < dig_no || i < round_idx);
+ /* NOTREACHED */
+ }
+ else if (dig_no == int_no)
+ {
+ const mp_size_t target_bit = (MANT_DIG - 1) % BITS_PER_MP_LIMB;
+ const mp_size_t is_bit = (bits - 1) % BITS_PER_MP_LIMB;
+
+ if (target_bit == is_bit)
+ {
+ memcpy (&retval[RETURN_LIMB_SIZE - numsize], num,
+ numsize * sizeof (mp_limb_t));
+ /* FIXME: the following loop can be avoided if we assume a
+ maximal MANT_DIG value. */
+ MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize);
+ }
+ else if (target_bit > is_bit)
+ {
+ (void) __mpn_lshift (&retval[RETURN_LIMB_SIZE - numsize],
+ num, numsize, target_bit - is_bit);
+ /* FIXME: the following loop can be avoided if we assume a
+ maximal MANT_DIG value. */
+ MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize);
+ }
+ else
+ {
+ mp_limb_t cy;
+ assert (numsize < RETURN_LIMB_SIZE);
+
+ cy = __mpn_rshift (&retval[RETURN_LIMB_SIZE - numsize],
+ num, numsize, is_bit - target_bit);
+ retval[RETURN_LIMB_SIZE - numsize - 1] = cy;
+ /* FIXME: the following loop can be avoided if we assume a
+ maximal MANT_DIG value. */
+ MPN_ZERO (retval, RETURN_LIMB_SIZE - numsize - 1);
+ }
+
+ return round_and_return (retval, bits - 1, negative, 0, 0, 0);
+ /* NOTREACHED */
+ }
+
+ /* Store the bits we already have. */
+ memcpy (retval, num, numsize * sizeof (mp_limb_t));
+#if RETURN_LIMB_SIZE > 1
+ if (numsize < RETURN_LIMB_SIZE)
+ retval[numsize] = 0;
+#endif
+ }
+
+ /* We have to compute at least some of the fractional digits. */
+ {
+ /* We construct a fraction and the result of the division gives us
+ the needed digits. The denominator is 1.0 multiplied by the
+ exponent of the lowest digit; i.e. 0.123 gives 123 / 1000 and
+ 123e-6 gives 123 / 1000000. */
+
+ int expbit;
+ int neg_exp;
+ int more_bits;
+ mp_limb_t cy;
+ mp_limb_t *psrc = den;
+ mp_limb_t *pdest = num;
+ const struct mp_power *ttab = &_fpioconst_pow10[0];
+
+ assert (dig_no > int_no && exponent <= 0);
+
+
+ /* For the fractional part we need not process too many digits. One
+ decimal digits gives us log_2(10) ~ 3.32 bits. If we now compute
+ ceil(BITS / 3) =: N
+ digits we should have enough bits for the result. The remaining
+ decimal digits give us the information that more bits are following.
+ This can be used while rounding. (Two added as a safety margin.) */
+ if (dig_no - int_no > (MANT_DIG - bits + 2) / 3 + 2)
+ {
+ dig_no = int_no + (MANT_DIG - bits + 2) / 3 + 2;
+ more_bits = 1;
+ }
+ else
+ more_bits = 0;
+
+ neg_exp = dig_no - int_no - exponent;
+
+ /* Construct the denominator. */
+ densize = 0;
+ expbit = 1;
+ do
+ {
+ if ((neg_exp & expbit) != 0)
+ {
+ mp_limb_t cy;
+ neg_exp ^= expbit;
+
+ if (densize == 0)
+ {
+ densize = ttab->arraysize - _FPIO_CONST_OFFSET;
+ memcpy (psrc, &__tens[ttab->arrayoff + _FPIO_CONST_OFFSET],
+ densize * sizeof (mp_limb_t));
+ }
+ else
+ {
+ cy = __mpn_mul (pdest, &__tens[ttab->arrayoff
+ + _FPIO_CONST_OFFSET],
+ ttab->arraysize - _FPIO_CONST_OFFSET,
+ psrc, densize);
+ densize += ttab->arraysize - _FPIO_CONST_OFFSET;
+ if (cy == 0)
+ --densize;
+ (void) SWAP (psrc, pdest);
+ }
+ }
+ expbit <<= 1;
+ ++ttab;
+ }
+ while (neg_exp != 0);
+
+ if (psrc == num)
+ 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
+#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
+ a high place in the array so that the division constructs the wanted
+ digits. This is done by a "quasi fix point" number representation.
+
+ num: ddddddddddd . 0000000000000000000000
+ |--- m ---|
+ den: ddddddddddd n >= m
+ |--- n ---|
+ */
+
+ count_leading_zeros (cnt, den[densize - 1]);
+
+ if (cnt > 0)
+ {
+ /* Don't call `mpn_shift' with a count of zero since the specification
+ does not allow this. */
+ (void) __mpn_lshift (den, den, densize, cnt);
+ cy = __mpn_lshift (num, num, numsize, cnt);
+ if (cy != 0)
+ num[numsize++] = cy;
+ }
+
+ /* Now we are ready for the division. But it is not necessary to
+ do a full multi-precision division because we only need a small
+ number of bits for the result. So we do not use __mpn_divmod
+ here but instead do the division here by hand and stop whenever
+ the needed number of bits is reached. The code itself comes
+ from the GNU MP Library by Torbj\"orn Granlund. */
+
+ exponent = bits;
+
+ switch (densize)
+ {
+ case 1:
+ {
+ mp_limb_t d, n, quot;
+ int used = 0;
+
+ n = num[0];
+ d = den[0];
+ assert (numsize == 1 && n < d);
+
+ do
+ {
+ udiv_qrnnd (quot, n, n, 0, d);
+
+#define got_limb \
+ if (bits == 0) \
+ { \
+ register int cnt; \
+ if (quot == 0) \
+ cnt = BITS_PER_MP_LIMB; \
+ else \
+ count_leading_zeros (cnt, quot); \
+ exponent -= cnt; \
+ if (BITS_PER_MP_LIMB - cnt > MANT_DIG) \
+ { \
+ used = MANT_DIG + cnt; \
+ retval[0] = quot >> (BITS_PER_MP_LIMB - used); \
+ bits = MANT_DIG + 1; \
+ } \
+ else \
+ { \
+ /* Note that we only clear the second element. */ \
+ /* The conditional is determined at compile time. */ \
+ if (RETURN_LIMB_SIZE > 1) \
+ retval[1] = 0; \
+ retval[0] = quot; \
+ bits = -cnt; \
+ } \
+ } \
+ else if (bits + BITS_PER_MP_LIMB <= MANT_DIG) \
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, BITS_PER_MP_LIMB, \
+ quot); \
+ else \
+ { \
+ used = MANT_DIG - bits; \
+ if (used > 0) \
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, quot); \
+ } \
+ bits += BITS_PER_MP_LIMB
+
+ got_limb;
+ }
+ while (bits <= MANT_DIG);
+
+ return round_and_return (retval, exponent - 1, negative,
+ quot, BITS_PER_MP_LIMB - 1 - used,
+ more_bits || n != 0);
+ }
+ case 2:
+ {
+ mp_limb_t d0, d1, n0, n1;
+ mp_limb_t quot = 0;
+ int used = 0;
+
+ d0 = den[0];
+ d1 = den[1];
+
+ if (numsize < densize)
+ {
+ if (num[0] >= d1)
+ {
+ /* The numerator of the number occupies fewer bits than
+ the denominator but the one limb is bigger than the
+ high limb of the numerator. */
+ n1 = 0;
+ n0 = num[0];
+ }
+ else
+ {
+ if (bits <= 0)
+ exponent -= BITS_PER_MP_LIMB;
+ else
+ {
+ if (bits + BITS_PER_MP_LIMB <= MANT_DIG)
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE,
+ BITS_PER_MP_LIMB, 0);
+ else
+ {
+ used = MANT_DIG - bits;
+ if (used > 0)
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0);
+ }
+ bits += BITS_PER_MP_LIMB;
+ }
+ n1 = num[0];
+ n0 = 0;
+ }
+ }
+ else
+ {
+ n1 = num[1];
+ n0 = num[0];
+ }
+
+ while (bits <= MANT_DIG)
+ {
+ mp_limb_t r;
+
+ if (n1 == d1)
+ {
+ /* QUOT should be either 111..111 or 111..110. We need
+ special treatment of this rare case as normal division
+ would give overflow. */
+ quot = ~(mp_limb_t) 0;
+
+ r = n0 + d1;
+ if (r < d1) /* Carry in the addition? */
+ {
+ add_ssaaaa (n1, n0, r - d0, 0, 0, d0);
+ goto have_quot;
+ }
+ n1 = d0 - (d0 != 0);
+ n0 = -d0;
+ }
+ else
+ {
+ udiv_qrnnd (quot, r, n1, n0, d1);
+ umul_ppmm (n1, n0, d0, quot);
+ }
+
+ q_test:
+ if (n1 > r || (n1 == r && n0 > 0))
+ {
+ /* The estimated QUOT was too large. */
+ --quot;
+
+ sub_ddmmss (n1, n0, n1, n0, 0, d0);
+ r += d1;
+ if (r >= d1) /* If not carry, test QUOT again. */
+ goto q_test;
+ }
+ sub_ddmmss (n1, n0, r, 0, n1, n0);
+
+ have_quot:
+ got_limb;
+ }
+
+ return round_and_return (retval, exponent - 1, negative,
+ quot, BITS_PER_MP_LIMB - 1 - used,
+ more_bits || n1 != 0 || n0 != 0);
+ }
+ default:
+ {
+ int i;
+ mp_limb_t cy, dX, d1, n0, n1;
+ mp_limb_t quot = 0;
+ int used = 0;
+
+ dX = den[densize - 1];
+ d1 = den[densize - 2];
+
+ /* The division does not work if the upper limb of the two-limb
+ numerator is greater than the denominator. */
+ if (__mpn_cmp (num, &den[densize - numsize], numsize) > 0)
+ num[numsize++] = 0;
+
+ if (numsize < densize)
+ {
+ mp_size_t empty = densize - numsize;
+
+ if (bits <= 0)
+ {
+ register int i;
+ for (i = numsize; i > 0; --i)
+ num[i + empty] = num[i - 1];
+ MPN_ZERO (num, empty + 1);
+ exponent -= empty * BITS_PER_MP_LIMB;
+ }
+ else
+ {
+ if (bits + empty * BITS_PER_MP_LIMB <= MANT_DIG)
+ {
+ /* We make a difference here because the compiler
+ cannot optimize the `else' case that good and
+ this reflects all currently used FLOAT types
+ and GMP implementations. */
+ register int i;
+#if RETURN_LIMB_SIZE <= 2
+ assert (empty == 1);
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE,
+ BITS_PER_MP_LIMB, 0);
+#else
+ for (i = RETURN_LIMB_SIZE; i > empty; --i)
+ retval[i] = retval[i - empty];
+#endif
+ for (i = numsize; i > 0; --i)
+ num[i + empty] = num[i - 1];
+ MPN_ZERO (num, empty + 1);
+ }
+ else
+ {
+ used = MANT_DIG - bits;
+ if (used >= BITS_PER_MP_LIMB)
+ {
+ register int i;
+ (void) __mpn_lshift (&retval[used
+ / BITS_PER_MP_LIMB],
+ retval, RETURN_LIMB_SIZE,
+ used % BITS_PER_MP_LIMB);
+ for (i = used / BITS_PER_MP_LIMB; i >= 0; --i)
+ retval[i] = 0;
+ }
+ else if (used > 0)
+ __mpn_lshift_1 (retval, RETURN_LIMB_SIZE, used, 0);
+ }
+ bits += empty * BITS_PER_MP_LIMB;
+ }
+ }
+ else
+ {
+ int i;
+ assert (numsize == densize);
+ for (i = numsize; i > 0; --i)
+ num[i] = num[i - 1];
+ }
+
+ den[densize] = 0;
+ n0 = num[densize];
+
+ while (bits <= MANT_DIG)
+ {
+ if (n0 == dX)
+ /* This might over-estimate QUOT, but it's probably not
+ worth the extra code here to find out. */
+ quot = ~(mp_limb_t) 0;
+ else
+ {
+ mp_limb_t r;
+
+ udiv_qrnnd (quot, r, n0, num[densize - 1], dX);
+ umul_ppmm (n1, n0, d1, quot);
+
+ while (n1 > r || (n1 == r && n0 > num[densize - 2]))
+ {
+ --quot;
+ r += dX;
+ if (r < dX) /* I.e. "carry in previous addition?" */
+ break;
+ n1 -= n0 < d1;
+ n0 -= d1;
+ }
+ }
+
+ /* Possible optimization: We already have (q * n0) and (1 * n1)
+ after the calculation of QUOT. Taking advantage of this, we
+ could make this loop make two iterations less. */
+
+ cy = __mpn_submul_1 (num, den, densize + 1, quot);
+
+ if (num[densize] != cy)
+ {
+ cy = __mpn_add_n (num, num, den, densize);
+ assert (cy != 0);
+ --quot;
+ }
+ n0 = num[densize] = num[densize - 1];
+ for (i = densize - 1; i > 0; --i)
+ num[i] = num[i - 1];
+
+ got_limb;
+ }
+
+ for (i = densize; num[i] == 0 && i >= 0; --i)
+ ;
+ return round_and_return (retval, exponent - 1, negative,
+ quot, BITS_PER_MP_LIMB - 1 - used,
+ more_bits || i >= 0);
+ }
+ }
+ }
+
+ /* NOTREACHED */
+}
+#if defined _LIBC && !defined USE_WIDE_CHAR
+libc_hidden_def (INTERNAL (__STRTOF))
+#endif
+
+/* External user entry point. */
-weak_alias (__strtod_l, strtod_l)
+FLOAT
+#ifdef weak_function
+weak_function
+#endif
+__STRTOF (nptr, endptr, loc)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ __locale_t loc;
+{
+ return INTERNAL (__STRTOF) (nptr, endptr, 0, loc);
+}
+weak_alias (__STRTOF, STRTOF)
diff --git a/stdlib/strtof.c b/stdlib/strtof.c
index 9d070279f8..b98cb9bfde 100644
--- a/stdlib/strtof.c
+++ b/stdlib/strtof.c
@@ -1,22 +1,35 @@
+/* Read decimal floating point numbers.
+ This file is part of the GNU C Library.
+ Copyright (C) 1995-2002, 2003, 2004 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
/* The actual implementation for all floating point sizes is in strtod.c.
These macros tell it to produce the `float' version, `strtof'. */
#define FLOAT float
#define FLT FLT
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __strtof_l
+#ifdef USE_WIDE_CHAR
+#define STRTOF wcstof
+#define STRTOF_L __wcstof_l
#else
# define STRTOF strtof
+# define STRTOF_L __strtof_l
#endif
-#define MPN2FLOAT __mpn_construct_float
-#define FLOAT_HUGE_VAL HUGE_VALF
-#define SET_MANTISSA(flt, mant) \
- do { union ieee754_float u; \
- u.f = (flt); \
- if ((mant & 0x7fffff) == 0) \
- mant = 0x400000; \
- u.ieee.mantissa = (mant) & 0x7fffff; \
- (flt) = u.f; \
- } while (0)
+
#include "strtod.c"
diff --git a/stdlib/strtof_l.c b/stdlib/strtof_l.c
index 1187ffc73b..bbc7611e1e 100644
--- a/stdlib/strtof_l.c
+++ b/stdlib/strtof_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to float value, using given locale.
- Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Copyright (C) 1997,98,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,14 +18,30 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-
#include <xlocale.h>
extern float ____strtof_l_internal (const char *, char **, int, __locale_t);
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
int, int, __locale_t);
-#include <strtof.c>
-
-weak_alias (__strtof_l, strtof_l)
+#define FLOAT float
+#define FLT FLT
+#ifdef USE_WIDE_CHAR
+# define STRTOF wcstof_l
+# define __STRTOF __wcstof_l
+#else
+# define STRTOF strtof_l
+# define __STRTOF __strtof_l
+#endif
+#define MPN2FLOAT __mpn_construct_float
+#define FLOAT_HUGE_VAL HUGE_VALF
+#define SET_MANTISSA(flt, mant) \
+ do { union ieee754_float u; \
+ u.f = (flt); \
+ if ((mant & 0x7fffff) == 0) \
+ mant = 0x400000; \
+ u.ieee.mantissa = (mant) & 0x7fffff; \
+ (flt) = u.f; \
+ } while (0)
+
+#include "strtod_l.c"
diff --git a/stdlib/strtold.c b/stdlib/strtold.c
new file mode 100644
index 0000000000..0bb227a84f
--- /dev/null
+++ b/stdlib/strtold.c
@@ -0,0 +1,35 @@
+/* Read decimal floating point numbers.
+ This file is part of the GNU C Library.
+ Copyright (C) 1995-2002, 2003, 2004 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* The actual implementation for all floating point sizes is in strtod.c.
+ These macros tell it to produce the `float' version, `strtof'. */
+
+#define FLOAT long double
+#define FLT LDBL
+#ifdef USE_WIDE_CHAR
+# define STRTOF wcstold
+# define STRTOF_L __wcstold_l
+#else
+# define STRTOF strtold
+# define STRTOF_L __strtold_l
+#endif
+
+
+#include "strtod.c"
diff --git a/stdlib/strtold_l.c b/stdlib/strtold_l.c
deleted file mode 100644
index c3a4e79390..0000000000
--- a/stdlib/strtold_l.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Convert string representing a number to float value, using given locale.
- Copyright (C) 1997,98,99,2002 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <math.h>
-#include <xlocale.h>
-
-#ifndef __NO_LONG_DOUBLE_MATH
-
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-
-extern long double ____strtold_l_internal (const char *, char **, int,
- __locale_t);
-extern unsigned long long int ____strtoull_l_internal (const char *, char **,
- int, int, __locale_t);
-
-# include <strtold.c>
-
-#else
-/* There is no `long double' type, use the `double' implementations. */
-extern double ____strtod_l_internal (const char *, char **, int,
- __locale_t);
-long double
-____strtold_l_internal (const char *nptr, char **endptr, int group,
- __locale_t loc)
-{
- return ____strtod_l_internal (nptr, endptr, group, loc);
-}
-
-long double
-__strtold_l (const char *nptr, char **endptr, __locale_t loc)
-{
- return ____strtod_l_internal (nptr, endptr, 0, loc);
-}
-#endif
-
-weak_alias (__strtold_l, strtold_l)
diff --git a/string/strcoll.c b/string/strcoll.c
index 26072018ac..8a73cae564 100644
--- a/string/strcoll.c
+++ b/string/strcoll.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1995-2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
@@ -17,540 +17,24 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <assert.h>
-#include <langinfo.h>
-#include <locale.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
#include <string.h>
#ifndef STRING_TYPE
# define STRING_TYPE char
-# define USTRING_TYPE unsigned char
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRCOLL __strcoll_l
-# else
-# define STRCOLL strcoll
-# endif
-# define STRCMP strcmp
-# define STRLEN strlen
-# define WEIGHT_H "../locale/weight.h"
-# define SUFFIX MB
-# define L(arg) arg
+# define STRCOLL strcoll
+# define STRCOLL_L __strcoll_l
#endif
-#define CONCAT(a,b) CONCAT1(a,b)
-#define CONCAT1(a,b) a##b
-
#include "../locale/localeinfo.h"
-#ifndef USE_IN_EXTENDED_LOCALE_MODEL
+
int
STRCOLL (s1, s2)
const STRING_TYPE *s1;
const STRING_TYPE *s2;
-#else
-int
-STRCOLL (s1, s2, l)
- const STRING_TYPE *s1;
- const STRING_TYPE *s2;
- __locale_t l;
-#endif
{
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
- struct locale_data *current = l->__locales[LC_COLLATE];
- uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
-#else
- uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
-#endif
- /* We don't assign the following values right away since it might be
- unnecessary in case there are no rules. */
- const unsigned char *rulesets;
- const int32_t *table;
- const USTRING_TYPE *weights;
- const USTRING_TYPE *extra;
- const int32_t *indirect;
- uint_fast32_t pass;
- int result = 0;
- const USTRING_TYPE *us1;
- const USTRING_TYPE *us2;
- size_t s1len;
- size_t s2len;
- int32_t *idx1arr;
- int32_t *idx2arr;
- unsigned char *rule1arr;
- unsigned char *rule2arr;
- size_t idx1max;
- size_t idx2max;
- size_t idx1cnt;
- size_t idx2cnt;
- size_t idx1now;
- size_t idx2now;
- size_t backw1_stop;
- size_t backw2_stop;
- size_t backw1;
- size_t backw2;
- int val1;
- int val2;
- int position;
- int seq1len;
- int seq2len;
- int use_malloc;
-
-#include WEIGHT_H
-
- if (nrules == 0)
- return STRCMP (s1, s2);
-
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
- rulesets = (const unsigned char *)
- current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
- table = (const int32_t *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
- weights = (const USTRING_TYPE *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
- extra = (const USTRING_TYPE *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
- indirect = (const int32_t *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
-#else
- rulesets = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_RULESETS);
- table = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_TABLE,SUFFIX));
- weights = (const USTRING_TYPE *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_WEIGHT,SUFFIX));
- extra = (const USTRING_TYPE *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_EXTRA,SUFFIX));
- indirect = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_INDIRECT,SUFFIX));
-#endif
- use_malloc = 0;
-
- assert (((uintptr_t) table) % __alignof__ (table[0]) == 0);
- assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0);
- assert (((uintptr_t) extra) % __alignof__ (extra[0]) == 0);
- assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0);
-
- /* We need this a few times. */
- s1len = STRLEN (s1);
- s2len = STRLEN (s2);
-
- /* Catch empty strings. */
- if (__builtin_expect (s1len == 0, 0) || __builtin_expect (s2len == 0, 0))
- return (s1len != 0) - (s2len != 0);
-
- /* We need the elements of the strings as unsigned values since they
- are used as indeces. */
- us1 = (const USTRING_TYPE *) s1;
- us2 = (const USTRING_TYPE *) s2;
-
- /* Perform the first pass over the string and while doing this find
- and store the weights for each character. Since we want this to
- be as fast as possible we are using `alloca' to store the temporary
- values. But since there is no limit on the length of the string
- we have to use `malloc' if the string is too long. We should be
- very conservative here.
-
- Please note that the localedef programs makes sure that `position'
- is not used at the first level. */
- if (! __libc_use_alloca (s1len + s2len))
- {
- idx1arr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
- idx2arr = &idx1arr[s1len];
- rule1arr = (unsigned char *) &idx2arr[s2len];
- rule2arr = &rule1arr[s1len];
-
- if (idx1arr == NULL)
- /* No memory. Well, go with the stack then.
-
- XXX Once this implementation is stable we will handle this
- differently. Instead of precomputing the indeces we will
- do this in time. This means, though, that this happens for
- every pass again. */
- goto try_stack;
- use_malloc = 1;
- }
- else
- {
- try_stack:
- idx1arr = (int32_t *) alloca (s1len * sizeof (int32_t));
- idx2arr = (int32_t *) alloca (s2len * sizeof (int32_t));
- rule1arr = (unsigned char *) alloca (s1len);
- rule2arr = (unsigned char *) alloca (s2len);
- }
-
- idx1cnt = 0;
- idx2cnt = 0;
- idx1max = 0;
- idx2max = 0;
- idx1now = 0;
- idx2now = 0;
- backw1_stop = ~0ul;
- backw2_stop = ~0ul;
- backw1 = ~0ul;
- backw2 = ~0ul;
- seq1len = 0;
- seq2len = 0;
- position = rulesets[0] & sort_position;
- while (1)
- {
- val1 = 0;
- val2 = 0;
-
- /* Get the next non-IGNOREd element for string `s1'. */
- if (seq1len == 0)
- do
- {
- ++val1;
-
- if (backw1_stop != ~0ul)
- {
- /* The is something pushed. */
- if (backw1 == backw1_stop)
- {
- /* The last pushed character was handled. Continue
- with forward characters. */
- if (idx1cnt < idx1max)
- idx1now = idx1cnt;
- else
- /* Nothing anymore. The backward sequence ended with
- the last sequence in the string. Note that seq1len
- is still zero. */
- break;
- }
- else
- idx1now = --backw1;
- }
- else
- {
- backw1_stop = idx1max;
-
- while (*us1 != L('\0'))
- {
- int32_t tmp = findidx (&us1);
- rule1arr[idx1max] = tmp >> 24;
- idx1arr[idx1max] = tmp & 0xffffff;
- idx1cnt = idx1max++;
-
- if ((rulesets[rule1arr[idx1cnt] * nrules]
- & sort_backward) == 0)
- /* No more backward characters to push. */
- break;
- ++idx1cnt;
- }
-
- if (backw1_stop >= idx1cnt)
- {
- /* No sequence at all or just one. */
- if (idx1cnt == idx1max || backw1_stop > idx1cnt)
- /* Note that seq1len is still zero. */
- break;
-
- backw1_stop = ~0ul;
- idx1now = idx1cnt;
- }
- else
- /* We pushed backward sequences. */
- idx1now = backw1 = idx1cnt - 1;
- }
- }
- while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
-
- /* And the same for string `s2'. */
- if (seq2len == 0)
- do
- {
- ++val2;
-
- if (backw2_stop != ~0ul)
- {
- /* The is something pushed. */
- if (backw2 == backw2_stop)
- {
- /* The last pushed character was handled. Continue
- with forward characters. */
- if (idx2cnt < idx2max)
- idx2now = idx2cnt;
- else
- /* Nothing anymore. The backward sequence ended with
- the last sequence in the string. Note that seq2len
- is still zero. */
- break;
- }
- else
- idx2now = --backw2;
- }
- else
- {
- backw2_stop = idx2max;
-
- while (*us2 != L('\0'))
- {
- int32_t tmp = findidx (&us2);
- rule2arr[idx2max] = tmp >> 24;
- idx2arr[idx2max] = tmp & 0xffffff;
- idx2cnt = idx2max++;
-
- if ((rulesets[rule2arr[idx2cnt] * nrules]
- & sort_backward) == 0)
- /* No more backward characters to push. */
- break;
- ++idx2cnt;
- }
-
- if (backw2_stop >= idx2cnt)
- {
- /* No sequence at all or just one. */
- if (idx2cnt == idx2max || backw2_stop > idx2cnt)
- /* Note that seq1len is still zero. */
- break;
-
- backw2_stop = ~0ul;
- idx2now = idx2cnt;
- }
- else
- /* We pushed backward sequences. */
- idx2now = backw2 = idx2cnt - 1;
- }
- }
- while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
-
- /* See whether any or both strings are empty. */
- if (seq1len == 0 || seq2len == 0)
- {
- if (seq1len == seq2len)
- /* Both ended. So far so good, both strings are equal at the
- first level. */
- break;
-
- /* This means one string is shorter than the other. Find out
- which one and return an appropriate value. */
- result = seq1len == 0 ? -1 : 1;
- goto free_and_return;
- }
-
- /* Test for position if necessary. */
- if (position && val1 != val2)
- {
- result = val1 - val2;
- goto free_and_return;
- }
-
- /* Compare the two sequences. */
- do
- {
- if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
- {
- /* The sequences differ. */
- result = weights[idx1arr[idx1now]] - weights[idx2arr[idx2now]];
- goto free_and_return;
- }
-
- /* Increment the offsets. */
- ++idx1arr[idx1now];
- ++idx2arr[idx2now];
-
- --seq1len;
- --seq2len;
- }
- while (seq1len > 0 && seq2len > 0);
-
- if (position && seq1len != seq2len)
- {
- result = seq1len - seq2len;
- goto free_and_return;
- }
- }
-
- /* Now the remaining passes over the weights. We now use the
- indeces we found before. */
- for (pass = 1; pass < nrules; ++pass)
- {
- /* We assume that if a rule has defined `position' in one section
- this is true for all of them. */
- idx1cnt = 0;
- idx2cnt = 0;
- backw1_stop = ~0ul;
- backw2_stop = ~0ul;
- backw1 = ~0ul;
- backw2 = ~0ul;
- position = rulesets[rule1arr[0] * nrules + pass] & sort_position;
-
- while (1)
- {
- val1 = 0;
- val2 = 0;
-
- /* Get the next non-IGNOREd element for string `s1'. */
- if (seq1len == 0)
- do
- {
- ++val1;
-
- if (backw1_stop != ~0ul)
- {
- /* The is something pushed. */
- if (backw1 == backw1_stop)
- {
- /* The last pushed character was handled. Continue
- with forward characters. */
- if (idx1cnt < idx1max)
- idx1now = idx1cnt;
- else
- {
- /* Nothing anymore. The backward sequence
- ended with the last sequence in the string. */
- idx1now = ~0ul;
- break;
- }
- }
- else
- idx1now = --backw1;
- }
- else
- {
- backw1_stop = idx1cnt;
-
- while (idx1cnt < idx1max)
- {
- if ((rulesets[rule1arr[idx1cnt] * nrules + pass]
- & sort_backward) == 0)
- /* No more backward characters to push. */
- break;
- ++idx1cnt;
- }
-
- if (backw1_stop == idx1cnt)
- {
- /* No sequence at all or just one. */
- if (idx1cnt == idx1max)
- /* Note that seq1len is still zero. */
- break;
-
- backw1_stop = ~0ul;
- idx1now = idx1cnt++;
- }
- else
- /* We pushed backward sequences. */
- idx1now = backw1 = idx1cnt - 1;
- }
- }
- while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
-
- /* And the same for string `s2'. */
- if (seq2len == 0)
- do
- {
- ++val2;
-
- if (backw2_stop != ~0ul)
- {
- /* The is something pushed. */
- if (backw2 == backw2_stop)
- {
- /* The last pushed character was handled. Continue
- with forward characters. */
- if (idx2cnt < idx2max)
- idx2now = idx2cnt;
- else
- {
- /* Nothing anymore. The backward sequence
- ended with the last sequence in the string. */
- idx2now = ~0ul;
- break;
- }
- }
- else
- idx2now = --backw2;
- }
- else
- {
- backw2_stop = idx2cnt;
-
- while (idx2cnt < idx2max)
- {
- if ((rulesets[rule2arr[idx2cnt] * nrules + pass]
- & sort_backward) == 0)
- /* No more backward characters to push. */
- break;
- ++idx2cnt;
- }
-
- if (backw2_stop == idx2cnt)
- {
- /* No sequence at all or just one. */
- if (idx2cnt == idx2max)
- /* Note that seq2len is still zero. */
- break;
-
- backw2_stop = ~0ul;
- idx2now = idx2cnt++;
- }
- else
- /* We pushed backward sequences. */
- idx2now = backw2 = idx2cnt - 1;
- }
- }
- while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
-
- /* See whether any or both strings are empty. */
- if (seq1len == 0 || seq2len == 0)
- {
- if (seq1len == seq2len)
- /* Both ended. So far so good, both strings are equal
- at this level. */
- break;
-
- /* This means one string is shorter than the other. Find out
- which one and return an appropriate value. */
- result = seq1len == 0 ? -1 : 1;
- goto free_and_return;
- }
-
- /* Test for position if necessary. */
- if (position && val1 != val2)
- {
- result = val1 - val2;
- goto free_and_return;
- }
-
- /* Compare the two sequences. */
- do
- {
- if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
- {
- /* The sequences differ. */
- result = (weights[idx1arr[idx1now]]
- - weights[idx2arr[idx2now]]);
- goto free_and_return;
- }
-
- /* Increment the offsets. */
- ++idx1arr[idx1now];
- ++idx2arr[idx2now];
-
- --seq1len;
- --seq2len;
- }
- while (seq1len > 0 && seq2len > 0);
-
- if (position && seq1len != seq2len)
- {
- result = seq1len - seq2len;
- goto free_and_return;
- }
- }
- }
-
- /* Free the memory if needed. */
- free_and_return:
- if (use_malloc)
- free (idx1arr);
-
- return result;
+ return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE);
}
-#if !defined WIDE_CHAR_VERSION && !defined USE_IN_EXTENDED_LOCALE_MODEL
+#if !defined WIDE_CHAR_VERSION
libc_hidden_def (strcoll)
#endif
diff --git a/string/strcoll_l.c b/string/strcoll_l.c
index 6611589ed0..c46921dcc9 100644
--- a/string/strcoll_l.c
+++ b/string/strcoll_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1995,96,97,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
@@ -17,7 +17,515 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <strcoll.c>
+#include <assert.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef STRING_TYPE
+# define STRING_TYPE char
+# define USTRING_TYPE unsigned char
+# define STRCOLL __strcoll_l
+# define STRCMP strcmp
+# define STRLEN strlen
+# define WEIGHT_H "../locale/weight.h"
+# define SUFFIX MB
+# define L(arg) arg
+#endif
+
+#define CONCAT(a,b) CONCAT1(a,b)
+#define CONCAT1(a,b) a##b
+
+#include "../locale/localeinfo.h"
+
+int
+STRCOLL (s1, s2, l)
+ const STRING_TYPE *s1;
+ const STRING_TYPE *s2;
+ __locale_t l;
+{
+ struct locale_data *current = l->__locales[LC_COLLATE];
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+ const int32_t *table;
+ const USTRING_TYPE *weights;
+ const USTRING_TYPE *extra;
+ const int32_t *indirect;
+ uint_fast32_t pass;
+ int result = 0;
+ const USTRING_TYPE *us1;
+ const USTRING_TYPE *us2;
+ size_t s1len;
+ size_t s2len;
+ int32_t *idx1arr;
+ int32_t *idx2arr;
+ unsigned char *rule1arr;
+ unsigned char *rule2arr;
+ size_t idx1max;
+ size_t idx2max;
+ size_t idx1cnt;
+ size_t idx2cnt;
+ size_t idx1now;
+ size_t idx2now;
+ size_t backw1_stop;
+ size_t backw2_stop;
+ size_t backw1;
+ size_t backw2;
+ int val1;
+ int val2;
+ int position;
+ int seq1len;
+ int seq2len;
+ int use_malloc;
+
+#include WEIGHT_H
+
+ if (nrules == 0)
+ return STRCMP (s1, s2);
+
+ rulesets = (const unsigned char *)
+ current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
+ table = (const int32_t *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
+ weights = (const USTRING_TYPE *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
+ extra = (const USTRING_TYPE *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
+ indirect = (const int32_t *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
+ use_malloc = 0;
+
+ assert (((uintptr_t) table) % __alignof__ (table[0]) == 0);
+ assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0);
+ assert (((uintptr_t) extra) % __alignof__ (extra[0]) == 0);
+ assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0);
+
+ /* We need this a few times. */
+ s1len = STRLEN (s1);
+ s2len = STRLEN (s2);
+
+ /* Catch empty strings. */
+ if (__builtin_expect (s1len == 0, 0) || __builtin_expect (s2len == 0, 0))
+ return (s1len != 0) - (s2len != 0);
+
+ /* We need the elements of the strings as unsigned values since they
+ are used as indeces. */
+ us1 = (const USTRING_TYPE *) s1;
+ us2 = (const USTRING_TYPE *) s2;
+
+ /* Perform the first pass over the string and while doing this find
+ and store the weights for each character. Since we want this to
+ be as fast as possible we are using `alloca' to store the temporary
+ values. But since there is no limit on the length of the string
+ we have to use `malloc' if the string is too long. We should be
+ very conservative here.
+
+ Please note that the localedef programs makes sure that `position'
+ is not used at the first level. */
+ if (! __libc_use_alloca (s1len + s2len))
+ {
+ idx1arr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
+ idx2arr = &idx1arr[s1len];
+ rule1arr = (unsigned char *) &idx2arr[s2len];
+ rule2arr = &rule1arr[s1len];
+
+ if (idx1arr == NULL)
+ /* No memory. Well, go with the stack then.
+
+ XXX Once this implementation is stable we will handle this
+ differently. Instead of precomputing the indeces we will
+ do this in time. This means, though, that this happens for
+ every pass again. */
+ goto try_stack;
+ use_malloc = 1;
+ }
+ else
+ {
+ try_stack:
+ idx1arr = (int32_t *) alloca (s1len * sizeof (int32_t));
+ idx2arr = (int32_t *) alloca (s2len * sizeof (int32_t));
+ rule1arr = (unsigned char *) alloca (s1len);
+ rule2arr = (unsigned char *) alloca (s2len);
+ }
+
+ idx1cnt = 0;
+ idx2cnt = 0;
+ idx1max = 0;
+ idx2max = 0;
+ idx1now = 0;
+ idx2now = 0;
+ backw1_stop = ~0ul;
+ backw2_stop = ~0ul;
+ backw1 = ~0ul;
+ backw2 = ~0ul;
+ seq1len = 0;
+ seq2len = 0;
+ position = rulesets[0] & sort_position;
+ while (1)
+ {
+ val1 = 0;
+ val2 = 0;
+
+ /* Get the next non-IGNOREd element for string `s1'. */
+ if (seq1len == 0)
+ do
+ {
+ ++val1;
+
+ if (backw1_stop != ~0ul)
+ {
+ /* The is something pushed. */
+ if (backw1 == backw1_stop)
+ {
+ /* The last pushed character was handled. Continue
+ with forward characters. */
+ if (idx1cnt < idx1max)
+ idx1now = idx1cnt;
+ else
+ /* Nothing anymore. The backward sequence ended with
+ the last sequence in the string. Note that seq1len
+ is still zero. */
+ break;
+ }
+ else
+ idx1now = --backw1;
+ }
+ else
+ {
+ backw1_stop = idx1max;
+
+ while (*us1 != L('\0'))
+ {
+ int32_t tmp = findidx (&us1);
+ rule1arr[idx1max] = tmp >> 24;
+ idx1arr[idx1max] = tmp & 0xffffff;
+ idx1cnt = idx1max++;
+
+ if ((rulesets[rule1arr[idx1cnt] * nrules]
+ & sort_backward) == 0)
+ /* No more backward characters to push. */
+ break;
+ ++idx1cnt;
+ }
+
+ if (backw1_stop >= idx1cnt)
+ {
+ /* No sequence at all or just one. */
+ if (idx1cnt == idx1max || backw1_stop > idx1cnt)
+ /* Note that seq1len is still zero. */
+ break;
+
+ backw1_stop = ~0ul;
+ idx1now = idx1cnt;
+ }
+ else
+ /* We pushed backward sequences. */
+ idx1now = backw1 = idx1cnt - 1;
+ }
+ }
+ while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
+
+ /* And the same for string `s2'. */
+ if (seq2len == 0)
+ do
+ {
+ ++val2;
+
+ if (backw2_stop != ~0ul)
+ {
+ /* The is something pushed. */
+ if (backw2 == backw2_stop)
+ {
+ /* The last pushed character was handled. Continue
+ with forward characters. */
+ if (idx2cnt < idx2max)
+ idx2now = idx2cnt;
+ else
+ /* Nothing anymore. The backward sequence ended with
+ the last sequence in the string. Note that seq2len
+ is still zero. */
+ break;
+ }
+ else
+ idx2now = --backw2;
+ }
+ else
+ {
+ backw2_stop = idx2max;
+
+ while (*us2 != L('\0'))
+ {
+ int32_t tmp = findidx (&us2);
+ rule2arr[idx2max] = tmp >> 24;
+ idx2arr[idx2max] = tmp & 0xffffff;
+ idx2cnt = idx2max++;
+
+ if ((rulesets[rule2arr[idx2cnt] * nrules]
+ & sort_backward) == 0)
+ /* No more backward characters to push. */
+ break;
+ ++idx2cnt;
+ }
+
+ if (backw2_stop >= idx2cnt)
+ {
+ /* No sequence at all or just one. */
+ if (idx2cnt == idx2max || backw2_stop > idx2cnt)
+ /* Note that seq1len is still zero. */
+ break;
+
+ backw2_stop = ~0ul;
+ idx2now = idx2cnt;
+ }
+ else
+ /* We pushed backward sequences. */
+ idx2now = backw2 = idx2cnt - 1;
+ }
+ }
+ while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
+
+ /* See whether any or both strings are empty. */
+ if (seq1len == 0 || seq2len == 0)
+ {
+ if (seq1len == seq2len)
+ /* Both ended. So far so good, both strings are equal at the
+ first level. */
+ break;
+
+ /* This means one string is shorter than the other. Find out
+ which one and return an appropriate value. */
+ result = seq1len == 0 ? -1 : 1;
+ goto free_and_return;
+ }
+
+ /* Test for position if necessary. */
+ if (position && val1 != val2)
+ {
+ result = val1 - val2;
+ goto free_and_return;
+ }
+
+ /* Compare the two sequences. */
+ do
+ {
+ if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
+ {
+ /* The sequences differ. */
+ result = weights[idx1arr[idx1now]] - weights[idx2arr[idx2now]];
+ goto free_and_return;
+ }
+
+ /* Increment the offsets. */
+ ++idx1arr[idx1now];
+ ++idx2arr[idx2now];
+
+ --seq1len;
+ --seq2len;
+ }
+ while (seq1len > 0 && seq2len > 0);
+
+ if (position && seq1len != seq2len)
+ {
+ result = seq1len - seq2len;
+ goto free_and_return;
+ }
+ }
+
+ /* Now the remaining passes over the weights. We now use the
+ indeces we found before. */
+ for (pass = 1; pass < nrules; ++pass)
+ {
+ /* We assume that if a rule has defined `position' in one section
+ this is true for all of them. */
+ idx1cnt = 0;
+ idx2cnt = 0;
+ backw1_stop = ~0ul;
+ backw2_stop = ~0ul;
+ backw1 = ~0ul;
+ backw2 = ~0ul;
+ position = rulesets[rule1arr[0] * nrules + pass] & sort_position;
+
+ while (1)
+ {
+ val1 = 0;
+ val2 = 0;
+
+ /* Get the next non-IGNOREd element for string `s1'. */
+ if (seq1len == 0)
+ do
+ {
+ ++val1;
+
+ if (backw1_stop != ~0ul)
+ {
+ /* The is something pushed. */
+ if (backw1 == backw1_stop)
+ {
+ /* The last pushed character was handled. Continue
+ with forward characters. */
+ if (idx1cnt < idx1max)
+ idx1now = idx1cnt;
+ else
+ {
+ /* Nothing anymore. The backward sequence
+ ended with the last sequence in the string. */
+ idx1now = ~0ul;
+ break;
+ }
+ }
+ else
+ idx1now = --backw1;
+ }
+ else
+ {
+ backw1_stop = idx1cnt;
+
+ while (idx1cnt < idx1max)
+ {
+ if ((rulesets[rule1arr[idx1cnt] * nrules + pass]
+ & sort_backward) == 0)
+ /* No more backward characters to push. */
+ break;
+ ++idx1cnt;
+ }
+
+ if (backw1_stop == idx1cnt)
+ {
+ /* No sequence at all or just one. */
+ if (idx1cnt == idx1max)
+ /* Note that seq1len is still zero. */
+ break;
+
+ backw1_stop = ~0ul;
+ idx1now = idx1cnt++;
+ }
+ else
+ /* We pushed backward sequences. */
+ idx1now = backw1 = idx1cnt - 1;
+ }
+ }
+ while ((seq1len = weights[idx1arr[idx1now]++]) == 0);
+
+ /* And the same for string `s2'. */
+ if (seq2len == 0)
+ do
+ {
+ ++val2;
+
+ if (backw2_stop != ~0ul)
+ {
+ /* The is something pushed. */
+ if (backw2 == backw2_stop)
+ {
+ /* The last pushed character was handled. Continue
+ with forward characters. */
+ if (idx2cnt < idx2max)
+ idx2now = idx2cnt;
+ else
+ {
+ /* Nothing anymore. The backward sequence
+ ended with the last sequence in the string. */
+ idx2now = ~0ul;
+ break;
+ }
+ }
+ else
+ idx2now = --backw2;
+ }
+ else
+ {
+ backw2_stop = idx2cnt;
+
+ while (idx2cnt < idx2max)
+ {
+ if ((rulesets[rule2arr[idx2cnt] * nrules + pass]
+ & sort_backward) == 0)
+ /* No more backward characters to push. */
+ break;
+ ++idx2cnt;
+ }
+
+ if (backw2_stop == idx2cnt)
+ {
+ /* No sequence at all or just one. */
+ if (idx2cnt == idx2max)
+ /* Note that seq2len is still zero. */
+ break;
+
+ backw2_stop = ~0ul;
+ idx2now = idx2cnt++;
+ }
+ else
+ /* We pushed backward sequences. */
+ idx2now = backw2 = idx2cnt - 1;
+ }
+ }
+ while ((seq2len = weights[idx2arr[idx2now]++]) == 0);
+
+ /* See whether any or both strings are empty. */
+ if (seq1len == 0 || seq2len == 0)
+ {
+ if (seq1len == seq2len)
+ /* Both ended. So far so good, both strings are equal
+ at this level. */
+ break;
+
+ /* This means one string is shorter than the other. Find out
+ which one and return an appropriate value. */
+ result = seq1len == 0 ? -1 : 1;
+ goto free_and_return;
+ }
+
+ /* Test for position if necessary. */
+ if (position && val1 != val2)
+ {
+ result = val1 - val2;
+ goto free_and_return;
+ }
+
+ /* Compare the two sequences. */
+ do
+ {
+ if (weights[idx1arr[idx1now]] != weights[idx2arr[idx2now]])
+ {
+ /* The sequences differ. */
+ result = (weights[idx1arr[idx1now]]
+ - weights[idx2arr[idx2now]]);
+ goto free_and_return;
+ }
+
+ /* Increment the offsets. */
+ ++idx1arr[idx1now];
+ ++idx2arr[idx2now];
+
+ --seq1len;
+ --seq2len;
+ }
+ while (seq1len > 0 && seq2len > 0);
+
+ if (position && seq1len != seq2len)
+ {
+ result = seq1len - seq2len;
+ goto free_and_return;
+ }
+ }
+ }
+
+ /* Free the memory if needed. */
+ free_and_return:
+ if (use_malloc)
+ free (idx1arr);
+
+ return result;
+}
+libc_hidden_def (STRCOLL)
+
+#ifndef WIDE_CHAR_VERSION
weak_alias (__strcoll_l, strcoll_l)
+#endif
diff --git a/string/strxfrm.c b/string/strxfrm.c
index 549d68cc1c..840f270675 100644
--- a/string/strxfrm.c
+++ b/string/strxfrm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1995-1999,2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
@@ -17,451 +17,17 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <assert.h>
-#include <langinfo.h>
-#include <locale.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/param.h>
+#include <locale/localeinfo.h>
#ifndef STRING_TYPE
# define STRING_TYPE char
-# define USTRING_TYPE unsigned char
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRXFRM __strxfrm_l
-# else
-# define STRXFRM strxfrm
-# endif
-# define STRCMP strcmp
-# define STRLEN strlen
-# define STPNCPY __stpncpy
-# define WEIGHT_H "../locale/weight.h"
-# define SUFFIX MB
-# define L(arg) arg
+# define STRXFRM strxfrm
+# define STRXFRM_L __strxfrm_l
#endif
-#define CONCAT(a,b) CONCAT1(a,b)
-#define CONCAT1(a,b) a##b
-
-#include "../locale/localeinfo.h"
-
-
-#ifndef WIDE_CHAR_VERSION
-
-/* We need UTF-8 encoding of numbers. */
-static int
-utf8_encode (char *buf, int val)
-{
- int retval;
-
- if (val < 0x80)
- {
- *buf++ = (char) val;
- retval = 1;
- }
- else
- {
- int step;
-
- for (step = 2; step < 6; ++step)
- if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
- break;
- retval = step;
-
- *buf = (unsigned char) (~0xff >> step);
- --step;
- do
- {
- buf[step] = 0x80 | (val & 0x3f);
- val >>= 6;
- }
- while (--step > 0);
- *buf |= val;
- }
-
- return retval;
-}
-#endif
-
-
-#ifndef USE_IN_EXTENDED_LOCALE_MODEL
size_t
STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n)
-#else
-size_t
-STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l)
-#endif
{
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
- struct locale_data *current = l->__locales[LC_COLLATE];
- uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
-#else
- uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
-#endif
- /* We don't assign the following values right away since it might be
- unnecessary in case there are no rules. */
- const unsigned char *rulesets;
- const int32_t *table;
- const USTRING_TYPE *weights;
- const USTRING_TYPE *extra;
- const int32_t *indirect;
- uint_fast32_t pass;
- size_t needed;
- const USTRING_TYPE *usrc;
- size_t srclen = STRLEN (src);
- int32_t *idxarr;
- unsigned char *rulearr;
- size_t idxmax;
- size_t idxcnt;
- int use_malloc;
-
-#include WEIGHT_H
-
- if (nrules == 0)
- {
- if (n != 0)
- STPNCPY (dest, src, MIN (srclen + 1, n));
-
- return srclen;
- }
-
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
- rulesets = (const unsigned char *)
- current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
- table = (const int32_t *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
- weights = (const USTRING_TYPE *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
- extra = (const USTRING_TYPE *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
- indirect = (const int32_t *)
- current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
-#else
- rulesets = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_RULESETS);
- table = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_TABLE,SUFFIX));
- weights = (const USTRING_TYPE *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_WEIGHT,SUFFIX));
- extra = (const USTRING_TYPE *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_EXTRA,SUFFIX));
- indirect = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, CONCAT(_NL_COLLATE_INDIRECT,SUFFIX));
-#endif
- use_malloc = 0;
-
- assert (((uintptr_t) table) % __alignof__ (table[0]) == 0);
- assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0);
- assert (((uintptr_t) extra) % __alignof__ (extra[0]) == 0);
- assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0);
-
- /* Handle an empty string as a special case. */
- if (srclen == 0)
- {
- if (n != 0)
- *dest = L('\0');
- return 0;
- }
-
- /* We need the elements of the string as unsigned values since they
- are used as indeces. */
- usrc = (const USTRING_TYPE *) src;
-
- /* Perform the first pass over the string and while doing this find
- and store the weights for each character. Since we want this to
- be as fast as possible we are using `alloca' to store the temporary
- values. But since there is no limit on the length of the string
- we have to use `malloc' if the string is too long. We should be
- very conservative here. */
- if (! __libc_use_alloca (srclen))
- {
- idxarr = (int32_t *) malloc ((srclen + 1) * (sizeof (int32_t) + 1));
- rulearr = (unsigned char *) &idxarr[srclen];
-
- if (idxarr == NULL)
- /* No memory. Well, go with the stack then.
-
- XXX Once this implementation is stable we will handle this
- differently. Instead of precomputing the indeces we will
- do this in time. This means, though, that this happens for
- every pass again. */
- goto try_stack;
- use_malloc = 1;
- }
- else
- {
- try_stack:
- idxarr = (int32_t *) alloca (srclen * sizeof (int32_t));
- rulearr = (unsigned char *) alloca (srclen + 1);
- }
-
- idxmax = 0;
- do
- {
- int32_t tmp = findidx (&usrc);
- rulearr[idxmax] = tmp >> 24;
- idxarr[idxmax] = tmp & 0xffffff;
-
- ++idxmax;
- }
- while (*usrc != L('\0'));
-
- /* This element is only read, the value never used but to determine
- another value which then is ignored. */
- rulearr[idxmax] = '\0';
-
- /* Now the passes over the weights. We now use the indeces we found
- before. */
- needed = 0;
- for (pass = 0; pass < nrules; ++pass)
- {
- size_t backw_stop = ~0ul;
- int rule = rulesets[rulearr[0] * nrules + pass];
- /* We assume that if a rule has defined `position' in one section
- this is true for all of them. */
- int position = rule & sort_position;
-
- if (position == 0)
- {
- for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
- {
- if ((rule & sort_forward) != 0)
- {
- size_t len;
-
- if (backw_stop != ~0ul)
- {
- /* Handle the pushed elements now. */
- size_t backw;
-
- for (backw = idxcnt - 1; backw >= backw_stop; --backw)
- {
- len = weights[idxarr[backw]++];
-
- if (needed + len < n)
- while (len-- > 0)
- dest[needed++] = weights[idxarr[backw]++];
- else
- {
- /* No more characters fit into the buffer. */
- needed += len;
- idxarr[backw] += len;
- }
- }
-
- backw_stop = ~0ul;
- }
-
- /* Now handle the forward element. */
- len = weights[idxarr[idxcnt]++];
- if (needed + len < n)
- while (len-- > 0)
- dest[needed++] = weights[idxarr[idxcnt]++];
- else
- {
- /* No more characters fit into the buffer. */
- needed += len;
- idxarr[idxcnt] += len;
- }
- }
- else
- {
- /* Remember where the backwards series started. */
- if (backw_stop == ~0ul)
- backw_stop = idxcnt;
- }
-
- rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
- }
-
-
- if (backw_stop != ~0ul)
- {
- /* Handle the pushed elements now. */
- size_t backw;
-
- backw = idxcnt;
- while (backw > backw_stop)
- {
- size_t len = weights[idxarr[--backw]++];
-
- if (needed + len < n)
- while (len-- > 0)
- dest[needed++] = weights[idxarr[backw]++];
- else
- {
- /* No more characters fit into the buffer. */
- needed += len;
- idxarr[backw] += len;
- }
- }
- }
- }
- else
- {
- int val = 1;
-#ifndef WIDE_CHAR_VERSION
- char buf[7];
- size_t buflen;
-#endif
- size_t i;
-
- for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
- {
- if ((rule & sort_forward) != 0)
- {
- size_t len;
-
- if (backw_stop != ~0ul)
- {
- /* Handle the pushed elements now. */
- size_t backw;
-
- for (backw = idxcnt - 1; backw >= backw_stop; --backw)
- {
- len = weights[idxarr[backw]++];
- if (len != 0)
- {
-#ifdef WIDE_CHAR_VERSION
- if (needed + 1 + len < n)
- {
- dest[needed] = val;
- for (i = 0; i < len; ++i)
- dest[needed + 1 + i] =
- weights[idxarr[backw] + i];
- }
- needed += 1 + len;
-#else
- buflen = utf8_encode (buf, val);
- if (needed + buflen + len < n)
- {
- for (i = 0; i < buflen; ++i)
- dest[needed + i] = buf[i];
- for (i = 0; i < len; ++i)
- dest[needed + buflen + i] =
- weights[idxarr[backw] + i];
- }
- needed += buflen + len;
-#endif
- idxarr[backw] += len;
- val = 1;
- }
- else
- ++val;
- }
-
- backw_stop = ~0ul;
- }
-
- /* Now handle the forward element. */
- len = weights[idxarr[idxcnt]++];
- if (len != 0)
- {
-#ifdef WIDE_CHAR_VERSION
- if (needed + 1+ len < n)
- {
- dest[needed] = val;
- for (i = 0; i < len; ++i)
- dest[needed + 1 + i] =
- weights[idxarr[idxcnt] + i];
- }
- needed += 1 + len;
-#else
- buflen = utf8_encode (buf, val);
- if (needed + buflen + len < n)
- {
- for (i = 0; i < buflen; ++i)
- dest[needed + i] = buf[i];
- for (i = 0; i < len; ++i)
- dest[needed + buflen + i] =
- weights[idxarr[idxcnt] + i];
- }
- needed += buflen + len;
-#endif
- idxarr[idxcnt] += len;
- val = 1;
- }
- else
- /* Note that we don't have to increment `idxarr[idxcnt]'
- since the length is zero. */
- ++val;
- }
- else
- {
- /* Remember where the backwards series started. */
- if (backw_stop == ~0ul)
- backw_stop = idxcnt;
- }
-
- rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
- }
-
- if (backw_stop != ~0ul)
- {
- /* Handle the pushed elements now. */
- size_t backw;
-
- backw = idxmax - 1;
- while (backw > backw_stop)
- {
- size_t len = weights[idxarr[--backw]++];
- if (len != 0)
- {
-#ifdef WIDE_CHAR_VERSION
- if (needed + 1 + len < n)
- {
- dest[needed] = val;
- for (i = 0; i < len; ++i)
- dest[needed + 1 + i] =
- weights[idxarr[backw] + i];
- }
- needed += 1 + len;
-#else
- buflen = utf8_encode (buf, val);
- if (needed + buflen + len < n)
- {
- for (i = 0; i < buflen; ++i)
- dest[needed + i] = buf[i];
- for (i = 0; i < len; ++i)
- dest[needed + buflen + i] =
- weights[idxarr[backw] + i];
- }
- needed += buflen + len;
-#endif
- idxarr[backw] += len;
- val = 1;
- }
- else
- ++val;
- }
- }
- }
-
- /* Finally store the byte to separate the passes or terminate
- the string. */
- if (needed < n)
- dest[needed] = pass + 1 < nrules ? L('\1') : L('\0');
- ++needed;
- }
-
- /* This is a little optimization: many collation specifications have
- a `position' rule at the end and if no non-ignored character
- is found the last \1 byte is immediately followed by a \0 byte
- signalling this. We can avoid the \1 byte(s). */
- if (needed <= n && needed > 2 && dest[needed - 2] == L('\1'))
- {
- /* Remove the \1 byte. */
- --needed;
- dest[needed - 1] = L('\0');
- }
-
- /* Free the memory if needed. */
- if (use_malloc)
- free (idxarr);
-
- /* Return the number of bytes/words we need, but don't count the NUL
- byte/word at the end. */
- return needed - 1;
+ return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCALE);
}
diff --git a/string/strxfrm_l.c b/string/strxfrm_l.c
index 264ab9bfe3..44b605168a 100644
--- a/string/strxfrm_l.c
+++ b/string/strxfrm_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1995,96,97,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
@@ -17,7 +17,430 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <strxfrm.c>
+#include <assert.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#ifndef STRING_TYPE
+# define STRING_TYPE char
+# define USTRING_TYPE unsigned char
+# define STRXFRM __strxfrm_l
+# define STRCMP strcmp
+# define STRLEN strlen
+# define STPNCPY __stpncpy
+# define WEIGHT_H "../locale/weight.h"
+# define SUFFIX MB
+# define L(arg) arg
+#endif
+
+#define CONCAT(a,b) CONCAT1(a,b)
+#define CONCAT1(a,b) a##b
+
+#include "../locale/localeinfo.h"
+
+
+#ifndef WIDE_CHAR_VERSION
+
+/* We need UTF-8 encoding of numbers. */
+static int
+utf8_encode (char *buf, int val)
+{
+ int retval;
+
+ if (val < 0x80)
+ {
+ *buf++ = (char) val;
+ retval = 1;
+ }
+ else
+ {
+ int step;
+
+ for (step = 2; step < 6; ++step)
+ if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
+ break;
+ retval = step;
+
+ *buf = (unsigned char) (~0xff >> step);
+ --step;
+ do
+ {
+ buf[step] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ }
+ while (--step > 0);
+ *buf |= val;
+ }
+
+ return retval;
+}
+#endif
+
+
+size_t
+STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l)
+{
+ struct locale_data *current = l->__locales[LC_COLLATE];
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+ const int32_t *table;
+ const USTRING_TYPE *weights;
+ const USTRING_TYPE *extra;
+ const int32_t *indirect;
+ uint_fast32_t pass;
+ size_t needed;
+ const USTRING_TYPE *usrc;
+ size_t srclen = STRLEN (src);
+ int32_t *idxarr;
+ unsigned char *rulearr;
+ size_t idxmax;
+ size_t idxcnt;
+ int use_malloc;
+
+#include WEIGHT_H
+
+ if (nrules == 0)
+ {
+ if (n != 0)
+ STPNCPY (dest, src, MIN (srclen + 1, n));
+
+ return srclen;
+ }
+
+ rulesets = (const unsigned char *)
+ current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
+ table = (const int32_t *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
+ weights = (const USTRING_TYPE *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
+ extra = (const USTRING_TYPE *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
+ indirect = (const int32_t *)
+ current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
+ use_malloc = 0;
+
+ assert (((uintptr_t) table) % __alignof__ (table[0]) == 0);
+ assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0);
+ assert (((uintptr_t) extra) % __alignof__ (extra[0]) == 0);
+ assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0);
+
+ /* Handle an empty string as a special case. */
+ if (srclen == 0)
+ {
+ if (n != 0)
+ *dest = L('\0');
+ return 0;
+ }
+
+ /* We need the elements of the string as unsigned values since they
+ are used as indeces. */
+ usrc = (const USTRING_TYPE *) src;
+
+ /* Perform the first pass over the string and while doing this find
+ and store the weights for each character. Since we want this to
+ be as fast as possible we are using `alloca' to store the temporary
+ values. But since there is no limit on the length of the string
+ we have to use `malloc' if the string is too long. We should be
+ very conservative here. */
+ if (! __libc_use_alloca (srclen))
+ {
+ idxarr = (int32_t *) malloc ((srclen + 1) * (sizeof (int32_t) + 1));
+ rulearr = (unsigned char *) &idxarr[srclen];
+
+ if (idxarr == NULL)
+ /* No memory. Well, go with the stack then.
+
+ XXX Once this implementation is stable we will handle this
+ differently. Instead of precomputing the indeces we will
+ do this in time. This means, though, that this happens for
+ every pass again. */
+ goto try_stack;
+ use_malloc = 1;
+ }
+ else
+ {
+ try_stack:
+ idxarr = (int32_t *) alloca (srclen * sizeof (int32_t));
+ rulearr = (unsigned char *) alloca (srclen + 1);
+ }
+
+ idxmax = 0;
+ do
+ {
+ int32_t tmp = findidx (&usrc);
+ rulearr[idxmax] = tmp >> 24;
+ idxarr[idxmax] = tmp & 0xffffff;
+
+ ++idxmax;
+ }
+ while (*usrc != L('\0'));
+
+ /* This element is only read, the value never used but to determine
+ another value which then is ignored. */
+ rulearr[idxmax] = '\0';
+
+ /* Now the passes over the weights. We now use the indeces we found
+ before. */
+ needed = 0;
+ for (pass = 0; pass < nrules; ++pass)
+ {
+ size_t backw_stop = ~0ul;
+ int rule = rulesets[rulearr[0] * nrules + pass];
+ /* We assume that if a rule has defined `position' in one section
+ this is true for all of them. */
+ int position = rule & sort_position;
+
+ if (position == 0)
+ {
+ for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
+ {
+ if ((rule & sort_forward) != 0)
+ {
+ size_t len;
+
+ if (backw_stop != ~0ul)
+ {
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+ for (backw = idxcnt - 1; backw >= backw_stop; --backw)
+ {
+ len = weights[idxarr[backw]++];
+
+ if (needed + len < n)
+ while (len-- > 0)
+ dest[needed++] = weights[idxarr[backw]++];
+ else
+ {
+ /* No more characters fit into the buffer. */
+ needed += len;
+ idxarr[backw] += len;
+ }
+ }
+
+ backw_stop = ~0ul;
+ }
+
+ /* Now handle the forward element. */
+ len = weights[idxarr[idxcnt]++];
+ if (needed + len < n)
+ while (len-- > 0)
+ dest[needed++] = weights[idxarr[idxcnt]++];
+ else
+ {
+ /* No more characters fit into the buffer. */
+ needed += len;
+ idxarr[idxcnt] += len;
+ }
+ }
+ else
+ {
+ /* Remember where the backwards series started. */
+ if (backw_stop == ~0ul)
+ backw_stop = idxcnt;
+ }
+
+ rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
+ }
+
+
+ if (backw_stop != ~0ul)
+ {
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+ backw = idxcnt;
+ while (backw > backw_stop)
+ {
+ size_t len = weights[idxarr[--backw]++];
+
+ if (needed + len < n)
+ while (len-- > 0)
+ dest[needed++] = weights[idxarr[backw]++];
+ else
+ {
+ /* No more characters fit into the buffer. */
+ needed += len;
+ idxarr[backw] += len;
+ }
+ }
+ }
+ }
+ else
+ {
+ int val = 1;
+#ifndef WIDE_CHAR_VERSION
+ char buf[7];
+ size_t buflen;
+#endif
+ size_t i;
+
+ for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
+ {
+ if ((rule & sort_forward) != 0)
+ {
+ size_t len;
+
+ if (backw_stop != ~0ul)
+ {
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+ for (backw = idxcnt - 1; backw >= backw_stop; --backw)
+ {
+ len = weights[idxarr[backw]++];
+ if (len != 0)
+ {
+#ifdef WIDE_CHAR_VERSION
+ if (needed + 1 + len < n)
+ {
+ dest[needed] = val;
+ for (i = 0; i < len; ++i)
+ dest[needed + 1 + i] =
+ weights[idxarr[backw] + i];
+ }
+ needed += 1 + len;
+#else
+ buflen = utf8_encode (buf, val);
+ if (needed + buflen + len < n)
+ {
+ for (i = 0; i < buflen; ++i)
+ dest[needed + i] = buf[i];
+ for (i = 0; i < len; ++i)
+ dest[needed + buflen + i] =
+ weights[idxarr[backw] + i];
+ }
+ needed += buflen + len;
+#endif
+ idxarr[backw] += len;
+ val = 1;
+ }
+ else
+ ++val;
+ }
+
+ backw_stop = ~0ul;
+ }
+
+ /* Now handle the forward element. */
+ len = weights[idxarr[idxcnt]++];
+ if (len != 0)
+ {
+#ifdef WIDE_CHAR_VERSION
+ if (needed + 1+ len < n)
+ {
+ dest[needed] = val;
+ for (i = 0; i < len; ++i)
+ dest[needed + 1 + i] =
+ weights[idxarr[idxcnt] + i];
+ }
+ needed += 1 + len;
+#else
+ buflen = utf8_encode (buf, val);
+ if (needed + buflen + len < n)
+ {
+ for (i = 0; i < buflen; ++i)
+ dest[needed + i] = buf[i];
+ for (i = 0; i < len; ++i)
+ dest[needed + buflen + i] =
+ weights[idxarr[idxcnt] + i];
+ }
+ needed += buflen + len;
+#endif
+ idxarr[idxcnt] += len;
+ val = 1;
+ }
+ else
+ /* Note that we don't have to increment `idxarr[idxcnt]'
+ since the length is zero. */
+ ++val;
+ }
+ else
+ {
+ /* Remember where the backwards series started. */
+ if (backw_stop == ~0ul)
+ backw_stop = idxcnt;
+ }
+
+ rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
+ }
+
+ if (backw_stop != ~0ul)
+ {
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+ backw = idxmax - 1;
+ while (backw > backw_stop)
+ {
+ size_t len = weights[idxarr[--backw]++];
+ if (len != 0)
+ {
+#ifdef WIDE_CHAR_VERSION
+ if (needed + 1 + len < n)
+ {
+ dest[needed] = val;
+ for (i = 0; i < len; ++i)
+ dest[needed + 1 + i] =
+ weights[idxarr[backw] + i];
+ }
+ needed += 1 + len;
+#else
+ buflen = utf8_encode (buf, val);
+ if (needed + buflen + len < n)
+ {
+ for (i = 0; i < buflen; ++i)
+ dest[needed + i] = buf[i];
+ for (i = 0; i < len; ++i)
+ dest[needed + buflen + i] =
+ weights[idxarr[backw] + i];
+ }
+ needed += buflen + len;
+#endif
+ idxarr[backw] += len;
+ val = 1;
+ }
+ else
+ ++val;
+ }
+ }
+ }
+
+ /* Finally store the byte to separate the passes or terminate
+ the string. */
+ if (needed < n)
+ dest[needed] = pass + 1 < nrules ? L('\1') : L('\0');
+ ++needed;
+ }
+
+ /* This is a little optimization: many collation specifications have
+ a `position' rule at the end and if no non-ignored character
+ is found the last \1 byte is immediately followed by a \0 byte
+ signalling this. We can avoid the \1 byte(s). */
+ if (needed <= n && needed > 2 && dest[needed - 2] == L('\1'))
+ {
+ /* Remove the \1 byte. */
+ --needed;
+ dest[needed - 1] = L('\0');
+ }
+
+ /* Free the memory if needed. */
+ if (use_malloc)
+ free (idxarr);
+
+ /* Return the number of bytes/words we need, but don't count the NUL
+ byte/word at the end. */
+ return needed - 1;
+}
+libc_hidden_def (STRXFRM)
+
+#ifndef WIDE_CHAR_VERSION
weak_alias (__strxfrm_l, strxfrm_l)
+#endif
diff --git a/sysdeps/generic/strtol.c b/sysdeps/generic/strtol.c
index 953c6c4a90..02ec19aabe 100644
--- a/sysdeps/generic/strtol.c
+++ b/sysdeps/generic/strtol.c
@@ -1,5 +1,5 @@
/* Convert string representation of a number into an integer value.
- Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001,2002,2003
+ Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001,2002,2003,2004
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,46 +18,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef _LIBC
-# define USE_NUMBER_GROUPING
-# define STDC_HEADERS
-# define HAVE_LIMITS_H
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-#ifndef __set_errno
-# define __set_errno(Val) errno = (Val)
-#endif
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifdef STDC_HEADERS
-# include <stddef.h>
-# include <stdlib.h>
-# include <string.h>
-# include <locale.h>
-#else
-# ifndef NULL
-# define NULL 0
-# endif
-#endif
-
-#ifdef USE_NUMBER_GROUPING
-# include "../locale/localeinfo.h"
-#endif
+#include <stdlib.h>
+#include <wchar.h>
+#include <locale/localeinfo.h>
-/* Nonzero if we are defining `strtoul' or `strtoull', operating on
- unsigned integers. */
#ifndef UNSIGNED
# define UNSIGNED 0
# define INT LONG int
@@ -65,508 +29,83 @@ extern int errno;
# define INT unsigned LONG int
#endif
-/* Determine the name. */
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# if UNSIGNED
-# ifdef USE_WIDE_CHAR
-# ifdef QUAD
-# define strtol __wcstoull_l
-# else
-# define strtol __wcstoul_l
-# endif
+#if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoull
+# define __strtol_l __wcstoull_l
# else
-# ifdef QUAD
-# define strtol __strtoull_l
-# else
-# define strtol __strtoul_l
-# endif
+# define strtol wcstoul
+# define __strtol_l __wcstoul_l
# endif
# else
-# ifdef USE_WIDE_CHAR
-# ifdef QUAD
-# define strtol __wcstoll_l
-# else
-# define strtol __wcstol_l
-# endif
+# ifdef QUAD
+# define strtol strtoull
+# define __strtol_l __strtoull_l
# else
-# ifdef QUAD
-# define strtol __strtoll_l
-# else
-# define strtol __strtol_l
-# endif
+# define strtol strtoul
+# define __strtol_l __strtoul_l
# endif
# endif
#else
-# if UNSIGNED
-# ifdef USE_WIDE_CHAR
-# ifdef QUAD
-# define strtol wcstoull
-# else
-# define strtol wcstoul
-# endif
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoll
+# define __strtol_l __wcstoll_l
# else
-# ifdef QUAD
-# define strtol strtoull
-# else
-# define strtol strtoul
-# endif
+# define strtol wcstol
+# define __strtol_l __wcstol_l
# endif
# else
-# ifdef USE_WIDE_CHAR
-# ifdef QUAD
-# define strtol wcstoll
-# else
-# define strtol wcstol
-# endif
-# else
-# ifdef QUAD
-# define strtol strtoll
-# endif
+# ifdef QUAD
+# define strtol strtoll
+# define __strtol_l __strtoll_l
# endif
# endif
#endif
+
/* If QUAD is defined, we are defining `strtoll' or `strtoull',
operating on `long long int's. */
#ifdef QUAD
# define LONG long long
-# define STRTOL_LONG_MIN LONG_LONG_MIN
-# define STRTOL_LONG_MAX LONG_LONG_MAX
-# define STRTOL_ULONG_MAX ULONG_LONG_MAX
-# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
- /* Work around gcc bug with using this constant. */
- static const unsigned long long int maxquad = ULONG_LONG_MAX;
-# undef STRTOL_ULONG_MAX
-# define STRTOL_ULONG_MAX maxquad
-# endif
#else
# define LONG long
-
-# ifndef ULONG_MAX
-# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
-# endif
-# ifndef LONG_MAX
-# define LONG_MAX ((long int) (ULONG_MAX >> 1))
-# endif
-# define STRTOL_LONG_MIN LONG_MIN
-# define STRTOL_LONG_MAX LONG_MAX
-# define STRTOL_ULONG_MAX ULONG_MAX
-#endif
-
-
-/* We use this code also for the extended locale handling where the
- function gets as an additional argument the locale which has to be
- used. To access the values we have to redefine the _NL_CURRENT
- macro. */
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# undef _NL_CURRENT
-# define _NL_CURRENT(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].string)
-# define LOCALE_PARAM , loc
-# define LOCALE_PARAM_DECL __locale_t loc;
-#else
-# define LOCALE_PARAM
-# define LOCALE_PARAM_DECL
#endif
-#if defined _LIBC || defined HAVE_WCHAR_H
-# include <wchar.h>
-#endif
#ifdef USE_WIDE_CHAR
-# include <wctype.h>
-# define L_(Ch) L##Ch
-# define UCHAR_TYPE wint_t
# define STRING_TYPE wchar_t
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
-# define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
-# define TOUPPER(Ch) __towupper_l ((Ch), loc)
-# else
-# define ISSPACE(Ch) iswspace (Ch)
-# define ISALPHA(Ch) iswalpha (Ch)
-# define TOUPPER(Ch) towupper (Ch)
-# endif
-# else
-# if defined _LIBC \
- || defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
-# define IN_CTYPE_DOMAIN(c) 1
-# else
-# define IN_CTYPE_DOMAIN(c) isascii(c)
-# endif
-# define L_(Ch) Ch
-# define UCHAR_TYPE unsigned char
-# define STRING_TYPE char
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define ISSPACE(Ch) __isspace_l ((Ch), loc)
-# define ISALPHA(Ch) __isalpha_l ((Ch), loc)
-# define TOUPPER(Ch) __toupper_l ((Ch), loc)
-# else
-# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch))
-# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch))
-# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch))
-# endif
-#endif
-
-#ifdef __STDC__
-# define INTERNAL(X) INTERNAL1(X)
-# define INTERNAL1(X) __##X##_internal
-# define WEAKNAME(X) WEAKNAME1(X)
#else
-# define INTERNAL(X) __/**/X/**/_internal
+# define STRING_TYPE char
#endif
-#ifdef USE_NUMBER_GROUPING
-/* This file defines a function to check for correct grouping. */
-# include "grouping.h"
-#endif
+
+#define INTERNAL(X) INTERNAL1(X)
+#define INTERNAL1(X) __##X##_internal
+extern INT INTERNAL (__strtol_l) (const STRING_TYPE *, STRING_TYPE **, int,
+ int, __locale_t);
-/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
- If BASE is 0 the base is determined by the presence of a leading
- zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
- If BASE is < 2 or > 36, it is reset to 10.
- If ENDPTR is not NULL, a pointer to the character after the last
- one converted is stored in *ENDPTR. */
INT
-INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
+INTERNAL (strtol) (nptr, endptr, base, group)
const STRING_TYPE *nptr;
STRING_TYPE **endptr;
int base;
int group;
- LOCALE_PARAM_DECL
{
- int negative;
- register unsigned LONG int cutoff;
- register unsigned int cutlim;
- register unsigned LONG int i;
- register const STRING_TYPE *s;
- register UCHAR_TYPE c;
- const STRING_TYPE *save, *end;
- int overflow;
-#ifndef USE_WIDE_CHAR
- size_t 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;
- size_t thousands_len = 0;
-# endif
- /* The numeric grouping specification of the current locale,
- in the format described in <locale.h>. */
- const char *grouping;
-
- if (__builtin_expect (group, 0))
- {
- grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
- if (*grouping <= 0 || *grouping == CHAR_MAX)
- grouping = NULL;
- else
- {
- /* Figure out the thousands separator character. */
-# 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
- grouping = NULL;
-#endif
-
- if (base < 0 || base == 1 || base > 36)
- {
- __set_errno (EINVAL);
- return 0;
- }
-
- save = s = nptr;
-
- /* Skip white space. */
- while (ISSPACE (*s))
- ++s;
- if (__builtin_expect (*s == L_('\0'), 0))
- goto noconv;
-
- /* Check for a sign. */
- negative = 0;
- if (*s == L_('-'))
- {
- negative = 1;
- ++s;
- }
- else if (*s == L_('+'))
- ++s;
-
- /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
- if (*s == L_('0'))
- {
- if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
- {
- s += 2;
- base = 16;
- }
- else if (base == 0)
- base = 8;
- }
- else if (base == 0)
- base = 10;
-
- /* Save the pointer so we can check later if anything happened. */
- save = s;
-
-#ifdef USE_NUMBER_GROUPING
- if (base != 10)
- grouping = NULL;
-
- if (__builtin_expect (grouping != NULL, 0))
- {
-# ifndef USE_WIDE_CHAR
- thousands_len = strlen (thousands);
-# endif
-
- /* Find the end of the digit string and check its grouping. */
- end = s;
- if (
-# ifdef USE_WIDE_CHAR
- *s != thousands
-# else
- ({ for (cnt = 0; cnt < thousands_len; ++cnt)
- if (thousands[cnt] != end[cnt])
- break;
- cnt < thousands_len; })
-# endif
- )
- {
- for (c = *end; c != L_('\0'); c = *++end)
- if (((STRING_TYPE) c < L_('0') || (STRING_TYPE) c > L_('9'))
-# ifdef USE_WIDE_CHAR
- && (wchar_t) c != thousands
-# else
- && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
- if (thousands[cnt] != end[cnt])
- break;
- cnt < thousands_len; })
-# endif
- && (!ISALPHA (c)
- || (int) (TOUPPER (c) - L_('A') + 10) >= base))
- break;
-
-# ifdef USE_WIDE_CHAR
- end = __correctly_grouped_prefixwc (s, end, thousands, grouping);
-# else
- end = __correctly_grouped_prefixmb (s, end, thousands, grouping);
-# endif
- }
- }
- else
-#endif
- end = NULL;
-
- cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
- cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
-
- overflow = 0;
- i = 0;
- c = *s;
- if (sizeof (long int) != sizeof (LONG int))
- {
- unsigned long int j = 0;
- unsigned long int jmax = ULONG_MAX / base;
-
- for (;c != L_('\0'); c = *++s)
- {
- if (s == end)
- break;
- if (c >= L_('0') && c <= L_('9'))
- c -= L_('0');
-#ifdef USE_NUMBER_GROUPING
-# ifdef USE_WIDE_CHAR
- else if (grouping && (wchar_t) c == thousands)
- continue;
-# else
- else if (thousands_len)
- {
- for (cnt = 0; cnt < thousands_len; ++cnt)
- if (thousands[cnt] != s[cnt])
- break;
- if (cnt == thousands_len)
- {
- s += thousands_len - 1;
- continue;
- }
- if (ISALPHA (c))
- c = TOUPPER (c) - L_('A') + 10;
- else
- break;
- }
-# endif
-#endif
- else if (ISALPHA (c))
- c = TOUPPER (c) - L_('A') + 10;
- else
- break;
- if ((int) c >= base)
- break;
- /* Note that we never can have an overflow. */
- else if (j >= jmax)
- {
- /* We have an overflow. Now use the long representation. */
- i = (unsigned LONG int) j;
- goto use_long;
- }
- else
- j = j * (unsigned long int) base + c;
- }
-
- i = (unsigned LONG int) j;
- }
- else
- for (;c != L_('\0'); c = *++s)
- {
- if (s == end)
- break;
- if (c >= L_('0') && c <= L_('9'))
- c -= L_('0');
-#ifdef USE_NUMBER_GROUPING
-# ifdef USE_WIDE_CHAR
- else if (grouping && (wchar_t) c == thousands)
- continue;
-# else
- else if (thousands_len)
- {
- for (cnt = 0; cnt < thousands_len; ++cnt)
- if (thousands[cnt] != s[cnt])
- break;
- if (cnt == thousands_len)
- {
- s += thousands_len - 1;
- continue;
- }
- if (ISALPHA (c))
- c = TOUPPER (c) - L_('A') + 10;
- else
- break;
- }
-# endif
-#endif
- else if (ISALPHA (c))
- c = TOUPPER (c) - L_('A') + 10;
- else
- break;
- if ((int) c >= base)
- break;
- /* Check for overflow. */
- if (i > cutoff || (i == cutoff && c > cutlim))
- overflow = 1;
- else
- {
- use_long:
- i *= (unsigned LONG int) base;
- i += c;
- }
- }
-
- /* Check if anything actually happened. */
- if (s == save)
- goto noconv;
-
- /* Store in ENDPTR the address of one character
- past the last character we converted. */
- if (endptr != NULL)
- *endptr = (STRING_TYPE *) s;
-
-#if !UNSIGNED
- /* Check for a value that is within the range of
- `unsigned LONG int', but outside the range of `LONG int'. */
- if (overflow == 0
- && i > (negative
- ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
- : (unsigned LONG int) STRTOL_LONG_MAX))
- overflow = 1;
-#endif
-
- if (__builtin_expect (overflow, 0))
- {
- __set_errno (ERANGE);
-#if UNSIGNED
- return STRTOL_ULONG_MAX;
-#else
- return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
-#endif
- }
-
- /* Return the result of the appropriate sign. */
- return negative ? -i : i;
-
-noconv:
- /* We must handle a special case here: the base is 0 or 16 and the
- first two characters are '0' and 'x', but the rest are no
- hexadecimal digits. This is no error case. We return 0 and
- ENDPTR points to the `x`. */
- if (endptr != NULL)
- {
- if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
- && save[-2] == L_('0'))
- *endptr = (STRING_TYPE *) &save[-1];
- else
- /* There was no number to convert. */
- *endptr = (STRING_TYPE *) nptr;
- }
-
- return 0L;
+ return INTERNAL (__strtol_l) (nptr, endptr, base, group, _NL_CURRENT_LOCALE);
}
-#if defined _LIBC \
- && !(defined USE_IN_EXTENDED_LOCALE_MODEL && defined USE_WIDE_CHAR)
libc_hidden_def (INTERNAL (strtol))
-#endif
-
-/* External user entry point. */
-
-#if _LIBC - 0 == 0
-# undef PARAMS
-# if defined (__STDC__) && __STDC__
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
-
-/* Prototype. */
-INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
-#endif
INT
-#ifdef weak_function
-weak_function
-#endif
-strtol (nptr, endptr, base LOCALE_PARAM)
+strtol (nptr, endptr, base)
const STRING_TYPE *nptr;
STRING_TYPE **endptr;
int base;
- LOCALE_PARAM_DECL
{
- return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
+ return INTERNAL (__strtol_l) (nptr, endptr, base, 0, _NL_CURRENT_LOCALE);
}
diff --git a/sysdeps/generic/strtol_l.c b/sysdeps/generic/strtol_l.c
index e4c3140a03..a3800d6f78 100644
--- a/sysdeps/generic/strtol_l.c
+++ b/sysdeps/generic/strtol_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,13 +18,496 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define USE_NUMBER_GROUPING
+# define STDC_HEADERS
+# define HAVE_LIMITS_H
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
#include <xlocale.h>
-extern long int ____strtol_l_internal (const char *, char **, int, int,
- __locale_t);
+#ifdef USE_NUMBER_GROUPING
+# include "../locale/localeinfo.h"
+#endif
+
+/* Nonzero if we are defining `strtoul' or `strtoull', operating on
+ unsigned integers. */
+#ifndef UNSIGNED
+# define UNSIGNED 0
+# define INT LONG int
+#else
+# define INT unsigned LONG int
+#endif
+
+/* Determine the name. */
+#if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol_l wcstoull_l
+# else
+# define strtol_l wcstoul_l
+# endif
+# else
+# ifdef QUAD
+# define strtol_l strtoull_l
+# else
+# define strtol_l strtoul_l
+# endif
+# endif
+#else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol_l wcstoll_l
+# else
+# define strtol_l wcstol_l
+# endif
+# else
+# ifdef QUAD
+# define strtol_l strtoll_l
+# else
+# define strtol_l strtol_l
+# endif
+# endif
+#endif
+
+#define __strtol_l __strtol_l2(strtol_l)
+#define __strtol_l2(name) __strtol_l3(name)
+#define __strtol_l3(name) __##name
+
+
+/* If QUAD is defined, we are defining `strtoll' or `strtoull',
+ operating on `long long int's. */
+#ifdef QUAD
+# define LONG long long
+# define STRTOL_LONG_MIN LONG_LONG_MIN
+# define STRTOL_LONG_MAX LONG_LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_LONG_MAX
+#else
+# define LONG long
+
+# ifndef ULONG_MAX
+# define ULONG_MAX ((unsigned long int) ~(unsigned long int) 0)
+# endif
+# ifndef LONG_MAX
+# define LONG_MAX ((long int) (ULONG_MAX >> 1))
+# endif
+# define STRTOL_LONG_MIN LONG_MIN
+# define STRTOL_LONG_MAX LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_MAX
+#endif
+
+
+/* We use this code for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT and
+ _NL_CURRENT_WORD macros. */
+#undef _NL_CURRENT
+#define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+#undef _NL_CURRENT_WORD
+#define _NL_CURRENT_WORD(category, item) \
+ ((uint32_t) current->values[_NL_ITEM_INDEX (item)].word)
+
+#if defined _LIBC || defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef USE_WIDE_CHAR
+# include <wctype.h>
+# define L_(Ch) L##Ch
+# define UCHAR_TYPE wint_t
+# define STRING_TYPE wchar_t
+# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
+# define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __towupper_l ((Ch), loc)
+#else
+# if defined _LIBC \
+ || defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+# else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+# endif
+# define L_(Ch) Ch
+# define UCHAR_TYPE unsigned char
+# define STRING_TYPE char
+# define ISSPACE(Ch) __isspace_l ((Ch), loc)
+# define ISALPHA(Ch) __isalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __toupper_l ((Ch), loc)
+#endif
+
+#define INTERNAL(X) INTERNAL1(X)
+#define INTERNAL1(X) __##X##_internal
+#define WEAKNAME(X) WEAKNAME1(X)
+
+#ifdef USE_NUMBER_GROUPING
+/* This file defines a function to check for correct grouping. */
+# include "grouping.h"
+#endif
+
+
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+
+INT
+INTERNAL (__strtol_l) (nptr, endptr, base, group, loc)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ int group;
+ __locale_t loc;
+{
+ int negative;
+ register unsigned LONG int cutoff;
+ register unsigned int cutlim;
+ register unsigned LONG int i;
+ register const STRING_TYPE *s;
+ register UCHAR_TYPE c;
+ const STRING_TYPE *save, *end;
+ int overflow;
+#ifndef USE_WIDE_CHAR
+ size_t cnt;
+#endif
+
+#ifdef USE_NUMBER_GROUPING
+ struct locale_data *current = loc->__locales[LC_NUMERIC];
+ /* The thousands character of the current locale. */
+# ifdef USE_WIDE_CHAR
+ wchar_t thousands = L'\0';
+# else
+ const char *thousands = NULL;
+ size_t thousands_len = 0;
+# endif
+ /* The numeric grouping specification of the current locale,
+ in the format described in <locale.h>. */
+ const char *grouping;
+
+ if (__builtin_expect (group, 0))
+ {
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+ else
+ {
+ /* Figure out the thousands separator character. */
+# 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
+ grouping = NULL;
+#endif
+
+ if (base < 0 || base == 1 || base > 36)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (ISSPACE (*s))
+ ++s;
+ if (__builtin_expect (*s == L_('\0'), 0))
+ goto noconv;
+
+ /* Check for a sign. */
+ negative = 0;
+ if (*s == L_('-'))
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == L_('+'))
+ ++s;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == L_('0'))
+ {
+ if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+#ifdef USE_NUMBER_GROUPING
+ if (base != 10)
+ grouping = NULL;
+
+ if (__builtin_expect (grouping != NULL, 0))
+ {
+# ifndef USE_WIDE_CHAR
+ thousands_len = strlen (thousands);
+# endif
+
+ /* Find the end of the digit string and check its grouping. */
+ end = s;
+ if (
+# ifdef USE_WIDE_CHAR
+ *s != thousands
+# else
+ ({ for (cnt = 0; cnt < thousands_len; ++cnt)
+ if (thousands[cnt] != end[cnt])
+ break;
+ cnt < thousands_len; })
+# endif
+ )
+ {
+ for (c = *end; c != L_('\0'); c = *++end)
+ if (((STRING_TYPE) c < L_('0') || (STRING_TYPE) c > L_('9'))
+# ifdef USE_WIDE_CHAR
+ && (wchar_t) c != thousands
+# else
+ && ({ for (cnt = 0; cnt < thousands_len; ++cnt)
+ if (thousands[cnt] != end[cnt])
+ break;
+ cnt < thousands_len; })
+# endif
+ && (!ISALPHA (c)
+ || (int) (TOUPPER (c) - L_('A') + 10) >= base))
+ break;
+
+# ifdef USE_WIDE_CHAR
+ end = __correctly_grouped_prefixwc (s, end, thousands, grouping);
+# else
+ end = __correctly_grouped_prefixmb (s, end, thousands, grouping);
+# endif
+ }
+ }
+ else
+#endif
+ end = NULL;
+
+ cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
+ cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
+
+ overflow = 0;
+ i = 0;
+ c = *s;
+ if (sizeof (long int) != sizeof (LONG int))
+ {
+ unsigned long int j = 0;
+ unsigned long int jmax = ULONG_MAX / base;
+
+ for (;c != L_('\0'); c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= L_('0') && c <= L_('9'))
+ c -= L_('0');
+#ifdef USE_NUMBER_GROUPING
+# ifdef USE_WIDE_CHAR
+ else if (grouping && (wchar_t) c == thousands)
+ continue;
+# else
+ else if (thousands_len)
+ {
+ for (cnt = 0; cnt < thousands_len; ++cnt)
+ if (thousands[cnt] != s[cnt])
+ break;
+ if (cnt == thousands_len)
+ {
+ s += thousands_len - 1;
+ continue;
+ }
+ if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ }
+# endif
+#endif
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Note that we never can have an overflow. */
+ else if (j >= jmax)
+ {
+ /* We have an overflow. Now use the long representation. */
+ i = (unsigned LONG int) j;
+ goto use_long;
+ }
+ else
+ j = j * (unsigned long int) base + c;
+ }
+
+ i = (unsigned LONG int) j;
+ }
+ else
+ for (;c != L_('\0'); c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= L_('0') && c <= L_('9'))
+ c -= L_('0');
+#ifdef USE_NUMBER_GROUPING
+# ifdef USE_WIDE_CHAR
+ else if (grouping && (wchar_t) c == thousands)
+ continue;
+# else
+ else if (thousands_len)
+ {
+ for (cnt = 0; cnt < thousands_len; ++cnt)
+ if (thousands[cnt] != s[cnt])
+ break;
+ if (cnt == thousands_len)
+ {
+ s += thousands_len - 1;
+ continue;
+ }
+ if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ }
+# endif
+#endif
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ use_long:
+ i *= (unsigned LONG int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *) s;
+
+#if !UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned LONG int', but outside the range of `LONG int'. */
+ if (overflow == 0
+ && i > (negative
+ ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
+ : (unsigned LONG int) STRTOL_LONG_MAX))
+ overflow = 1;
+#endif
+
+ if (__builtin_expect (overflow, 0))
+ {
+ __set_errno (ERANGE);
+#if UNSIGNED
+ return STRTOL_ULONG_MAX;
+#else
+ return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ {
+ if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
+ && save[-2] == L_('0'))
+ *endptr = (STRING_TYPE *) &save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (STRING_TYPE *) nptr;
+ }
+
+ return 0L;
+}
+#if defined _LIBC && !defined USE_WIDE_CHAR
+libc_hidden_def (INTERNAL (__strtol_l))
+#endif
+
+/* External user entry point. */
+
+#if _LIBC - 0 == 0
+# undef PARAMS
+# if defined (__STDC__) && __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+
+/* Prototype. */
+extern INT __strtol_l PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr,
+ int base));
+#endif
-#include "strtol.c"
+INT
+#ifdef weak_function
+weak_function
+#endif
+__strtol_l (nptr, endptr, base, loc)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ __locale_t loc;
+{
+ return INTERNAL (__strtol_l) (nptr, endptr, base, 0, loc);
+}
weak_alias (__strtol_l, strtol_l)
diff --git a/sysdeps/generic/strtold.c b/sysdeps/generic/strtold_l.c
index 7303025eff..e43654700f 100644
--- a/sysdeps/generic/strtold.c
+++ b/sysdeps/generic/strtold_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2004 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
@@ -18,17 +18,23 @@
#include <math.h>
#include <stdlib.h>
+#include <xlocale.h>
+
+
+extern double ____strtod_l_internal (const char *, char **, int, __locale_t);
+
/* There is no `long double' type, use the `double' implementations. */
long double
-__strtold_internal (const char *nptr, char **endptr, int group)
+____strtold_l_internal (const char *nptr, char **endptr, int group,
+ __locale_t loc)
{
- return __strtod_internal (nptr, endptr, group);
+ return ____strtod_l_internal (nptr, endptr, group, loc);
}
-libc_hidden_def (__strtold_internal)
+
long double
-strtold (const char *nptr, char **endptr)
+strtold (const char *nptr, char **endptr, __locale_t loc)
{
- return __strtod_internal (nptr, endptr, 0);
+ return ____strtod_l_internal (nptr, endptr, 0, loc);
}
diff --git a/sysdeps/generic/strtoll_l.c b/sysdeps/generic/strtoll_l.c
index 5e7ae7674c..7725035bd1 100644
--- a/sysdeps/generic/strtoll_l.c
+++ b/sysdeps/generic/strtoll_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,13 +18,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define QUAD 1
#include <xlocale.h>
extern long long int ____strtoll_l_internal (const char *, char **, int, int,
__locale_t);
-#include <strtoll.c>
-
-weak_alias (__strtoll_l, strtoll_l)
+#include <strtol_l.c>
diff --git a/sysdeps/generic/strtoul_l.c b/sysdeps/generic/strtoul_l.c
index a049d2d006..a8b980f48d 100644
--- a/sysdeps/generic/strtoul_l.c
+++ b/sysdeps/generic/strtoul_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,13 +18,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define UNSIGNED 1
#include <xlocale.h>
extern unsigned long int ____strtoul_l_internal (const char *, char **, int,
int, __locale_t);
-#include "strtoul.c"
-
-weak_alias (__strtoul_l, strtoul_l)
+#include "strtol_l.c"
diff --git a/sysdeps/generic/strtoull_l.c b/sysdeps/generic/strtoull_l.c
index 55be504318..68ad0d826e 100644
--- a/sysdeps/generic/strtoull_l.c
+++ b/sysdeps/generic/strtoull_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,13 +18,12 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define QUAD 1
+#define UNSIGNED 1
#include <xlocale.h>
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
int, int, __locale_t);
-#include <strtoull.c>
-
-weak_alias (__strtoull_l, strtoull_l)
+#include <strtol_l.c>
diff --git a/sysdeps/generic/wcstol_l.c b/sysdeps/generic/wcstol_l.c
index 91b0d3fa7d..f1b4171f18 100644
--- a/sysdeps/generic/wcstol_l.c
+++ b/sysdeps/generic/wcstol_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -22,11 +22,9 @@
#include <stddef.h>
#include <locale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define USE_WIDE_CHAR 1
extern long int ____wcstol_l_internal (const wchar_t *, wchar_t **, int, int,
__locale_t);
-#include "wcstol.c"
-
-weak_alias (__wcstol_l, wcstol_l)
+#include "strtol_l.c"
diff --git a/sysdeps/generic/wcstoll_l.c b/sysdeps/generic/wcstoll_l.c
index 9ed2c5aca7..f1a4ca1623 100644
--- a/sysdeps/generic/wcstoll_l.c
+++ b/sysdeps/generic/wcstoll_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -22,11 +22,9 @@
#include <stddef.h>
#include <locale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define QUAD 1
extern long long int ____wcstoll_l_internal (const wchar_t *, wchar_t **,
int, int, __locale_t);
-#include <wcstoll.c>
-
-weak_alias (__wcstoll_l, wcstoll_l)
+#include <wcstol_l.c>
diff --git a/sysdeps/generic/wcstoul_l.c b/sysdeps/generic/wcstoul_l.c
index 9d567bbcc5..eeee1f0baa 100644
--- a/sysdeps/generic/wcstoul_l.c
+++ b/sysdeps/generic/wcstoul_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -22,11 +22,9 @@
#include <stddef.h>
#include <locale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define UNSIGNED 1
extern unsigned long int ____wcstoul_l_internal (const wchar_t *, wchar_t **,
int, int, __locale_t);
-#include <wcstoul.c>
-
-weak_alias (__wcstoul_l, wcstoul_l)
+#include <wcstol_l.c>
diff --git a/sysdeps/generic/wcstoull_l.c b/sysdeps/generic/wcstoull_l.c
index f8f05ba8d8..32bc3c4bb9 100644
--- a/sysdeps/generic/wcstoull_l.c
+++ b/sysdeps/generic/wcstoull_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -22,12 +22,10 @@
#include <stddef.h>
#include <locale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+#define UNSIGNED 1
extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
wchar_t **, int, int,
__locale_t);
-#include <wcstoull.c>
-
-weak_alias (__wcstoull_l, wcstoull_l)
+#include <wcstoll_l.c>
diff --git a/sysdeps/ieee754/ldbl-128/strtold.c b/sysdeps/ieee754/ldbl-128/strtold_l.c
index 45ba361c75..eb227fce61 100644
--- a/sysdeps/ieee754/ldbl-128/strtold.c
+++ b/sysdeps/ieee754/ldbl-128/strtold_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2004 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
@@ -21,16 +21,18 @@
/* The actual implementation for all floating point sizes is in strtod.c.
These macros tell it to produce the `long double' version, `strtold'. */
-# define FLOAT long double
-# define FLT LDBL
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __strtold_l
-# else
-# define STRTOF strtold
-# endif
-# define MPN2FLOAT __mpn_construct_long_double
-# define FLOAT_HUGE_VAL HUGE_VALL
-# define SET_MANTISSA(flt, mant) \
+#define FLOAT long double
+#define FLT LDBL
+#ifdef USE_WIDE_CHAR
+# define STRTOF wcstold_l
+# define __STRTOF __wcstold_l
+#else
+# define STRTOF strtold_l
+# define __STRTOF __strtold_l
+#endif
+#define MPN2FLOAT __mpn_construct_long_double
+#define FLOAT_HUGE_VAL HUGE_VALL
+#define SET_MANTISSA(flt, mant) \
do { union ieee854_long_double u; \
u.d = (flt); \
u.ieee.mantissa0 = 0x8000; \
@@ -40,4 +42,4 @@
(flt) = u.d; \
} while (0)
-# include "strtod.c"
+#include <strtod_l.c>
diff --git a/sysdeps/ieee754/ldbl-96/strtold.c b/sysdeps/ieee754/ldbl-96/strtold_l.c
index c4f395273b..32bf18084b 100644
--- a/sysdeps/ieee754/ldbl-96/strtold.c
+++ b/sysdeps/ieee754/ldbl-96/strtold_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2004 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
@@ -21,16 +21,18 @@
/* The actual implementation for all floating point sizes is in strtod.c.
These macros tell it to produce the `long double' version, `strtold'. */
-# define FLOAT long double
-# define FLT LDBL
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __strtold_l
-# else
-# define STRTOF strtold
-# endif
-# define MPN2FLOAT __mpn_construct_long_double
-# define FLOAT_HUGE_VAL HUGE_VALL
-# define SET_MANTISSA(flt, mant) \
+#define FLOAT long double
+#define FLT LDBL
+#ifdef USE_WIDE_CHAR
+# define STRTOF wcstold_l
+# define __STRTOF __wcstold_l
+#else
+# define STRTOF strtold_l
+# define __STRTOF __strtold_l
+#endif
+#define MPN2FLOAT __mpn_construct_long_double
+#define FLOAT_HUGE_VAL HUGE_VALL
+#define SET_MANTISSA(flt, mant) \
do { union ieee854_long_double u; \
u.d = (flt); \
if ((mant & 0x7fffffffffffffffULL) == 0) \
@@ -40,4 +42,4 @@
(flt) = u.d; \
} while (0)
-# include "strtod.c"
+#include <strtod_l.c>
diff --git a/sysdeps/m68k/strtold.c b/sysdeps/m68k/strtold.c
deleted file mode 100644
index f756488275..0000000000
--- a/sysdeps/m68k/strtold.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define DENORM_EXP (MIN_EXP - 1)
-#include <sysdeps/ieee754/ldbl-96/strtold.c>
diff --git a/sysdeps/m68k/strtold_l.c b/sysdeps/m68k/strtold_l.c
new file mode 100644
index 0000000000..481d9924c2
--- /dev/null
+++ b/sysdeps/m68k/strtold_l.c
@@ -0,0 +1,2 @@
+#define DENORM_EXP (MIN_EXP - 1)
+#include <sysdeps/ieee754/ldbl-96/strtold_l.c>
diff --git a/time/strftime.c b/time/strftime.c
index 04250317e3..5a4917e352 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1999, 2000, 2001, 2002, 2003
+/* Copyright (C) 1991-1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -17,1422 +17,13 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <time.h>
+#include <locale/localeinfo.h>
-#ifdef _LIBC
-# define HAVE_LIMITS_H 1
-# define HAVE_MBLEN 1
-# define HAVE_MBRLEN 1
-# define HAVE_STRUCT_ERA_ENTRY 1
-# define HAVE_TM_GMTOFF 1
-# define HAVE_TM_ZONE 1
-# define HAVE_TZNAME 1
-# define HAVE_TZSET 1
-# define MULTIBYTE_IS_FORMAT_SAFE 1
-# define STDC_HEADERS 1
-# include "../locale/localeinfo.h"
-#endif
-#if defined emacs && !defined HAVE_BCOPY
-# define HAVE_MEMCPY 1
-#endif
-
-#include <ctype.h>
-#include <sys/types.h> /* Some systems define `time_t' here. */
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#if HAVE_TZNAME
-extern char *tzname[];
-#endif
-
-/* Do multibyte processing if multibytes are supported, unless
- multibyte sequences are safe in formats. Multibyte sequences are
- safe if they cannot contain byte sequences that look like format
- conversion specifications. The GNU C Library uses UTF8 multibyte
- encoding, which is safe for formats, but strftime.c can be used
- with other C libraries that use unsafe encodings. */
-#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
-
-#if DO_MULTIBYTE
-# if HAVE_MBRLEN
-# include <wchar.h>
-# else
- /* Simulate mbrlen with mblen as best we can. */
-# define mbstate_t int
-# define mbrlen(s, n, ps) mblen (s, n)
-# define mbsinit(ps) (*(ps) == 0)
-# endif
- static const mbstate_t mbstate_zero;
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#if STDC_HEADERS
-# include <stddef.h>
-# include <stdlib.h>
-# include <string.h>
-#else
-# ifndef HAVE_MEMCPY
-# define memcpy(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
-
-#ifdef COMPILE_WIDE
-# include <endian.h>
-# define CHAR_T wchar_t
-# define UCHAR_T unsigned int
-# define L_(Str) L##Str
-# define NLW(Sym) _NL_W##Sym
-
-# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
-# define STRLEN(s) __wcslen (s)
-
-#else
-# define CHAR_T char
-# define UCHAR_T unsigned char
-# define L_(Str) Str
-# define NLW(Sym) Sym
-
-# if !defined STDC_HEADERS && !defined HAVE_MEMCPY
-# define MEMCPY(d, s, n) bcopy ((s), (d), (n))
-# else
-# define MEMCPY(d, s, n) memcpy ((d), (s), (n))
-# endif
-# define STRLEN(s) strlen (s)
-
-# ifdef _LIBC
-# define MEMPCPY(d, s, n) __mempcpy (d, s, n)
-# else
-# ifndef HAVE_MEMPCPY
-# define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
-# endif
-# endif
-#endif
-
-#ifndef __P
-# if defined __GNUC__ || (defined __STDC__ && __STDC__)
-# define __P(args) args
-# else
-# define __P(args) ()
-# endif /* GCC. */
-#endif /* Not __P. */
-
-#ifndef PTR
-# ifdef __STDC__
-# define PTR void *
-# else
-# define PTR char *
-# endif
-#endif
-
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
-
-#ifndef NULL
-# define NULL 0
-#endif
-
-#define TYPE_SIGNED(t) ((t) -1 < 0)
-
-/* Bound on length of the string representing an integer value of type t.
- Subtract one for the sign bit if t is signed;
- 302 / 1000 is log10 (2) rounded up;
- add one for integer division truncation;
- add one more for a minus sign if t is signed. */
-#define INT_STRLEN_BOUND(t) \
- ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
-
-#define TM_YEAR_BASE 1900
-
-#ifndef __isleap
-/* Nonzero if YEAR is a leap year (every 4 years,
- except every 100th isn't, and every 400th is). */
-# define __isleap(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-#endif
-
-
-#ifdef _LIBC
-# define tzname __tzname
-# define tzset __tzset
-#endif
-
-#if !HAVE_TM_GMTOFF
-/* Portable standalone applications should supply a "time_r.h" that
- declares a POSIX-compliant localtime_r, for the benefit of older
- implementations that lack localtime_r or have a nonstandard one.
- Similarly for gmtime_r. See the gnulib time_r module for one way
- to implement this. */
-# include "time_r.h"
-# undef __gmtime_r
-# undef __localtime_r
-# define __gmtime_r gmtime_r
-# define __localtime_r localtime_r
-#endif
-
-
-#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
-/* Some systems lack the `memset' function and we don't want to
- introduce additional dependencies. */
-/* The SGI compiler reportedly barfs on the trailing null
- if we use a string constant as the initializer. 28 June 1997, rms. */
-static const CHAR_T spaces[16] = /* " " */
-{
- L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
- L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
-};
-static const CHAR_T zeroes[16] = /* "0000000000000000" */
-{
- L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
- L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
-};
-
-# define memset_space(P, Len) \
- do { \
- int _len = (Len); \
- \
- do \
- { \
- int _this = _len > 16 ? 16 : _len; \
- (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
- _len -= _this; \
- } \
- while (_len > 0); \
- } while (0)
-
-# define memset_zero(P, Len) \
- do { \
- int _len = (Len); \
- \
- do \
- { \
- int _this = _len > 16 ? 16 : _len; \
- (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
- _len -= _this; \
- } \
- while (_len > 0); \
- } while (0)
-#else
-# ifdef COMPILE_WIDE
-# define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
-# define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
-# else
-# define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
-# define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
-# endif
-#endif
-
-#define add(n, f) \
- do \
- { \
- int _n = (n); \
- int _delta = width - _n; \
- int _incr = _n + (_delta > 0 ? _delta : 0); \
- if ((size_t) _incr >= maxsize - i) \
- return 0; \
- if (p) \
- { \
- if (_delta > 0) \
- { \
- if (pad == L_('0')) \
- memset_zero (p, _delta); \
- else \
- memset_space (p, _delta); \
- } \
- f; \
- p += _n; \
- } \
- i += _incr; \
- } while (0)
-
-#define cpy(n, s) \
- add ((n), \
- if (to_lowcase) \
- memcpy_lowcase (p, (s), _n LOCALE_ARG); \
- else if (to_uppcase) \
- memcpy_uppcase (p, (s), _n LOCALE_ARG); \
- else \
- MEMCPY ((PTR) p, (const PTR) (s), _n))
-
-#ifdef COMPILE_WIDE
-# ifndef USE_IN_EXTENDED_LOCALE_MODEL
-# undef __mbsrtowcs_l
-# define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
-# endif
-# define widen(os, ws, l) \
- { \
- mbstate_t __st; \
- const char *__s = os; \
- memset (&__st, '\0', sizeof (__st)); \
- l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
- ws = alloca ((l + 1) * sizeof (wchar_t)); \
- (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
- }
-#endif
-
-
-#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
-/* We use this code also for the extended locale handling where the
- function gets as an additional argument the locale which has to be
- used. To access the values we have to redefine the _NL_CURRENT
- macro. */
-# define strftime __strftime_l
-# define wcsftime __wcsftime_l
-# undef _NL_CURRENT
-# define _NL_CURRENT(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].string)
-# define LOCALE_PARAM , loc
-# define LOCALE_ARG , loc
-# define LOCALE_PARAM_DECL __locale_t loc;
-# define LOCALE_PARAM_PROTO , __locale_t loc
-# define HELPER_LOCALE_ARG , current
-#else
-# define LOCALE_PARAM
-# define LOCALE_PARAM_PROTO
-# define LOCALE_ARG
-# define LOCALE_PARAM_DECL
-# ifdef _LIBC
-# define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
-# else
-# define HELPER_LOCALE_ARG
-# endif
-#endif
-
-#ifdef COMPILE_WIDE
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define TOUPPER(Ch, L) __towupper_l (Ch, L)
-# define TOLOWER(Ch, L) __towlower_l (Ch, L)
-# else
-# define TOUPPER(Ch, L) towupper (Ch)
-# define TOLOWER(Ch, L) towlower (Ch)
-# endif
-#else
-# ifdef _LIBC
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define TOUPPER(Ch, L) __toupper_l (Ch, L)
-# define TOLOWER(Ch, L) __tolower_l (Ch, L)
-# else
-# define TOUPPER(Ch, L) toupper (Ch)
-# define TOLOWER(Ch, L) tolower (Ch)
-# endif
-# else
-# define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
-# define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
-# endif
-#endif
-/* We don't use `isdigit' here since the locale dependent
- interpretation is not what we want here. We only need to accept
- the arabic digits in the ASCII range. One day there is perhaps a
- more reliable way to accept other sets of digits. */
-#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
-
-static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
- size_t len LOCALE_PARAM_PROTO));
-
-static CHAR_T *
-memcpy_lowcase (dest, src, len LOCALE_PARAM)
- CHAR_T *dest;
- const CHAR_T *src;
- size_t len;
- LOCALE_PARAM_DECL
-{
- while (len-- > 0)
- dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
- return dest;
-}
-
-static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
- size_t len LOCALE_PARAM_PROTO));
-
-static CHAR_T *
-memcpy_uppcase (dest, src, len LOCALE_PARAM)
- CHAR_T *dest;
- const CHAR_T *src;
- size_t len;
- LOCALE_PARAM_DECL
-{
- while (len-- > 0)
- dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
- return dest;
-}
-
-
-#if ! HAVE_TM_GMTOFF
-/* Yield the difference between *A and *B,
- measured in seconds, ignoring leap seconds. */
-# define tm_diff ftime_tm_diff
-static int tm_diff __P ((const struct tm *, const struct tm *));
-static int
-tm_diff (a, b)
- const struct tm *a;
- const struct tm *b;
-{
- /* Compute intervening leap days correctly even if year is negative.
- Take care to avoid int overflow in leap day calculations,
- but it's OK to assume that A and B are close to each other. */
- int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
- int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
- int a100 = a4 / 25 - (a4 % 25 < 0);
- int b100 = b4 / 25 - (b4 % 25 < 0);
- int a400 = a100 >> 2;
- int b400 = b100 >> 2;
- int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
- int years = a->tm_year - b->tm_year;
- int days = (365 * years + intervening_leap_days
- + (a->tm_yday - b->tm_yday));
- return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
- + (a->tm_min - b->tm_min))
- + (a->tm_sec - b->tm_sec));
-}
-#endif /* ! HAVE_TM_GMTOFF */
-
-
-
-/* The number of days from the first day of the first ISO week of this
- year to the year day YDAY with week day WDAY. ISO weeks start on
- Monday; the first ISO week has the year's first Thursday. YDAY may
- be as small as YDAY_MINIMUM. */
-#define ISO_WEEK_START_WDAY 1 /* Monday */
-#define ISO_WEEK1_WDAY 4 /* Thursday */
-#define YDAY_MINIMUM (-366)
-static int iso_week_days __P ((int, int));
-#ifdef __GNUC__
-__inline__
-#endif
-static int
-iso_week_days (yday, wday)
- int yday;
- int wday;
-{
- /* Add enough to the first operand of % to make it nonnegative. */
- int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
- return (yday
- - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
- + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
-}
-
-
-#if !(defined _NL_CURRENT || HAVE_STRFTIME)
-static CHAR_T const weekday_name[][10] =
- {
- L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
- L_("Thursday"), L_("Friday"), L_("Saturday")
- };
-static CHAR_T const month_name[][10] =
- {
- L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
- L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
- L_("November"), L_("December")
- };
-#endif
-
-
-#ifdef emacs
-# define my_strftime emacs_strftimeu
-# define ut_argument , ut
-# define ut_argument_spec int ut;
-# define ut_argument_spec_iso , int ut
-#else
-# ifdef COMPILE_WIDE
-# define my_strftime wcsftime
-# define nl_get_alt_digit _nl_get_walt_digit
-# else
-# define my_strftime strftime
-# define nl_get_alt_digit _nl_get_alt_digit
-# endif
-# define ut_argument
-# define ut_argument_spec
-# define ut_argument_spec_iso
-/* We don't have this information in general. */
-# define ut 0
-#endif
-
-#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
- /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
- Work around this bug by copying *tp before it might be munged. */
- size_t _strftime_copytm __P ((char *, size_t, const char *,
- const struct tm * ut_argument_spec_iso));
- size_t
- my_strftime (s, maxsize, format, tp ut_argument)
- CHAR_T *s;
- size_t maxsize;
- const CHAR_T *format;
- const struct tm *tp;
- ut_argument_spec
- {
- struct tm tmcopy;
- tmcopy = *tp;
- return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
- }
-# undef my_strftime
-# define my_strftime _strftime_copytm
-#endif
-
-
-/* Write information from TP into S according to the format
- string FORMAT, writing no more that MAXSIZE characters
- (including the terminating '\0') and returning number of
- characters written. If S is NULL, nothing will be written
- anywhere, so to determine how many characters would be
- written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
-size_t
-my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
- CHAR_T *s;
- size_t maxsize;
- const CHAR_T *format;
- const struct tm *tp;
- ut_argument_spec
- LOCALE_PARAM_DECL
-{
-#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
- struct locale_data *const current = loc->__locales[LC_TIME];
-#endif
-
- int hour12 = tp->tm_hour;
-#ifdef _NL_CURRENT
- /* We cannot make the following values variables since we must delay
- the evaluation of these values until really needed since some
- expressions might not be valid in every situation. The `struct tm'
- might be generated by a strptime() call that initialized
- only a few elements. Dereference the pointers only if the format
- requires this. Then it is ok to fail if the pointers are invalid. */
-# define a_wkday \
- ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
-# define f_wkday \
- ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
-# define a_month \
- ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
-# define f_month \
- ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
-# define ampm \
- ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
- ? NLW(PM_STR) : NLW(AM_STR)))
-
-# define aw_len STRLEN (a_wkday)
-# define am_len STRLEN (a_month)
-# define ap_len STRLEN (ampm)
-#else
-# if !HAVE_STRFTIME
-# define f_wkday (weekday_name[tp->tm_wday])
-# define f_month (month_name[tp->tm_mon])
-# define a_wkday f_wkday
-# define a_month f_month
-# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
-
- size_t aw_len = 3;
- size_t am_len = 3;
- size_t ap_len = 2;
-# endif
-#endif
- const char *zone;
- size_t i = 0;
- CHAR_T *p = s;
- const CHAR_T *f;
-#if DO_MULTIBYTE && !defined COMPILE_WIDE
- const char *format_end = NULL;
-#endif
-
- zone = NULL;
-#if HAVE_TM_ZONE
- /* The POSIX test suite assumes that setting
- the environment variable TZ to a new value before calling strftime()
- will influence the result (the %Z format) even if the information in
- TP is computed with a totally different time zone.
- This is bogus: though POSIX allows bad behavior like this,
- POSIX does not require it. Do the right thing instead. */
- zone = (const char *) tp->tm_zone;
-#endif
-#if HAVE_TZNAME
- if (ut)
- {
- if (! (zone && *zone))
- zone = "GMT";
- }
- else
- {
- /* POSIX.1 requires that local time zone information is used as
- though strftime called tzset. */
-# if HAVE_TZSET
- tzset ();
-# endif
- }
-#endif
-
- if (hour12 > 12)
- hour12 -= 12;
- else
- if (hour12 == 0)
- hour12 = 12;
-
- for (f = format; *f != '\0'; ++f)
- {
- int pad = 0; /* Padding for number ('-', '_', or 0). */
- int modifier; /* Field modifier ('E', 'O', or 0). */
- int digits; /* Max digits for numeric format. */
- int number_value; /* Numeric value to be printed. */
- int negative_number; /* 1 if the number is negative. */
- const CHAR_T *subfmt;
- CHAR_T *bufp;
- CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
- ? INT_STRLEN_BOUND (time_t)
- : INT_STRLEN_BOUND (int))];
- int width = -1;
- int to_lowcase = 0;
- int to_uppcase = 0;
- int change_case = 0;
- int format_char;
-
-#if DO_MULTIBYTE && !defined COMPILE_WIDE
- switch (*f)
- {
- case L_('%'):
- break;
-
- case L_('\b'): case L_('\t'): case L_('\n'):
- case L_('\v'): case L_('\f'): case L_('\r'):
- case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
- case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
- case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
- case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
- case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
- case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
- case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
- case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
- case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
- case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
- case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
- case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
- case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
- case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
- case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
- case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
- case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
- case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
- case L_('~'):
- /* The C Standard requires these 98 characters (plus '%') to
- be in the basic execution character set. None of these
- characters can start a multibyte sequence, so they need
- not be analyzed further. */
- add (1, *p = *f);
- continue;
-
- default:
- /* Copy this multibyte sequence until we reach its end, find
- an error, or come back to the initial shift state. */
- {
- mbstate_t mbstate = mbstate_zero;
- size_t len = 0;
- size_t fsize;
-
- if (! format_end)
- format_end = f + strlen (f) + 1;
- fsize = format_end - f;
-
- do
- {
- size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
-
- if (bytes == 0)
- break;
-
- if (bytes == (size_t) -2)
- {
- len += strlen (f + len);
- break;
- }
-
- if (bytes == (size_t) -1)
- {
- len++;
- break;
- }
-
- len += bytes;
- }
- while (! mbsinit (&mbstate));
-
- cpy (len, f);
- f += len - 1;
- continue;
- }
- }
-
-#else /* ! DO_MULTIBYTE */
-
- /* Either multibyte encodings are not supported, they are
- safe for formats, so any non-'%' byte can be copied through,
- or this is the wide character version. */
- if (*f != L_('%'))
- {
- add (1, *p = *f);
- continue;
- }
-
-#endif /* ! DO_MULTIBYTE */
-
- /* Check for flags that can modify a format. */
- while (1)
- {
- switch (*++f)
- {
- /* This influences the number formats. */
- case L_('_'):
- case L_('-'):
- case L_('0'):
- pad = *f;
- continue;
-
- /* This changes textual output. */
- case L_('^'):
- to_uppcase = 1;
- continue;
- case L_('#'):
- change_case = 1;
- continue;
-
- default:
- break;
- }
- break;
- }
-
- /* As a GNU extension we allow to specify the field width. */
- if (ISDIGIT (*f))
- {
- width = 0;
- do
- {
- if (width > INT_MAX / 10
- || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
- /* Avoid overflow. */
- width = INT_MAX;
- else
- {
- width *= 10;
- width += *f - L_('0');
- }
- ++f;
- }
- while (ISDIGIT (*f));
- }
-
- /* Check for modifiers. */
- switch (*f)
- {
- case L_('E'):
- case L_('O'):
- modifier = *f++;
- break;
-
- default:
- modifier = 0;
- break;
- }
-
- /* Now do the specified format. */
- format_char = *f;
- switch (format_char)
- {
-#define DO_NUMBER(d, v) \
- digits = d > width ? d : width; \
- number_value = v; goto do_number
-#define DO_NUMBER_SPACEPAD(d, v) \
- digits = d > width ? d : width; \
- number_value = v; goto do_number_spacepad
-
- case L_('%'):
- if (modifier != 0)
- goto bad_format;
- add (1, *p = *f);
- break;
-
- case L_('a'):
- if (modifier != 0)
- goto bad_format;
- if (change_case)
- {
- to_uppcase = 1;
- to_lowcase = 0;
- }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
- cpy (aw_len, a_wkday);
- break;
-#else
- goto underlying_strftime;
-#endif
-
- case 'A':
- if (modifier != 0)
- goto bad_format;
- if (change_case)
- {
- to_uppcase = 1;
- to_lowcase = 0;
- }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
- cpy (STRLEN (f_wkday), f_wkday);
- break;
-#else
- goto underlying_strftime;
-#endif
-
- case L_('b'):
- case L_('h'):
- if (change_case)
- {
- to_uppcase = 1;
- to_lowcase = 0;
- }
- if (modifier != 0)
- goto bad_format;
-#if defined _NL_CURRENT || !HAVE_STRFTIME
- cpy (am_len, a_month);
- break;
-#else
- goto underlying_strftime;
-#endif
-
- case L_('B'):
- if (modifier != 0)
- goto bad_format;
- if (change_case)
- {
- to_uppcase = 1;
- to_lowcase = 0;
- }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
- cpy (STRLEN (f_month), f_month);
- break;
-#else
- goto underlying_strftime;
-#endif
-
- case L_('c'):
- if (modifier == L_('O'))
- goto bad_format;
-#ifdef _NL_CURRENT
- if (! (modifier == 'E'
- && (*(subfmt =
- (const CHAR_T *) _NL_CURRENT (LC_TIME,
- NLW(ERA_D_T_FMT)))
- != '\0')))
- subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# else
- subfmt = L_("%a %b %e %H:%M:%S %Y");
-# endif
-#endif
-
- subformat:
- {
- CHAR_T *old_start = p;
- size_t len = my_strftime (NULL, (size_t) -1, subfmt,
- tp ut_argument LOCALE_ARG);
- add (len, my_strftime (p, maxsize - i, subfmt,
- tp ut_argument LOCALE_ARG));
-
- if (to_uppcase)
- while (old_start < p)
- {
- *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
- ++old_start;
- }
- }
- break;
-
-#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
- underlying_strftime:
- {
- /* The relevant information is available only via the
- underlying strftime implementation, so use that. */
- char ufmt[4];
- char *u = ufmt;
- char ubuf[1024]; /* enough for any single format in practice */
- size_t len;
- /* Make sure we're calling the actual underlying strftime.
- In some cases, config.h contains something like
- "#define strftime rpl_strftime". */
-# ifdef strftime
-# undef strftime
- size_t strftime ();
-# endif
-
- *u++ = '%';
- if (modifier != 0)
- *u++ = modifier;
- *u++ = format_char;
- *u = '\0';
- len = strftime (ubuf, sizeof ubuf, ufmt, tp);
- if (len == 0 && ubuf[0] != '\0')
- return 0;
- cpy (len, ubuf);
- }
- break;
-#endif
-
- case L_('C'):
- if (modifier == L_('O'))
- goto bad_format;
- if (modifier == L_('E'))
- {
-#if HAVE_STRUCT_ERA_ENTRY
- struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
- if (era)
- {
-# ifdef COMPILE_WIDE
- size_t len = __wcslen (era->era_wname);
- cpy (len, era->era_wname);
-# else
- size_t len = strlen (era->era_name);
- cpy (len, era->era_name);
-# endif
- break;
- }
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# endif
-#endif
- }
-
- {
- int year = tp->tm_year + TM_YEAR_BASE;
- DO_NUMBER (1, year / 100 - (year % 100 < 0));
- }
-
- case L_('x'):
- if (modifier == L_('O'))
- goto bad_format;
-#ifdef _NL_CURRENT
- if (! (modifier == L_('E')
- && (*(subfmt =
- (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
- != L_('\0'))))
- subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
- goto subformat;
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# else
- /* Fall through. */
-# endif
-#endif
- case L_('D'):
- if (modifier != 0)
- goto bad_format;
- subfmt = L_("%m/%d/%y");
- goto subformat;
-
- case L_('d'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, tp->tm_mday);
-
- case L_('e'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER_SPACEPAD (2, tp->tm_mday);
-
- /* All numeric formats set DIGITS and NUMBER_VALUE and then
- jump to one of these two labels. */
-
- do_number_spacepad:
- /* Force `_' flag unless overwritten by `0' or '-' flag. */
- if (pad != L_('0') && pad != L_('-'))
- pad = L_('_');
-
- do_number:
- /* Format the number according to the MODIFIER flag. */
-
- if (modifier == L_('O') && 0 <= number_value)
- {
-#ifdef _NL_CURRENT
- /* Get the locale specific alternate representation of
- the number NUMBER_VALUE. If none exist NULL is returned. */
- const CHAR_T *cp = nl_get_alt_digit (number_value
- HELPER_LOCALE_ARG);
-
- if (cp != NULL)
- {
- size_t digitlen = STRLEN (cp);
- if (digitlen != 0)
- {
- cpy (digitlen, cp);
- break;
- }
- }
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# endif
-#endif
- }
- {
- unsigned int u = number_value;
-
- bufp = buf + sizeof (buf) / sizeof (buf[0]);
- negative_number = number_value < 0;
-
- if (negative_number)
- u = -u;
-
- do
- *--bufp = u % 10 + L_('0');
- while ((u /= 10) != 0);
- }
-
- do_number_sign_and_padding:
- if (negative_number)
- *--bufp = L_('-');
-
- if (pad != L_('-'))
- {
- int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
- - bufp);
-
- if (padding > 0)
- {
- if (pad == L_('_'))
- {
- if ((size_t) padding >= maxsize - i)
- return 0;
-
- if (p)
- memset_space (p, padding);
- i += padding;
- width = width > padding ? width - padding : 0;
- }
- else
- {
- if ((size_t) digits >= maxsize - i)
- return 0;
-
- if (negative_number)
- {
- ++bufp;
-
- if (p)
- *p++ = L_('-');
- ++i;
- }
-
- if (p)
- memset_zero (p, padding);
- i += padding;
- width = 0;
- }
- }
- }
-
- cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
- break;
-
- case L_('F'):
- if (modifier != 0)
- goto bad_format;
- subfmt = L_("%Y-%m-%d");
- goto subformat;
-
- case L_('H'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, tp->tm_hour);
-
- case L_('I'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, hour12);
-
- case L_('k'): /* GNU extension. */
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER_SPACEPAD (2, tp->tm_hour);
-
- case L_('l'): /* GNU extension. */
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER_SPACEPAD (2, hour12);
-
- case L_('j'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (3, 1 + tp->tm_yday);
-
- case L_('M'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, tp->tm_min);
-
- case L_('m'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, tp->tm_mon + 1);
-
- case L_('n'):
- add (1, *p = L_('\n'));
- break;
-
- case L_('P'):
- to_lowcase = 1;
-#if !defined _NL_CURRENT && HAVE_STRFTIME
- format_char = L_('p');
-#endif
- /* FALLTHROUGH */
-
- case L_('p'):
- if (change_case)
- {
- to_uppcase = 0;
- to_lowcase = 1;
- }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
- cpy (ap_len, ampm);
- break;
-#else
- goto underlying_strftime;
-#endif
-
- case L_('R'):
- subfmt = L_("%H:%M");
- goto subformat;
-
- case L_('r'):
-#if !defined _NL_CURRENT && HAVE_STRFTIME
- goto underlying_strftime;
-#else
-# ifdef _NL_CURRENT
- if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
- NLW(T_FMT_AMPM)))
- == L_('\0'))
-# endif
- subfmt = L_("%I:%M:%S %p");
- goto subformat;
-#endif
-
- case L_('S'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, tp->tm_sec);
-
- case L_('s'): /* GNU extension. */
- {
- struct tm ltm;
- time_t t;
-
- ltm = *tp;
- t = mktime (&ltm);
-
- /* Generate string value for T using time_t arithmetic;
- this works even if sizeof (long) < sizeof (time_t). */
-
- bufp = buf + sizeof (buf) / sizeof (buf[0]);
- negative_number = t < 0;
-
- do
- {
- int d = t % 10;
- t /= 10;
-
- if (negative_number)
- {
- d = -d;
-
- /* Adjust if division truncates to minus infinity. */
- if (0 < -1 % 10 && d < 0)
- {
- t++;
- d += 10;
- }
- }
-
- *--bufp = d + L_('0');
- }
- while (t != 0);
-
- digits = 1;
- goto do_number_sign_and_padding;
- }
-
- case L_('X'):
- if (modifier == L_('O'))
- goto bad_format;
-#ifdef _NL_CURRENT
- if (! (modifier == L_('E')
- && (*(subfmt =
- (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
- != L_('\0'))))
- subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
- goto subformat;
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# else
- /* Fall through. */
-# endif
-#endif
- case L_('T'):
- subfmt = L_("%H:%M:%S");
- goto subformat;
-
- case L_('t'):
- add (1, *p = L_('\t'));
- break;
-
- case L_('u'):
- DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
-
- case L_('U'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
-
- case L_('V'):
- case L_('g'):
- case L_('G'):
- if (modifier == L_('E'))
- goto bad_format;
- {
- int year = tp->tm_year + TM_YEAR_BASE;
- int days = iso_week_days (tp->tm_yday, tp->tm_wday);
-
- if (days < 0)
- {
- /* This ISO week belongs to the previous year. */
- year--;
- days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
- tp->tm_wday);
- }
- else
- {
- int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
- tp->tm_wday);
- if (0 <= d)
- {
- /* This ISO week belongs to the next year. */
- year++;
- days = d;
- }
- }
-
- switch (*f)
- {
- case L_('g'):
- DO_NUMBER (2, (year % 100 + 100) % 100);
-
- case L_('G'):
- DO_NUMBER (1, year);
-
- default:
- DO_NUMBER (2, days / 7 + 1);
- }
- }
-
- case L_('W'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
-
- case L_('w'):
- if (modifier == L_('E'))
- goto bad_format;
-
- DO_NUMBER (1, tp->tm_wday);
-
- case L_('Y'):
- if (modifier == 'E')
- {
-#if HAVE_STRUCT_ERA_ENTRY
- struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
- if (era)
- {
-# ifdef COMPILE_WIDE
- subfmt = era->era_wformat;
-# else
- subfmt = era->era_format;
-# endif
- goto subformat;
- }
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# endif
-#endif
- }
- if (modifier == L_('O'))
- goto bad_format;
- else
- DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
-
- case L_('y'):
- if (modifier == L_('E'))
- {
-#if HAVE_STRUCT_ERA_ENTRY
- struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
- if (era)
- {
- int delta = tp->tm_year - era->start_date[0];
- DO_NUMBER (1, (era->offset
- + delta * era->absolute_direction));
- }
-#else
-# if HAVE_STRFTIME
- goto underlying_strftime;
-# endif
-#endif
- }
- DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
-
- case L_('Z'):
- if (change_case)
- {
- to_uppcase = 0;
- to_lowcase = 1;
- }
-
-#if HAVE_TZNAME
- /* The tzset() call might have changed the value. */
- if (!(zone && *zone) && tp->tm_isdst >= 0)
- zone = tzname[tp->tm_isdst];
-#endif
- if (! zone)
- zone = "";
-
-#ifdef COMPILE_WIDE
- {
- /* The zone string is always given in multibyte form. We have
- to transform it first. */
- wchar_t *wczone;
- size_t len;
- widen (zone, wczone, len);
- cpy (len, wczone);
- }
-#else
- cpy (strlen (zone), zone);
-#endif
- break;
-
- case L_('z'):
- if (tp->tm_isdst < 0)
- break;
-
- {
- int diff;
-#if HAVE_TM_GMTOFF
- diff = tp->tm_gmtoff;
-#else
- if (ut)
- diff = 0;
- else
- {
- struct tm gtm;
- struct tm ltm;
- time_t lt;
-
- ltm = *tp;
- lt = mktime (&ltm);
-
- if (lt == (time_t) -1)
- {
- /* mktime returns -1 for errors, but -1 is also a
- valid time_t value. Check whether an error really
- occurred. */
- struct tm tm;
-
- if (! __localtime_r (&lt, &tm)
- || ((ltm.tm_sec ^ tm.tm_sec)
- | (ltm.tm_min ^ tm.tm_min)
- | (ltm.tm_hour ^ tm.tm_hour)
- | (ltm.tm_mday ^ tm.tm_mday)
- | (ltm.tm_mon ^ tm.tm_mon)
- | (ltm.tm_year ^ tm.tm_year)))
- break;
- }
-
- if (! __gmtime_r (&lt, &gtm))
- break;
-
- diff = tm_diff (&ltm, &gtm);
- }
-#endif
-
- if (diff < 0)
- {
- add (1, *p = L_('-'));
- diff = -diff;
- }
- else
- add (1, *p = L_('+'));
-
- diff /= 60;
- DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
- }
-
- case L_('\0'): /* GNU extension: % at end of format. */
- --f;
- /* Fall through. */
- default:
- /* Unknown format; output the format, including the '%',
- since this is most likely the right thing to do if a
- multibyte string has been misparsed. */
- bad_format:
- {
- int flen;
- for (flen = 1; f[1 - flen] != L_('%'); flen++)
- continue;
- cpy (flen, &f[1 - flen]);
- }
- break;
- }
- }
-
- if (p && maxsize != 0)
- *p = L_('\0');
- return i;
-}
-#ifdef _LIBC
-libc_hidden_def (my_strftime)
-#endif
-
-
-#ifdef emacs
-/* For Emacs we have a separate interface which corresponds to the normal
- strftime function and does not have the extra information whether the
- TP arguments comes from a `gmtime' call or not. */
size_t
-emacs_strftime (s, maxsize, format, tp)
- char *s;
- size_t maxsize;
- const char *format;
- const struct tm *tp;
+strftime (char *s, size_t maxsize, const char *format, const struct tm *tp)
{
- return my_strftime (s, maxsize, format, tp, 0);
+ return __strftime_l (s, maxsize, format, tp, _NL_CURRENT_LOCALE);
}
-#endif
+libc_hidden_def (strftime)
diff --git a/time/strftime_l.c b/time/strftime_l.c
index c6ecada4ce..6cae85d32f 100644
--- a/time/strftime_l.c
+++ b/time/strftime_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004 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
@@ -16,7 +16,1427 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <strftime.c>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#ifdef _LIBC
+# define USE_IN_EXTENDED_LOCALE_MODEL 1
+# define HAVE_LIMITS_H 1
+# define HAVE_MBLEN 1
+# define HAVE_MBRLEN 1
+# define HAVE_STRUCT_ERA_ENTRY 1
+# define HAVE_TM_GMTOFF 1
+# define HAVE_TM_ZONE 1
+# define HAVE_TZNAME 1
+# define HAVE_TZSET 1
+# define MULTIBYTE_IS_FORMAT_SAFE 1
+# define STDC_HEADERS 1
+# include "../locale/localeinfo.h"
+#endif
+
+#if defined emacs && !defined HAVE_BCOPY
+# define HAVE_MEMCPY 1
+#endif
+
+#include <ctype.h>
+#include <sys/types.h> /* Some systems define `time_t' here. */
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#if HAVE_TZNAME
+extern char *tzname[];
+#endif
+
+/* Do multibyte processing if multibytes are supported, unless
+ multibyte sequences are safe in formats. Multibyte sequences are
+ safe if they cannot contain byte sequences that look like format
+ conversion specifications. The GNU C Library uses UTF8 multibyte
+ encoding, which is safe for formats, but strftime.c can be used
+ with other C libraries that use unsafe encodings. */
+#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
+
+#if DO_MULTIBYTE
+# if HAVE_MBRLEN
+# include <wchar.h>
+# else
+ /* Simulate mbrlen with mblen as best we can. */
+# define mbstate_t int
+# define mbrlen(s, n, ps) mblen (s, n)
+# define mbsinit(ps) (*(ps) == 0)
+# endif
+ static const mbstate_t mbstate_zero;
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#if STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#ifdef COMPILE_WIDE
+# include <endian.h>
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# define L_(Str) L##Str
+# define NLW(Sym) _NL_W##Sym
+
+# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
+# define STRLEN(s) __wcslen (s)
+
+#else
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define L_(Str) Str
+# define NLW(Sym) Sym
+
+# if !defined STDC_HEADERS && !defined HAVE_MEMCPY
+# define MEMCPY(d, s, n) bcopy ((s), (d), (n))
+# else
+# define MEMCPY(d, s, n) memcpy ((d), (s), (n))
+# endif
+# define STRLEN(s) strlen (s)
+
+# ifdef _LIBC
+# define MEMPCPY(d, s, n) __mempcpy (d, s, n)
+# else
+# ifndef HAVE_MEMPCPY
+# define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
+# endif
+# endif
+#endif
+
+#ifndef __P
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+#ifndef PTR
+# ifdef __STDC__
+# define PTR void *
+# else
+# define PTR char *
+# endif
+#endif
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#define TYPE_SIGNED(t) ((t) -1 < 0)
+
+/* Bound on length of the string representing an integer value of type t.
+ Subtract one for the sign bit if t is signed;
+ 302 / 1000 is log10 (2) rounded up;
+ add one for integer division truncation;
+ add one more for a minus sign if t is signed. */
+#define INT_STRLEN_BOUND(t) \
+ ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
+
+#define TM_YEAR_BASE 1900
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+
+#ifdef _LIBC
+# define tzname __tzname
+# define tzset __tzset
+#endif
+
+#if !HAVE_TM_GMTOFF
+/* Portable standalone applications should supply a "time_r.h" that
+ declares a POSIX-compliant localtime_r, for the benefit of older
+ implementations that lack localtime_r or have a nonstandard one.
+ Similarly for gmtime_r. See the gnulib time_r module for one way
+ to implement this. */
+# include "time_r.h"
+# undef __gmtime_r
+# undef __localtime_r
+# define __gmtime_r gmtime_r
+# define __localtime_r localtime_r
+#endif
+
+
+#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
+/* Some systems lack the `memset' function and we don't want to
+ introduce additional dependencies. */
+/* The SGI compiler reportedly barfs on the trailing null
+ if we use a string constant as the initializer. 28 June 1997, rms. */
+static const CHAR_T spaces[16] = /* " " */
+{
+ L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
+ L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
+};
+static const CHAR_T zeroes[16] = /* "0000000000000000" */
+{
+ L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
+ L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
+};
+
+# define memset_space(P, Len) \
+ do { \
+ int _len = (Len); \
+ \
+ do \
+ { \
+ int _this = _len > 16 ? 16 : _len; \
+ (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
+ _len -= _this; \
+ } \
+ while (_len > 0); \
+ } while (0)
+
+# define memset_zero(P, Len) \
+ do { \
+ int _len = (Len); \
+ \
+ do \
+ { \
+ int _this = _len > 16 ? 16 : _len; \
+ (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
+ _len -= _this; \
+ } \
+ while (_len > 0); \
+ } while (0)
+#else
+# ifdef COMPILE_WIDE
+# define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
+# define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
+# else
+# define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
+# define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
+# endif
+#endif
+
+#define add(n, f) \
+ do \
+ { \
+ int _n = (n); \
+ int _delta = width - _n; \
+ int _incr = _n + (_delta > 0 ? _delta : 0); \
+ if ((size_t) _incr >= maxsize - i) \
+ return 0; \
+ if (p) \
+ { \
+ if (_delta > 0) \
+ { \
+ if (pad == L_('0')) \
+ memset_zero (p, _delta); \
+ else \
+ memset_space (p, _delta); \
+ } \
+ f; \
+ p += _n; \
+ } \
+ i += _incr; \
+ } while (0)
+
+#define cpy(n, s) \
+ add ((n), \
+ if (to_lowcase) \
+ memcpy_lowcase (p, (s), _n LOCALE_ARG); \
+ else if (to_uppcase) \
+ memcpy_uppcase (p, (s), _n LOCALE_ARG); \
+ else \
+ MEMCPY ((PTR) p, (const PTR) (s), _n))
+
+#ifdef COMPILE_WIDE
+# ifndef USE_IN_EXTENDED_LOCALE_MODEL
+# undef __mbsrtowcs_l
+# define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
+# endif
+# define widen(os, ws, l) \
+ { \
+ mbstate_t __st; \
+ const char *__s = os; \
+ memset (&__st, '\0', sizeof (__st)); \
+ l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
+ ws = alloca ((l + 1) * sizeof (wchar_t)); \
+ (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
+ }
+#endif
+
+
+#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+# define strftime __strftime_l
+# define wcsftime __wcsftime_l
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_PARAM , loc
+# define LOCALE_ARG , loc
+# define LOCALE_PARAM_DECL __locale_t loc;
+# define LOCALE_PARAM_PROTO , __locale_t loc
+# define HELPER_LOCALE_ARG , current
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_PROTO
+# define LOCALE_ARG
+# define LOCALE_PARAM_DECL
+# ifdef _LIBC
+# define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
+# else
+# define HELPER_LOCALE_ARG
+# endif
+#endif
+
+#ifdef COMPILE_WIDE
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define TOUPPER(Ch, L) __towupper_l (Ch, L)
+# define TOLOWER(Ch, L) __towlower_l (Ch, L)
+# else
+# define TOUPPER(Ch, L) towupper (Ch)
+# define TOLOWER(Ch, L) towlower (Ch)
+# endif
+#else
+# ifdef _LIBC
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define TOUPPER(Ch, L) __toupper_l (Ch, L)
+# define TOLOWER(Ch, L) __tolower_l (Ch, L)
+# else
+# define TOUPPER(Ch, L) toupper (Ch)
+# define TOLOWER(Ch, L) tolower (Ch)
+# endif
+# else
+# define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
+# define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
+# endif
+#endif
+/* We don't use `isdigit' here since the locale dependent
+ interpretation is not what we want here. We only need to accept
+ the arabic digits in the ASCII range. One day there is perhaps a
+ more reliable way to accept other sets of digits. */
+#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
+
+static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
+ size_t len LOCALE_PARAM_PROTO));
+
+static CHAR_T *
+memcpy_lowcase (dest, src, len LOCALE_PARAM)
+ CHAR_T *dest;
+ const CHAR_T *src;
+ size_t len;
+ LOCALE_PARAM_DECL
+{
+ while (len-- > 0)
+ dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
+ return dest;
+}
+
+static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
+ size_t len LOCALE_PARAM_PROTO));
+
+static CHAR_T *
+memcpy_uppcase (dest, src, len LOCALE_PARAM)
+ CHAR_T *dest;
+ const CHAR_T *src;
+ size_t len;
+ LOCALE_PARAM_DECL
+{
+ while (len-- > 0)
+ dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
+ return dest;
+}
+
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds. */
+# define tm_diff ftime_tm_diff
+static int tm_diff __P ((const struct tm *, const struct tm *));
+static int
+tm_diff (a, b)
+ const struct tm *a;
+ const struct tm *b;
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+ int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+
+
+/* The number of days from the first day of the first ISO week of this
+ year to the year day YDAY with week day WDAY. ISO weeks start on
+ Monday; the first ISO week has the year's first Thursday. YDAY may
+ be as small as YDAY_MINIMUM. */
+#define ISO_WEEK_START_WDAY 1 /* Monday */
+#define ISO_WEEK1_WDAY 4 /* Thursday */
+#define YDAY_MINIMUM (-366)
+static int iso_week_days __P ((int, int));
+#ifdef __GNUC__
+__inline__
+#endif
+static int
+iso_week_days (yday, wday)
+ int yday;
+ int wday;
+{
+ /* Add enough to the first operand of % to make it nonnegative. */
+ int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
+ return (yday
+ - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
+ + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
+}
+
+
+#if !(defined _NL_CURRENT || HAVE_STRFTIME)
+static CHAR_T const weekday_name[][10] =
+ {
+ L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
+ L_("Thursday"), L_("Friday"), L_("Saturday")
+ };
+static CHAR_T const month_name[][10] =
+ {
+ L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
+ L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
+ L_("November"), L_("December")
+ };
+#endif
+
+
+#ifdef emacs
+# define my_strftime emacs_strftimeu
+# define ut_argument , ut
+# define ut_argument_spec int ut;
+# define ut_argument_spec_iso , int ut
+#else
+# ifdef COMPILE_WIDE
+# define my_strftime wcsftime
+# define nl_get_alt_digit _nl_get_walt_digit
+# else
+# define my_strftime strftime
+# define nl_get_alt_digit _nl_get_alt_digit
+# endif
+# define ut_argument
+# define ut_argument_spec
+# define ut_argument_spec_iso
+/* We don't have this information in general. */
+# define ut 0
+#endif
+
+#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
+ /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
+ Work around this bug by copying *tp before it might be munged. */
+ size_t _strftime_copytm __P ((char *, size_t, const char *,
+ const struct tm * ut_argument_spec_iso));
+ size_t
+ my_strftime (s, maxsize, format, tp ut_argument)
+ CHAR_T *s;
+ size_t maxsize;
+ const CHAR_T *format;
+ const struct tm *tp;
+ ut_argument_spec
+ {
+ struct tm tmcopy;
+ tmcopy = *tp;
+ return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
+ }
+# undef my_strftime
+# define my_strftime _strftime_copytm
+#endif
+
+
+/* Write information from TP into S according to the format
+ string FORMAT, writing no more that MAXSIZE characters
+ (including the terminating '\0') and returning number of
+ characters written. If S is NULL, nothing will be written
+ anywhere, so to determine how many characters would be
+ written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
+size_t
+my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
+ CHAR_T *s;
+ size_t maxsize;
+ const CHAR_T *format;
+ const struct tm *tp;
+ ut_argument_spec
+ LOCALE_PARAM_DECL
+{
+#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
+ struct locale_data *const current = loc->__locales[LC_TIME];
+#endif
+
+ int hour12 = tp->tm_hour;
+#ifdef _NL_CURRENT
+ /* We cannot make the following values variables since we must delay
+ the evaluation of these values until really needed since some
+ expressions might not be valid in every situation. The `struct tm'
+ might be generated by a strptime() call that initialized
+ only a few elements. Dereference the pointers only if the format
+ requires this. Then it is ok to fail if the pointers are invalid. */
+# define a_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
+# define f_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
+# define a_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
+# define f_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
+# define ampm \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
+ ? NLW(PM_STR) : NLW(AM_STR)))
+
+# define aw_len STRLEN (a_wkday)
+# define am_len STRLEN (a_month)
+# define ap_len STRLEN (ampm)
+#else
+# if !HAVE_STRFTIME
+# define f_wkday (weekday_name[tp->tm_wday])
+# define f_month (month_name[tp->tm_mon])
+# define a_wkday f_wkday
+# define a_month f_month
+# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
+
+ size_t aw_len = 3;
+ size_t am_len = 3;
+ size_t ap_len = 2;
+# endif
+#endif
+ const char *zone;
+ size_t i = 0;
+ CHAR_T *p = s;
+ const CHAR_T *f;
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ const char *format_end = NULL;
+#endif
+
+ zone = NULL;
+#if HAVE_TM_ZONE
+ /* The POSIX test suite assumes that setting
+ the environment variable TZ to a new value before calling strftime()
+ will influence the result (the %Z format) even if the information in
+ TP is computed with a totally different time zone.
+ This is bogus: though POSIX allows bad behavior like this,
+ POSIX does not require it. Do the right thing instead. */
+ zone = (const char *) tp->tm_zone;
+#endif
+#if HAVE_TZNAME
+ if (ut)
+ {
+ if (! (zone && *zone))
+ zone = "GMT";
+ }
+ else
+ {
+ /* POSIX.1 requires that local time zone information is used as
+ though strftime called tzset. */
+# if HAVE_TZSET
+ tzset ();
+# endif
+ }
+#endif
+
+ if (hour12 > 12)
+ hour12 -= 12;
+ else
+ if (hour12 == 0)
+ hour12 = 12;
+
+ for (f = format; *f != '\0'; ++f)
+ {
+ int pad = 0; /* Padding for number ('-', '_', or 0). */
+ int modifier; /* Field modifier ('E', 'O', or 0). */
+ int digits; /* Max digits for numeric format. */
+ int number_value; /* Numeric value to be printed. */
+ int negative_number; /* 1 if the number is negative. */
+ const CHAR_T *subfmt;
+ CHAR_T *bufp;
+ CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
+ ? INT_STRLEN_BOUND (time_t)
+ : INT_STRLEN_BOUND (int))];
+ int width = -1;
+ int to_lowcase = 0;
+ int to_uppcase = 0;
+ int change_case = 0;
+ int format_char;
+
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ switch (*f)
+ {
+ case L_('%'):
+ break;
+
+ case L_('\b'): case L_('\t'): case L_('\n'):
+ case L_('\v'): case L_('\f'): case L_('\r'):
+ case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
+ case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
+ case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
+ case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
+ case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
+ case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
+ case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
+ case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
+ case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
+ case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
+ case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
+ case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
+ case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
+ case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
+ case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
+ case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
+ case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
+ case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
+ case L_('~'):
+ /* The C Standard requires these 98 characters (plus '%') to
+ be in the basic execution character set. None of these
+ characters can start a multibyte sequence, so they need
+ not be analyzed further. */
+ add (1, *p = *f);
+ continue;
+
+ default:
+ /* Copy this multibyte sequence until we reach its end, find
+ an error, or come back to the initial shift state. */
+ {
+ mbstate_t mbstate = mbstate_zero;
+ size_t len = 0;
+ size_t fsize;
+
+ if (! format_end)
+ format_end = f + strlen (f) + 1;
+ fsize = format_end - f;
+
+ do
+ {
+ size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
+
+ if (bytes == 0)
+ break;
+
+ if (bytes == (size_t) -2)
+ {
+ len += strlen (f + len);
+ break;
+ }
+
+ if (bytes == (size_t) -1)
+ {
+ len++;
+ break;
+ }
+
+ len += bytes;
+ }
+ while (! mbsinit (&mbstate));
+
+ cpy (len, f);
+ f += len - 1;
+ continue;
+ }
+ }
+
+#else /* ! DO_MULTIBYTE */
+
+ /* Either multibyte encodings are not supported, they are
+ safe for formats, so any non-'%' byte can be copied through,
+ or this is the wide character version. */
+ if (*f != L_('%'))
+ {
+ add (1, *p = *f);
+ continue;
+ }
+
+#endif /* ! DO_MULTIBYTE */
+
+ /* Check for flags that can modify a format. */
+ while (1)
+ {
+ switch (*++f)
+ {
+ /* This influences the number formats. */
+ case L_('_'):
+ case L_('-'):
+ case L_('0'):
+ pad = *f;
+ continue;
+
+ /* This changes textual output. */
+ case L_('^'):
+ to_uppcase = 1;
+ continue;
+ case L_('#'):
+ change_case = 1;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* As a GNU extension we allow to specify the field width. */
+ if (ISDIGIT (*f))
+ {
+ width = 0;
+ do
+ {
+ if (width > INT_MAX / 10
+ || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
+ /* Avoid overflow. */
+ width = INT_MAX;
+ else
+ {
+ width *= 10;
+ width += *f - L_('0');
+ }
+ ++f;
+ }
+ while (ISDIGIT (*f));
+ }
+
+ /* Check for modifiers. */
+ switch (*f)
+ {
+ case L_('E'):
+ case L_('O'):
+ modifier = *f++;
+ break;
+
+ default:
+ modifier = 0;
+ break;
+ }
+
+ /* Now do the specified format. */
+ format_char = *f;
+ switch (format_char)
+ {
+#define DO_NUMBER(d, v) \
+ digits = d > width ? d : width; \
+ number_value = v; goto do_number
+#define DO_NUMBER_SPACEPAD(d, v) \
+ digits = d > width ? d : width; \
+ number_value = v; goto do_number_spacepad
+
+ case L_('%'):
+ if (modifier != 0)
+ goto bad_format;
+ add (1, *p = *f);
+ break;
+
+ case L_('a'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (aw_len, a_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case 'A':
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_wkday), f_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('b'):
+ case L_('h'):
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+ if (modifier != 0)
+ goto bad_format;
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (am_len, a_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('B'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_month), f_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('c'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == 'E'
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(ERA_D_T_FMT)))
+ != '\0')))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ subfmt = L_("%a %b %e %H:%M:%S %Y");
+# endif
+#endif
+
+ subformat:
+ {
+ CHAR_T *old_start = p;
+ size_t len = my_strftime (NULL, (size_t) -1, subfmt,
+ tp ut_argument LOCALE_ARG);
+ add (len, my_strftime (p, maxsize - i, subfmt,
+ tp ut_argument LOCALE_ARG));
+
+ if (to_uppcase)
+ while (old_start < p)
+ {
+ *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
+ ++old_start;
+ }
+ }
+ break;
+
+#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
+ underlying_strftime:
+ {
+ /* The relevant information is available only via the
+ underlying strftime implementation, so use that. */
+ char ufmt[4];
+ char *u = ufmt;
+ char ubuf[1024]; /* enough for any single format in practice */
+ size_t len;
+ /* Make sure we're calling the actual underlying strftime.
+ In some cases, config.h contains something like
+ "#define strftime rpl_strftime". */
+# ifdef strftime
+# undef strftime
+ size_t strftime ();
+# endif
+
+ *u++ = '%';
+ if (modifier != 0)
+ *u++ = modifier;
+ *u++ = format_char;
+ *u = '\0';
+ len = strftime (ubuf, sizeof ubuf, ufmt, tp);
+ if (len == 0 && ubuf[0] != '\0')
+ return 0;
+ cpy (len, ubuf);
+ }
+ break;
+#endif
+
+ case L_('C'):
+ if (modifier == L_('O'))
+ goto bad_format;
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ size_t len = __wcslen (era->era_wname);
+ cpy (len, era->era_wname);
+# else
+ size_t len = strlen (era->era_name);
+ cpy (len, era->era_name);
+# endif
+ break;
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+
+ {
+ int year = tp->tm_year + TM_YEAR_BASE;
+ DO_NUMBER (1, year / 100 - (year % 100 < 0));
+ }
+
+ case L_('x'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
+ goto subformat;
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('D'):
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%m/%d/%y");
+ goto subformat;
+
+ case L_('d'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_mday);
+
+ case L_('e'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, tp->tm_mday);
+
+ /* All numeric formats set DIGITS and NUMBER_VALUE and then
+ jump to one of these two labels. */
+
+ do_number_spacepad:
+ /* Force `_' flag unless overwritten by `0' or '-' flag. */
+ if (pad != L_('0') && pad != L_('-'))
+ pad = L_('_');
+
+ do_number:
+ /* Format the number according to the MODIFIER flag. */
+
+ if (modifier == L_('O') && 0 <= number_value)
+ {
+#ifdef _NL_CURRENT
+ /* Get the locale specific alternate representation of
+ the number NUMBER_VALUE. If none exist NULL is returned. */
+ const CHAR_T *cp = nl_get_alt_digit (number_value
+ HELPER_LOCALE_ARG);
+
+ if (cp != NULL)
+ {
+ size_t digitlen = STRLEN (cp);
+ if (digitlen != 0)
+ {
+ cpy (digitlen, cp);
+ break;
+ }
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ {
+ unsigned int u = number_value;
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+ negative_number = number_value < 0;
+
+ if (negative_number)
+ u = -u;
+
+ do
+ *--bufp = u % 10 + L_('0');
+ while ((u /= 10) != 0);
+ }
+
+ do_number_sign_and_padding:
+ if (negative_number)
+ *--bufp = L_('-');
+
+ if (pad != L_('-'))
+ {
+ int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
+ - bufp);
+
+ if (padding > 0)
+ {
+ if (pad == L_('_'))
+ {
+ if ((size_t) padding >= maxsize - i)
+ return 0;
+
+ if (p)
+ memset_space (p, padding);
+ i += padding;
+ width = width > padding ? width - padding : 0;
+ }
+ else
+ {
+ if ((size_t) digits >= maxsize - i)
+ return 0;
+
+ if (negative_number)
+ {
+ ++bufp;
+
+ if (p)
+ *p++ = L_('-');
+ ++i;
+ }
+
+ if (p)
+ memset_zero (p, padding);
+ i += padding;
+ width = 0;
+ }
+ }
+ }
+
+ cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
+ break;
+
+ case L_('F'):
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%Y-%m-%d");
+ goto subformat;
+
+ case L_('H'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_hour);
+
+ case L_('I'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, hour12);
+
+ case L_('k'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, tp->tm_hour);
+
+ case L_('l'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, hour12);
+
+ case L_('j'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (3, 1 + tp->tm_yday);
+
+ case L_('M'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_min);
+
+ case L_('m'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_mon + 1);
+
+ case L_('n'):
+ add (1, *p = L_('\n'));
+ break;
+
+ case L_('P'):
+ to_lowcase = 1;
+#if !defined _NL_CURRENT && HAVE_STRFTIME
+ format_char = L_('p');
+#endif
+ /* FALLTHROUGH */
+
+ case L_('p'):
+ if (change_case)
+ {
+ to_uppcase = 0;
+ to_lowcase = 1;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (ap_len, ampm);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('R'):
+ subfmt = L_("%H:%M");
+ goto subformat;
+
+ case L_('r'):
+#if !defined _NL_CURRENT && HAVE_STRFTIME
+ goto underlying_strftime;
+#else
+# ifdef _NL_CURRENT
+ if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(T_FMT_AMPM)))
+ == L_('\0'))
+# endif
+ subfmt = L_("%I:%M:%S %p");
+ goto subformat;
+#endif
+
+ case L_('S'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_sec);
+
+ case L_('s'): /* GNU extension. */
+ {
+ struct tm ltm;
+ time_t t;
+
+ ltm = *tp;
+ t = mktime (&ltm);
+
+ /* Generate string value for T using time_t arithmetic;
+ this works even if sizeof (long) < sizeof (time_t). */
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+ negative_number = t < 0;
+
+ do
+ {
+ int d = t % 10;
+ t /= 10;
+
+ if (negative_number)
+ {
+ d = -d;
+
+ /* Adjust if division truncates to minus infinity. */
+ if (0 < -1 % 10 && d < 0)
+ {
+ t++;
+ d += 10;
+ }
+ }
+
+ *--bufp = d + L_('0');
+ }
+ while (t != 0);
+
+ digits = 1;
+ goto do_number_sign_and_padding;
+ }
+
+ case L_('X'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
+ goto subformat;
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('T'):
+ subfmt = L_("%H:%M:%S");
+ goto subformat;
+
+ case L_('t'):
+ add (1, *p = L_('\t'));
+ break;
+
+ case L_('u'):
+ DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
+
+ case L_('U'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
+
+ case L_('V'):
+ case L_('g'):
+ case L_('G'):
+ if (modifier == L_('E'))
+ goto bad_format;
+ {
+ int year = tp->tm_year + TM_YEAR_BASE;
+ int days = iso_week_days (tp->tm_yday, tp->tm_wday);
+
+ if (days < 0)
+ {
+ /* This ISO week belongs to the previous year. */
+ year--;
+ days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
+ tp->tm_wday);
+ }
+ else
+ {
+ int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
+ tp->tm_wday);
+ if (0 <= d)
+ {
+ /* This ISO week belongs to the next year. */
+ year++;
+ days = d;
+ }
+ }
+
+ switch (*f)
+ {
+ case L_('g'):
+ DO_NUMBER (2, (year % 100 + 100) % 100);
+
+ case L_('G'):
+ DO_NUMBER (1, year);
+
+ default:
+ DO_NUMBER (2, days / 7 + 1);
+ }
+ }
+
+ case L_('W'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
+
+ case L_('w'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (1, tp->tm_wday);
+
+ case L_('Y'):
+ if (modifier == 'E')
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ subfmt = era->era_wformat;
+# else
+ subfmt = era->era_format;
+# endif
+ goto subformat;
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ if (modifier == L_('O'))
+ goto bad_format;
+ else
+ DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
+
+ case L_('y'):
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+ int delta = tp->tm_year - era->start_date[0];
+ DO_NUMBER (1, (era->offset
+ + delta * era->absolute_direction));
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
+
+ case L_('Z'):
+ if (change_case)
+ {
+ to_uppcase = 0;
+ to_lowcase = 1;
+ }
+
+#if HAVE_TZNAME
+ /* The tzset() call might have changed the value. */
+ if (!(zone && *zone) && tp->tm_isdst >= 0)
+ zone = tzname[tp->tm_isdst];
+#endif
+ if (! zone)
+ zone = "";
+
+#ifdef COMPILE_WIDE
+ {
+ /* The zone string is always given in multibyte form. We have
+ to transform it first. */
+ wchar_t *wczone;
+ size_t len;
+ widen (zone, wczone, len);
+ cpy (len, wczone);
+ }
+#else
+ cpy (strlen (zone), zone);
+#endif
+ break;
+
+ case L_('z'):
+ if (tp->tm_isdst < 0)
+ break;
+
+ {
+ int diff;
+#if HAVE_TM_GMTOFF
+ diff = tp->tm_gmtoff;
+#else
+ if (ut)
+ diff = 0;
+ else
+ {
+ struct tm gtm;
+ struct tm ltm;
+ time_t lt;
+
+ ltm = *tp;
+ lt = mktime (&ltm);
+
+ if (lt == (time_t) -1)
+ {
+ /* mktime returns -1 for errors, but -1 is also a
+ valid time_t value. Check whether an error really
+ occurred. */
+ struct tm tm;
+
+ if (! __localtime_r (&lt, &tm)
+ || ((ltm.tm_sec ^ tm.tm_sec)
+ | (ltm.tm_min ^ tm.tm_min)
+ | (ltm.tm_hour ^ tm.tm_hour)
+ | (ltm.tm_mday ^ tm.tm_mday)
+ | (ltm.tm_mon ^ tm.tm_mon)
+ | (ltm.tm_year ^ tm.tm_year)))
+ break;
+ }
+
+ if (! __gmtime_r (&lt, &gtm))
+ break;
+
+ diff = tm_diff (&ltm, &gtm);
+ }
+#endif
+
+ if (diff < 0)
+ {
+ add (1, *p = L_('-'));
+ diff = -diff;
+ }
+ else
+ add (1, *p = L_('+'));
+
+ diff /= 60;
+ DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
+ }
+
+ case L_('\0'): /* GNU extension: % at end of format. */
+ --f;
+ /* Fall through. */
+ default:
+ /* Unknown format; output the format, including the '%',
+ since this is most likely the right thing to do if a
+ multibyte string has been misparsed. */
+ bad_format:
+ {
+ int flen;
+ for (flen = 1; f[1 - flen] != L_('%'); flen++)
+ continue;
+ cpy (flen, &f[1 - flen]);
+ }
+ break;
+ }
+ }
+
+ if (p && maxsize != 0)
+ *p = L_('\0');
+ return i;
+}
+#ifdef _LIBC
+libc_hidden_def (my_strftime)
+#endif
+
+
+#ifdef emacs
+/* For Emacs we have a separate interface which corresponds to the normal
+ strftime function and does not have the extra information whether the
+ TP arguments comes from a `gmtime' call or not. */
+size_t
+emacs_strftime (s, maxsize, format, tp)
+ char *s;
+ size_t maxsize;
+ const char *format;
+ const struct tm *tp;
+{
+ return my_strftime (s, maxsize, format, tp, 0);
+}
+#endif
+
+#if defined _LIBC && !defined COMPILE_WIDE
weak_alias (__strftime_l, strftime_l)
+#endif
diff --git a/time/strptime.c b/time/strptime.c
index 1edd4ac257..fc3526912d 100644
--- a/time/strptime.c
+++ b/time/strptime.c
@@ -1,5 +1,5 @@
/* Convert a string representation of time to a time value.
- Copyright (C) 1996-2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996-2000, 2001, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -23,1072 +23,18 @@
some of them in the same format (such as year, week and weekday)
this is enough information for determining the date. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <langinfo.h>
-#include <limits.h>
-#include <string.h>
#include <time.h>
-
-#ifdef _LIBC
-# include "../locale/localeinfo.h"
-#endif
-
-
-#ifndef __P
-# if defined __GNUC__ || (defined __STDC__ && __STDC__)
-# define __P(args) args
-# else
-# define __P(args) ()
-# endif /* GCC. */
-#endif /* Not __P. */
-
-
-#if ! HAVE_LOCALTIME_R && ! defined localtime_r
-# ifdef _LIBC
-# define localtime_r __localtime_r
-# else
-/* Approximate localtime_r as best we can in its absence. */
-# define localtime_r my_localtime_r
-static struct tm *localtime_r __P ((const time_t *, struct tm *));
-static struct tm *
-localtime_r (t, tp)
- const time_t *t;
- struct tm *tp;
-{
- struct tm *l = localtime (t);
- if (! l)
- return 0;
- *tp = *l;
- return tp;
-}
-# endif /* ! _LIBC */
-#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
-
-
-#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
-#if defined __GNUC__ && __GNUC__ >= 2
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define match_string(cs1, s2) \
- ({ size_t len = strlen (cs1); \
- int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
- if (result) (s2) += len; \
- result; })
-# else
-# define match_string(cs1, s2) \
- ({ size_t len = strlen (cs1); \
- int result = strncasecmp ((cs1), (s2), len) == 0; \
- if (result) (s2) += len; \
- result; })
-# endif
-#else
-/* Oh come on. Get a reasonable compiler. */
-# define match_string(cs1, s2) \
- (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
-#endif
-/* We intentionally do not use isdigit() for testing because this will
- lead to problems with the wide character version. */
-#define get_number(from, to, n) \
- do { \
- int __n = n; \
- val = 0; \
- while (*rp == ' ') \
- ++rp; \
- if (*rp < '0' || *rp > '9') \
- return NULL; \
- do { \
- val *= 10; \
- val += *rp++ - '0'; \
- } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
- if (val < from || val > to) \
- return NULL; \
- } while (0)
-#ifdef _NL_CURRENT
-# define get_alt_number(from, to, n) \
- ({ \
- __label__ do_normal; \
- \
- if (*decided != raw) \
- { \
- val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
- if (val == -1 && *decided != loc) \
- { \
- *decided = loc; \
- goto do_normal; \
- } \
- if (val < from || val > to) \
- return NULL; \
- } \
- else \
- { \
- do_normal: \
- get_number (from, to, n); \
- } \
- 0; \
- })
-#else
-# define get_alt_number(from, to, n) \
- /* We don't have the alternate representation. */ \
- get_number(from, to, n)
-#endif
-#define recursive(new_fmt) \
- (*(new_fmt) != '\0' \
- && (rp = strptime_internal (rp, (new_fmt), tm, \
- decided, era_cnt LOCALE_ARG)) != NULL)
-
-
-#ifdef _LIBC
-/* This is defined in locale/C-time.c in the GNU libc. */
-extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
-
-# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
-# define ab_weekday_name \
- (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
-# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
-# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
-# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
-# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
-# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
-# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
-# define HERE_T_FMT_AMPM \
- (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
-# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
-
-# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
-#else
-static char const weekday_name[][10] =
- {
- "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"
- };
-static char const ab_weekday_name[][4] =
- {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
-static char const month_name[][10] =
- {
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
- };
-static char const ab_month_name[][4] =
- {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
-# define HERE_D_FMT "%m/%d/%y"
-# define HERE_AM_STR "AM"
-# define HERE_PM_STR "PM"
-# define HERE_T_FMT_AMPM "%I:%M:%S %p"
-# define HERE_T_FMT "%H:%M:%S"
-
-static const unsigned short int __mon_yday[2][13] =
- {
- /* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
- /* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
- };
-#endif
-
-#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
-/* We use this code also for the extended locale handling where the
- function gets as an additional argument the locale which has to be
- used. To access the values we have to redefine the _NL_CURRENT
- macro. */
-# define strptime __strptime_l
-# undef _NL_CURRENT
-# define _NL_CURRENT(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].string)
-# undef _NL_CURRENT_WORD
-# define _NL_CURRENT_WORD(category, item) \
- (current->values[_NL_ITEM_INDEX (item)].word)
-# define LOCALE_PARAM , locale
-# define LOCALE_ARG , locale
-# define LOCALE_PARAM_PROTO , __locale_t locale
-# define LOCALE_PARAM_DECL __locale_t locale;
-# define HELPER_LOCALE_ARG , current
-# define ISSPACE(Ch) __isspace_l (Ch, locale)
-#else
-# define LOCALE_PARAM
-# define LOCALE_ARG
-# define LOCALE_PARAM_DECL
-# define LOCALE_PARAM_PROTO
-# ifdef _LIBC
-# define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
-# else
-# define HELPER_LOCALE_ARG
-# endif
-# define ISSPACE(Ch) isspace (Ch)
-#endif
-
-
-/* Status of lookup: do we use the locale data or the raw data? */
-enum locale_status { not, loc, raw };
-
-
-#ifndef __isleap
-/* Nonzero if YEAR is a leap year (every 4 years,
- except every 100th isn't, and every 400th is). */
-# define __isleap(year) \
- ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-#endif
-
-/* Compute the day of the week. */
-static void
-day_of_the_week (struct tm *tm)
-{
- /* We know that January 1st 1970 was a Thursday (= 4). Compute the
- the difference between this data in the one on TM and so determine
- the weekday. */
- int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
- int wday = (-473
- + (365 * (tm->tm_year - 70))
- + (corr_year / 4)
- - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
- + (((corr_year / 4) / 25) / 4)
- + __mon_yday[0][tm->tm_mon]
- + tm->tm_mday - 1);
- tm->tm_wday = ((wday % 7) + 7) % 7;
-}
-
-/* Compute the day of the year. */
-static void
-day_of_the_year (struct tm *tm)
-{
- tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
- + (tm->tm_mday - 1));
-}
-
-
-static char *
-#ifdef _LIBC
-internal_function
-#endif
-strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
- enum locale_status *decided, int era_cnt
- LOCALE_PARAM_PROTO));
-
-static char *
-#ifdef _LIBC
-internal_function
-#endif
-strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
- const char *rp;
- const char *fmt;
- struct tm *tm;
- enum locale_status *decided;
- int era_cnt;
- LOCALE_PARAM_DECL
-{
-#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
- struct locale_data *const current = locale->__locales[LC_TIME];
-#endif
-
- const char *rp_backup;
- int cnt;
- size_t val;
- int have_I, is_pm;
- int century, want_century;
- int want_era;
- int have_wday, want_xday;
- int have_yday;
- int have_mon, have_mday;
- int have_uweek, have_wweek;
- int week_no;
- size_t num_eras;
- struct era_entry *era;
-
- have_I = is_pm = 0;
- century = -1;
- want_century = 0;
- want_era = 0;
- era = NULL;
- week_no = 0;
-
- have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
- have_wweek = 0;
-
- while (*fmt != '\0')
- {
- /* A white space in the format string matches 0 more or white
- space in the input string. */
- if (ISSPACE (*fmt))
- {
- while (ISSPACE (*rp))
- ++rp;
- ++fmt;
- continue;
- }
-
- /* Any character but `%' must be matched by the same character
- in the iput string. */
- if (*fmt != '%')
- {
- match_char (*fmt++, *rp++);
- continue;
- }
-
- ++fmt;
-#ifndef _NL_CURRENT
- /* We need this for handling the `E' modifier. */
- start_over:
-#endif
-
- /* Make back up of current processing pointer. */
- rp_backup = rp;
-
- switch (*fmt++)
- {
- case '%':
- /* Match the `%' character itself. */
- match_char ('%', *rp++);
- break;
- case 'a':
- case 'A':
- /* Match day of week. */
- for (cnt = 0; cnt < 7; ++cnt)
- {
-#ifdef _NL_CURRENT
- if (*decided !=raw)
- {
- if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
- {
- if (*decided == not
- && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
- weekday_name[cnt]))
- *decided = loc;
- break;
- }
- if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
- {
- if (*decided == not
- && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
- ab_weekday_name[cnt]))
- *decided = loc;
- break;
- }
- }
-#endif
- if (*decided != loc
- && (match_string (weekday_name[cnt], rp)
- || match_string (ab_weekday_name[cnt], rp)))
- {
- *decided = raw;
- break;
- }
- }
- if (cnt == 7)
- /* Does not match a weekday name. */
- return NULL;
- tm->tm_wday = cnt;
- have_wday = 1;
- break;
- case 'b':
- case 'B':
- case 'h':
- /* Match month name. */
- for (cnt = 0; cnt < 12; ++cnt)
- {
-#ifdef _NL_CURRENT
- if (*decided !=raw)
- {
- if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
- {
- if (*decided == not
- && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
- month_name[cnt]))
- *decided = loc;
- break;
- }
- if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
- {
- if (*decided == not
- && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
- ab_month_name[cnt]))
- *decided = loc;
- break;
- }
- }
-#endif
- if (match_string (month_name[cnt], rp)
- || match_string (ab_month_name[cnt], rp))
- {
- *decided = raw;
- break;
- }
- }
- if (cnt == 12)
- /* Does not match a month name. */
- return NULL;
- tm->tm_mon = cnt;
- want_xday = 1;
- break;
- case 'c':
- /* Match locale's date and time format. */
-#ifdef _NL_CURRENT
- if (*decided != raw)
- {
- if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (*decided == not &&
- strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
- *decided = loc;
- want_xday = 1;
- break;
- }
- *decided = raw;
- }
-#endif
- if (!recursive (HERE_D_T_FMT))
- return NULL;
- want_xday = 1;
- break;
- case 'C':
- /* Match century number. */
- match_century:
- get_number (0, 99, 2);
- century = val;
- want_xday = 1;
- break;
- case 'd':
- case 'e':
- /* Match day of month. */
- get_number (1, 31, 2);
- tm->tm_mday = val;
- have_mday = 1;
- want_xday = 1;
- break;
- case 'F':
- if (!recursive ("%Y-%m-%d"))
- return NULL;
- want_xday = 1;
- break;
- case 'x':
-#ifdef _NL_CURRENT
- if (*decided != raw)
- {
- if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (*decided == not
- && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
- *decided = loc;
- want_xday = 1;
- break;
- }
- *decided = raw;
- }
-#endif
- /* Fall through. */
- case 'D':
- /* Match standard day format. */
- if (!recursive (HERE_D_FMT))
- return NULL;
- want_xday = 1;
- break;
- case 'k':
- case 'H':
- /* Match hour in 24-hour clock. */
- get_number (0, 23, 2);
- tm->tm_hour = val;
- have_I = 0;
- break;
- case 'l':
- /* Match hour in 12-hour clock. GNU extension. */
- case 'I':
- /* Match hour in 12-hour clock. */
- get_number (1, 12, 2);
- tm->tm_hour = val % 12;
- have_I = 1;
- break;
- case 'j':
- /* Match day number of year. */
- get_number (1, 366, 3);
- tm->tm_yday = val - 1;
- have_yday = 1;
- break;
- case 'm':
- /* Match number of month. */
- get_number (1, 12, 2);
- tm->tm_mon = val - 1;
- have_mon = 1;
- want_xday = 1;
- break;
- case 'M':
- /* Match minute. */
- get_number (0, 59, 2);
- tm->tm_min = val;
- break;
- case 'n':
- case 't':
- /* Match any white space. */
- while (ISSPACE (*rp))
- ++rp;
- break;
- case 'p':
- /* Match locale's equivalent of AM/PM. */
-#ifdef _NL_CURRENT
- if (*decided != raw)
- {
- if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
- {
- if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
- *decided = loc;
- break;
- }
- if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
- {
- if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
- *decided = loc;
- is_pm = 1;
- break;
- }
- *decided = raw;
- }
-#endif
- if (!match_string (HERE_AM_STR, rp))
- if (match_string (HERE_PM_STR, rp))
- is_pm = 1;
- else
- return NULL;
- break;
- case 'r':
-#ifdef _NL_CURRENT
- if (*decided != raw)
- {
- if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (*decided == not &&
- strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
- HERE_T_FMT_AMPM))
- *decided = loc;
- break;
- }
- *decided = raw;
- }
-#endif
- if (!recursive (HERE_T_FMT_AMPM))
- return NULL;
- break;
- case 'R':
- if (!recursive ("%H:%M"))
- return NULL;
- break;
- case 's':
- {
- /* The number of seconds may be very high so we cannot use
- the `get_number' macro. Instead read the number
- character for character and construct the result while
- doing this. */
- time_t secs = 0;
- if (*rp < '0' || *rp > '9')
- /* We need at least one digit. */
- return NULL;
-
- do
- {
- secs *= 10;
- secs += *rp++ - '0';
- }
- while (*rp >= '0' && *rp <= '9');
-
- if (localtime_r (&secs, tm) == NULL)
- /* Error in function. */
- return NULL;
- }
- break;
- case 'S':
- get_number (0, 61, 2);
- tm->tm_sec = val;
- break;
- case 'X':
-#ifdef _NL_CURRENT
- if (*decided != raw)
- {
- if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
- *decided = loc;
- break;
- }
- *decided = raw;
- }
-#endif
- /* Fall through. */
- case 'T':
- if (!recursive (HERE_T_FMT))
- return NULL;
- break;
- case 'u':
- get_number (1, 7, 1);
- tm->tm_wday = val % 7;
- have_wday = 1;
- break;
- case 'g':
- get_number (0, 99, 2);
- /* XXX This cannot determine any field in TM. */
- break;
- case 'G':
- if (*rp < '0' || *rp > '9')
- return NULL;
- /* XXX Ignore the number since we would need some more
- information to compute a real date. */
- do
- ++rp;
- while (*rp >= '0' && *rp <= '9');
- break;
- case 'U':
- get_number (0, 53, 2);
- week_no = val;
- have_uweek = 1;
- break;
- case 'W':
- get_number (0, 53, 2);
- week_no = val;
- have_wweek = 1;
- break;
- case 'V':
- get_number (0, 53, 2);
- /* XXX This cannot determine any field in TM without some
- information. */
- break;
- case 'w':
- /* Match number of weekday. */
- get_number (0, 6, 1);
- tm->tm_wday = val;
- have_wday = 1;
- break;
- case 'y':
- match_year_in_century:
- /* Match year within century. */
- get_number (0, 99, 2);
- /* The "Year 2000: The Millennium Rollover" paper suggests that
- values in the range 69-99 refer to the twentieth century. */
- tm->tm_year = val >= 69 ? val : val + 100;
- /* Indicate that we want to use the century, if specified. */
- want_century = 1;
- want_xday = 1;
- break;
- case 'Y':
- /* Match year including century number. */
- get_number (0, 9999, 4);
- tm->tm_year = val - 1900;
- want_century = 0;
- want_xday = 1;
- break;
- case 'Z':
- /* XXX How to handle this? */
- break;
- case 'E':
-#ifdef _NL_CURRENT
- switch (*fmt++)
- {
- case 'c':
- /* Match locale's alternate date and time format. */
- if (*decided != raw)
- {
- const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
-
- if (*fmt == '\0')
- fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
-
- if (!recursive (fmt))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (strcmp (fmt, HERE_D_T_FMT))
- *decided = loc;
- want_xday = 1;
- break;
- }
- *decided = raw;
- }
- /* The C locale has no era information, so use the
- normal representation. */
- if (!recursive (HERE_D_T_FMT))
- return NULL;
- want_xday = 1;
- break;
- case 'C':
- if (*decided != raw)
- {
- if (era_cnt >= 0)
- {
- era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
- if (era != NULL && match_string (era->era_name, rp))
- {
- *decided = loc;
- break;
- }
- else
- return NULL;
- }
- else
- {
- num_eras = _NL_CURRENT_WORD (LC_TIME,
- _NL_TIME_ERA_NUM_ENTRIES);
- for (era_cnt = 0; era_cnt < (int) num_eras;
- ++era_cnt, rp = rp_backup)
- {
- era = _nl_select_era_entry (era_cnt
- HELPER_LOCALE_ARG);
- if (era != NULL && match_string (era->era_name, rp))
- {
- *decided = loc;
- break;
- }
- }
- if (era_cnt == (int) num_eras)
- {
- era_cnt = -1;
- if (*decided == loc)
- return NULL;
- }
- else
- break;
- }
-
- *decided = raw;
- }
- /* The C locale has no era information, so use the
- normal representation. */
- goto match_century;
- case 'y':
- if (*decided == raw)
- goto match_year_in_century;
-
- get_number(0, 9999, 4);
- tm->tm_year = val;
- want_era = 1;
- want_xday = 1;
- want_century = 1;
- break;
- case 'Y':
- if (*decided != raw)
- {
- num_eras = _NL_CURRENT_WORD (LC_TIME,
- _NL_TIME_ERA_NUM_ENTRIES);
- for (era_cnt = 0; era_cnt < (int) num_eras;
- ++era_cnt, rp = rp_backup)
- {
- era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
- if (era != NULL && recursive (era->era_format))
- break;
- }
- if (era_cnt == (int) num_eras)
- {
- era_cnt = -1;
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- *decided = loc;
- era_cnt = -1;
- break;
- }
-
- *decided = raw;
- }
- get_number (0, 9999, 4);
- tm->tm_year = val - 1900;
- want_century = 0;
- want_xday = 1;
- break;
- case 'x':
- if (*decided != raw)
- {
- const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
-
- if (*fmt == '\0')
- fmt = _NL_CURRENT (LC_TIME, D_FMT);
-
- if (!recursive (fmt))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (strcmp (fmt, HERE_D_FMT))
- *decided = loc;
- break;
- }
- *decided = raw;
- }
- if (!recursive (HERE_D_FMT))
- return NULL;
- break;
- case 'X':
- if (*decided != raw)
- {
- const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
-
- if (*fmt == '\0')
- fmt = _NL_CURRENT (LC_TIME, T_FMT);
-
- if (!recursive (fmt))
- {
- if (*decided == loc)
- return NULL;
- else
- rp = rp_backup;
- }
- else
- {
- if (strcmp (fmt, HERE_T_FMT))
- *decided = loc;
- break;
- }
- *decided = raw;
- }
- if (!recursive (HERE_T_FMT))
- return NULL;
- break;
- default:
- return NULL;
- }
- break;
-#else
- /* We have no information about the era format. Just use
- the normal format. */
- if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
- && *fmt != 'x' && *fmt != 'X')
- /* This is an illegal format. */
- return NULL;
-
- goto start_over;
-#endif
- case 'O':
- switch (*fmt++)
- {
- case 'd':
- case 'e':
- /* Match day of month using alternate numeric symbols. */
- get_alt_number (1, 31, 2);
- tm->tm_mday = val;
- have_mday = 1;
- want_xday = 1;
- break;
- case 'H':
- /* Match hour in 24-hour clock using alternate numeric
- symbols. */
- get_alt_number (0, 23, 2);
- tm->tm_hour = val;
- have_I = 0;
- break;
- case 'I':
- /* Match hour in 12-hour clock using alternate numeric
- symbols. */
- get_alt_number (1, 12, 2);
- tm->tm_hour = val % 12;
- have_I = 1;
- break;
- case 'm':
- /* Match month using alternate numeric symbols. */
- get_alt_number (1, 12, 2);
- tm->tm_mon = val - 1;
- have_mon = 1;
- want_xday = 1;
- break;
- case 'M':
- /* Match minutes using alternate numeric symbols. */
- get_alt_number (0, 59, 2);
- tm->tm_min = val;
- break;
- case 'S':
- /* Match seconds using alternate numeric symbols. */
- get_alt_number (0, 61, 2);
- tm->tm_sec = val;
- break;
- case 'U':
- get_alt_number (0, 53, 2);
- week_no = val;
- have_uweek = 1;
- break;
- case 'W':
- get_alt_number (0, 53, 2);
- week_no = val;
- have_wweek = 1;
- break;
- case 'V':
- get_alt_number (0, 53, 2);
- /* XXX This cannot determine any field in TM without
- further information. */
- break;
- case 'w':
- /* Match number of weekday using alternate numeric symbols. */
- get_alt_number (0, 6, 1);
- tm->tm_wday = val;
- have_wday = 1;
- break;
- case 'y':
- /* Match year within century using alternate numeric symbols. */
- get_alt_number (0, 99, 2);
- tm->tm_year = val >= 69 ? val : val + 100;
- want_xday = 1;
- break;
- default:
- return NULL;
- }
- break;
- default:
- return NULL;
- }
- }
-
- if (have_I && is_pm)
- tm->tm_hour += 12;
-
- if (century != -1)
- {
- if (want_century)
- tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
- else
- /* Only the century, but not the year. Strange, but so be it. */
- tm->tm_year = (century - 19) * 100;
- }
-
- if (era_cnt != -1)
- {
- era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
- if (era == NULL)
- return NULL;
- if (want_era)
- tm->tm_year = (era->start_date[0]
- + ((tm->tm_year - era->offset)
- * era->absolute_direction));
- else
- /* Era start year assumed. */
- tm->tm_year = era->start_date[0];
- }
- else
- if (want_era)
- {
- /* No era found but we have seen an E modifier. Rectify some
- values. */
- if (want_century && century == -1 && tm->tm_year < 69)
- tm->tm_year += 100;
- }
-
- if (want_xday && !have_wday)
- {
- if ( !(have_mon && have_mday) && have_yday)
- {
- /* We don't have tm_mon and/or tm_mday, compute them. */
- int t_mon = 0;
- while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
- t_mon++;
- if (!have_mon)
- tm->tm_mon = t_mon - 1;
- if (!have_mday)
- tm->tm_mday =
- (tm->tm_yday
- - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
- }
- day_of_the_week (tm);
- }
-
- if (want_xday && !have_yday)
- day_of_the_year (tm);
-
- if ((have_uweek || have_wweek) && have_wday)
- {
- int save_wday = tm->tm_wday;
- int save_mday = tm->tm_mday;
- int save_mon = tm->tm_mon;
- int w_offset = have_uweek ? 0 : 1;
-
- tm->tm_mday = 1;
- tm->tm_mon = 0;
- day_of_the_week (tm);
- if (have_mday)
- tm->tm_mday = save_mday;
- if (have_mon)
- tm->tm_mon = save_mon;
-
- if (!have_yday)
- tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
- + (week_no - 1) *7
- + save_wday - w_offset);
-
- if (!have_mday || !have_mon)
- {
- int t_mon = 0;
- while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
- <= tm->tm_yday)
- t_mon++;
- if (!have_mon)
- tm->tm_mon = t_mon - 1;
- if (!have_mday)
- tm->tm_mday =
- (tm->tm_yday
- - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
- }
-
- tm->tm_wday = save_wday;
- }
-
- return (char *) rp;
-}
+#include <locale/localeinfo.h>
char *
-strptime (buf, format, tm LOCALE_PARAM)
+strptime (buf, format, tm)
const char *buf;
const char *format;
struct tm *tm;
- LOCALE_PARAM_DECL
{
- enum locale_status decided;
-
-#ifdef _NL_CURRENT
- decided = not;
-#else
- decided = raw;
-#endif
- return strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
+ enum ptime_locale_status decided = not;
+ return __strptime_internal (buf, format, tm, &decided, -1,
+ _NL_CURRENT_LOCALE);
}
-#if defined _LIBC && !defined USE_IN_EXTENDED_LOCALE_MODEL
libc_hidden_def (strptime)
-#endif
diff --git a/time/strptime_l.c b/time/strptime_l.c
index 681386003d..b95f0982e8 100644
--- a/time/strptime_l.c
+++ b/time/strptime_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004 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
@@ -16,7 +16,1053 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <strptime.c>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <ctype.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+#endif
+
+
+#ifndef __P
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+
+#if ! HAVE_LOCALTIME_R && ! defined localtime_r
+# ifdef _LIBC
+# define localtime_r __localtime_r
+# else
+/* Approximate localtime_r as best we can in its absence. */
+# define localtime_r my_localtime_r
+static struct tm *localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+localtime_r (t, tp)
+ const time_t *t;
+ struct tm *tp;
+{
+ struct tm *l = localtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+# endif /* ! _LIBC */
+#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
+
+
+#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
+#if defined __GNUC__ && __GNUC__ >= 2
+# define match_string(cs1, s2) \
+ ({ size_t len = strlen (cs1); \
+ int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
+ if (result) (s2) += len; \
+ result; })
+#else
+/* Oh come on. Get a reasonable compiler. */
+# define match_string(cs1, s2) \
+ (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
+#endif
+/* We intentionally do not use isdigit() for testing because this will
+ lead to problems with the wide character version. */
+#define get_number(from, to, n) \
+ do { \
+ int __n = n; \
+ val = 0; \
+ while (*rp == ' ') \
+ ++rp; \
+ if (*rp < '0' || *rp > '9') \
+ return NULL; \
+ do { \
+ val *= 10; \
+ val += *rp++ - '0'; \
+ } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
+ if (val < from || val > to) \
+ return NULL; \
+ } while (0)
+#ifdef _NL_CURRENT
+# define get_alt_number(from, to, n) \
+ ({ \
+ __label__ do_normal; \
+ \
+ if (*decided != raw) \
+ { \
+ val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
+ if (val == -1 && *decided != loc) \
+ { \
+ *decided = loc; \
+ goto do_normal; \
+ } \
+ if (val < from || val > to) \
+ return NULL; \
+ } \
+ else \
+ { \
+ do_normal: \
+ get_number (from, to, n); \
+ } \
+ 0; \
+ })
+#else
+# define get_alt_number(from, to, n) \
+ /* We don't have the alternate representation. */ \
+ get_number(from, to, n)
+#endif
+#define recursive(new_fmt) \
+ (*(new_fmt) != '\0' \
+ && (rp = __strptime_internal (rp, (new_fmt), tm, \
+ decided, era_cnt LOCALE_ARG)) != NULL)
+
+
+#ifdef _LIBC
+/* This is defined in locale/C-time.c in the GNU libc. */
+extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
+
+# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
+# define ab_weekday_name \
+ (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
+# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
+# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
+# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
+# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
+# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
+# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
+# define HERE_T_FMT_AMPM \
+ (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
+# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
+
+# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
+#else
+static char const weekday_name[][10] =
+ {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ };
+static char const ab_weekday_name[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+static char const month_name[][10] =
+ {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ };
+static char const ab_month_name[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
+# define HERE_D_FMT "%m/%d/%y"
+# define HERE_AM_STR "AM"
+# define HERE_PM_STR "PM"
+# define HERE_T_FMT_AMPM "%I:%M:%S %p"
+# define HERE_T_FMT "%H:%M:%S"
+
+static const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+#endif
+
+#if defined _LIBC
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+# define strptime __strptime_l
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# undef _NL_CURRENT_WORD
+# define _NL_CURRENT_WORD(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].word)
+# define LOCALE_PARAM , locale
+# define LOCALE_ARG , locale
+# define LOCALE_PARAM_PROTO , __locale_t locale
+# define LOCALE_PARAM_DECL __locale_t locale;
+# define HELPER_LOCALE_ARG , current
+# define ISSPACE(Ch) __isspace_l (Ch, locale)
+#else
+# define LOCALE_PARAM
+# define LOCALE_ARG
+# define LOCALE_PARAM_DECL
+# define LOCALE_PARAM_PROTO
+# define HELPER_LOCALE_ARG
+# define ISSPACE(Ch) isspace (Ch)
+#endif
+
+
+
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* Compute the day of the week. */
+static void
+day_of_the_week (struct tm *tm)
+{
+ /* We know that January 1st 1970 was a Thursday (= 4). Compute the
+ the difference between this data in the one on TM and so determine
+ the weekday. */
+ int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
+ int wday = (-473
+ + (365 * (tm->tm_year - 70))
+ + (corr_year / 4)
+ - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
+ + (((corr_year / 4) / 25) / 4)
+ + __mon_yday[0][tm->tm_mon]
+ + tm->tm_mday - 1);
+ tm->tm_wday = ((wday % 7) + 7) % 7;
+}
+
+/* Compute the day of the year. */
+static void
+day_of_the_year (struct tm *tm)
+{
+ tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
+ + (tm->tm_mday - 1));
+}
+
+
+#ifdef _LIBC
+char *
+internal_function
+#else
+static char *
+#endif
+__strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
+ const char *rp;
+ const char *fmt;
+ struct tm *tm;
+ enum ptime_locale_status *decided;
+ int era_cnt;
+ LOCALE_PARAM_DECL
+{
+#ifdef _LIBC
+ struct locale_data *const current = locale->__locales[LC_TIME];
+#endif
+
+ const char *rp_backup;
+ int cnt;
+ size_t val;
+ int have_I, is_pm;
+ int century, want_century;
+ int want_era;
+ int have_wday, want_xday;
+ int have_yday;
+ int have_mon, have_mday;
+ int have_uweek, have_wweek;
+ int week_no;
+ size_t num_eras;
+ struct era_entry *era;
+
+ have_I = is_pm = 0;
+ century = -1;
+ want_century = 0;
+ want_era = 0;
+ era = NULL;
+ week_no = 0;
+
+ have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
+ have_wweek = 0;
+
+ while (*fmt != '\0')
+ {
+ /* A white space in the format string matches 0 more or white
+ space in the input string. */
+ if (ISSPACE (*fmt))
+ {
+ while (ISSPACE (*rp))
+ ++rp;
+ ++fmt;
+ continue;
+ }
+
+ /* Any character but `%' must be matched by the same character
+ in the iput string. */
+ if (*fmt != '%')
+ {
+ match_char (*fmt++, *rp++);
+ continue;
+ }
+
+ ++fmt;
+#ifndef _NL_CURRENT
+ /* We need this for handling the `E' modifier. */
+ start_over:
+#endif
+
+ /* Make back up of current processing pointer. */
+ rp_backup = rp;
+
+ switch (*fmt++)
+ {
+ case '%':
+ /* Match the `%' character itself. */
+ match_char ('%', *rp++);
+ break;
+ case 'a':
+ case 'A':
+ /* Match day of week. */
+ for (cnt = 0; cnt < 7; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
+ weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
+ ab_weekday_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (*decided != loc
+ && (match_string (weekday_name[cnt], rp)
+ || match_string (ab_weekday_name[cnt], rp)))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 7)
+ /* Does not match a weekday name. */
+ return NULL;
+ tm->tm_wday = cnt;
+ have_wday = 1;
+ break;
+ case 'b':
+ case 'B':
+ case 'h':
+ /* Match month name. */
+ for (cnt = 0; cnt < 12; ++cnt)
+ {
+#ifdef _NL_CURRENT
+ if (*decided !=raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
+ month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
+ ab_month_name[cnt]))
+ *decided = loc;
+ break;
+ }
+ }
+#endif
+ if (match_string (month_name[cnt], rp)
+ || match_string (ab_month_name[cnt], rp))
+ {
+ *decided = raw;
+ break;
+ }
+ }
+ if (cnt == 12)
+ /* Does not match a month name. */
+ return NULL;
+ tm->tm_mon = cnt;
+ want_xday = 1;
+ break;
+ case 'c':
+ /* Match locale's date and time format. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ /* Match century number. */
+ match_century:
+ get_number (0, 99, 2);
+ century = val;
+ want_xday = 1;
+ break;
+ case 'd':
+ case 'e':
+ /* Match day of month. */
+ get_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'F':
+ if (!recursive ("%Y-%m-%d"))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'x':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not
+ && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ /* Fall through. */
+ case 'D':
+ /* Match standard day format. */
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'k':
+ case 'H':
+ /* Match hour in 24-hour clock. */
+ get_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'l':
+ /* Match hour in 12-hour clock. GNU extension. */
+ case 'I':
+ /* Match hour in 12-hour clock. */
+ get_number (1, 12, 2);
+ tm->tm_hour = val % 12;
+ have_I = 1;
+ break;
+ case 'j':
+ /* Match day number of year. */
+ get_number (1, 366, 3);
+ tm->tm_yday = val - 1;
+ have_yday = 1;
+ break;
+ case 'm':
+ /* Match number of month. */
+ get_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minute. */
+ get_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'n':
+ case 't':
+ /* Match any white space. */
+ while (ISSPACE (*rp))
+ ++rp;
+ break;
+ case 'p':
+ /* Match locale's equivalent of AM/PM. */
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
+ *decided = loc;
+ break;
+ }
+ if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
+ *decided = loc;
+ is_pm = 1;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!match_string (HERE_AM_STR, rp))
+ if (match_string (HERE_PM_STR, rp))
+ is_pm = 1;
+ else
+ return NULL;
+ break;
+ case 'r':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (*decided == not &&
+ strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
+ HERE_T_FMT_AMPM))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ if (!recursive (HERE_T_FMT_AMPM))
+ return NULL;
+ break;
+ case 'R':
+ if (!recursive ("%H:%M"))
+ return NULL;
+ break;
+ case 's':
+ {
+ /* The number of seconds may be very high so we cannot use
+ the `get_number' macro. Instead read the number
+ character for character and construct the result while
+ doing this. */
+ time_t secs = 0;
+ if (*rp < '0' || *rp > '9')
+ /* We need at least one digit. */
+ return NULL;
+
+ do
+ {
+ secs *= 10;
+ secs += *rp++ - '0';
+ }
+ while (*rp >= '0' && *rp <= '9');
+
+ if (localtime_r (&secs, tm) == NULL)
+ /* Error in function. */
+ return NULL;
+ }
+ break;
+ case 'S':
+ get_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'X':
+#ifdef _NL_CURRENT
+ if (*decided != raw)
+ {
+ if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+#endif
+ /* Fall through. */
+ case 'T':
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ case 'u':
+ get_number (1, 7, 1);
+ tm->tm_wday = val % 7;
+ have_wday = 1;
+ break;
+ case 'g':
+ get_number (0, 99, 2);
+ /* XXX This cannot determine any field in TM. */
+ break;
+ case 'G':
+ if (*rp < '0' || *rp > '9')
+ return NULL;
+ /* XXX Ignore the number since we would need some more
+ information to compute a real date. */
+ do
+ ++rp;
+ while (*rp >= '0' && *rp <= '9');
+ break;
+ case 'U':
+ get_number (0, 53, 2);
+ week_no = val;
+ have_uweek = 1;
+ break;
+ case 'W':
+ get_number (0, 53, 2);
+ week_no = val;
+ have_wweek = 1;
+ break;
+ case 'V':
+ get_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without some
+ information. */
+ break;
+ case 'w':
+ /* Match number of weekday. */
+ get_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+ match_year_in_century:
+ /* Match year within century. */
+ get_number (0, 99, 2);
+ /* The "Year 2000: The Millennium Rollover" paper suggests that
+ values in the range 69-99 refer to the twentieth century. */
+ tm->tm_year = val >= 69 ? val : val + 100;
+ /* Indicate that we want to use the century, if specified. */
+ want_century = 1;
+ want_xday = 1;
+ break;
+ case 'Y':
+ /* Match year including century number. */
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'Z':
+ /* XXX How to handle this? */
+ break;
+ case 'E':
+#ifdef _NL_CURRENT
+ switch (*fmt++)
+ {
+ case 'c':
+ /* Match locale's alternate date and time format. */
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_T_FMT))
+ *decided = loc;
+ want_xday = 1;
+ break;
+ }
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ if (!recursive (HERE_D_T_FMT))
+ return NULL;
+ want_xday = 1;
+ break;
+ case 'C':
+ if (*decided != raw)
+ {
+ if (era_cnt >= 0)
+ {
+ era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
+ if (era != NULL && match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt
+ HELPER_LOCALE_ARG);
+ if (era != NULL && match_string (era->era_name, rp))
+ {
+ *decided = loc;
+ break;
+ }
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ }
+ else
+ break;
+ }
+
+ *decided = raw;
+ }
+ /* The C locale has no era information, so use the
+ normal representation. */
+ goto match_century;
+ case 'y':
+ if (*decided == raw)
+ goto match_year_in_century;
+
+ get_number(0, 9999, 4);
+ tm->tm_year = val;
+ want_era = 1;
+ want_xday = 1;
+ want_century = 1;
+ break;
+ case 'Y':
+ if (*decided != raw)
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+ _NL_TIME_ERA_NUM_ENTRIES);
+ for (era_cnt = 0; era_cnt < (int) num_eras;
+ ++era_cnt, rp = rp_backup)
+ {
+ era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
+ if (era != NULL && recursive (era->era_format))
+ break;
+ }
+ if (era_cnt == (int) num_eras)
+ {
+ era_cnt = -1;
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ *decided = loc;
+ era_cnt = -1;
+ break;
+ }
+
+ *decided = raw;
+ }
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ want_century = 0;
+ want_xday = 1;
+ break;
+ case 'x':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, D_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_D_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_D_FMT))
+ return NULL;
+ break;
+ case 'X':
+ if (*decided != raw)
+ {
+ const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
+
+ if (*fmt == '\0')
+ fmt = _NL_CURRENT (LC_TIME, T_FMT);
+
+ if (!recursive (fmt))
+ {
+ if (*decided == loc)
+ return NULL;
+ else
+ rp = rp_backup;
+ }
+ else
+ {
+ if (strcmp (fmt, HERE_T_FMT))
+ *decided = loc;
+ break;
+ }
+ *decided = raw;
+ }
+ if (!recursive (HERE_T_FMT))
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+#else
+ /* We have no information about the era format. Just use
+ the normal format. */
+ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
+ && *fmt != 'x' && *fmt != 'X')
+ /* This is an illegal format. */
+ return NULL;
+
+ goto start_over;
+#endif
+ case 'O':
+ switch (*fmt++)
+ {
+ case 'd':
+ case 'e':
+ /* Match day of month using alternate numeric symbols. */
+ get_alt_number (1, 31, 2);
+ tm->tm_mday = val;
+ have_mday = 1;
+ want_xday = 1;
+ break;
+ case 'H':
+ /* Match hour in 24-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (0, 23, 2);
+ tm->tm_hour = val;
+ have_I = 0;
+ break;
+ case 'I':
+ /* Match hour in 12-hour clock using alternate numeric
+ symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_hour = val % 12;
+ have_I = 1;
+ break;
+ case 'm':
+ /* Match month using alternate numeric symbols. */
+ get_alt_number (1, 12, 2);
+ tm->tm_mon = val - 1;
+ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'M':
+ /* Match minutes using alternate numeric symbols. */
+ get_alt_number (0, 59, 2);
+ tm->tm_min = val;
+ break;
+ case 'S':
+ /* Match seconds using alternate numeric symbols. */
+ get_alt_number (0, 61, 2);
+ tm->tm_sec = val;
+ break;
+ case 'U':
+ get_alt_number (0, 53, 2);
+ week_no = val;
+ have_uweek = 1;
+ break;
+ case 'W':
+ get_alt_number (0, 53, 2);
+ week_no = val;
+ have_wweek = 1;
+ break;
+ case 'V':
+ get_alt_number (0, 53, 2);
+ /* XXX This cannot determine any field in TM without
+ further information. */
+ break;
+ case 'w':
+ /* Match number of weekday using alternate numeric symbols. */
+ get_alt_number (0, 6, 1);
+ tm->tm_wday = val;
+ have_wday = 1;
+ break;
+ case 'y':
+ /* Match year within century using alternate numeric symbols. */
+ get_alt_number (0, 99, 2);
+ tm->tm_year = val >= 69 ? val : val + 100;
+ want_xday = 1;
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ if (have_I && is_pm)
+ tm->tm_hour += 12;
+
+ if (century != -1)
+ {
+ if (want_century)
+ tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
+ else
+ /* Only the century, but not the year. Strange, but so be it. */
+ tm->tm_year = (century - 19) * 100;
+ }
+
+ if (era_cnt != -1)
+ {
+ era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
+ if (era == NULL)
+ return NULL;
+ if (want_era)
+ tm->tm_year = (era->start_date[0]
+ + ((tm->tm_year - era->offset)
+ * era->absolute_direction));
+ else
+ /* Era start year assumed. */
+ tm->tm_year = era->start_date[0];
+ }
+ else
+ if (want_era)
+ {
+ /* No era found but we have seen an E modifier. Rectify some
+ values. */
+ if (want_century && century == -1 && tm->tm_year < 69)
+ tm->tm_year += 100;
+ }
+
+ if (want_xday && !have_wday)
+ {
+ if ( !(have_mon && have_mday) && have_yday)
+ {
+ /* We don't have tm_mon and/or tm_mday, compute them. */
+ int t_mon = 0;
+ while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
+ t_mon++;
+ if (!have_mon)
+ tm->tm_mon = t_mon - 1;
+ if (!have_mday)
+ tm->tm_mday =
+ (tm->tm_yday
+ - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+ }
+ day_of_the_week (tm);
+ }
+
+ if (want_xday && !have_yday)
+ day_of_the_year (tm);
+
+ if ((have_uweek || have_wweek) && have_wday)
+ {
+ int save_wday = tm->tm_wday;
+ int save_mday = tm->tm_mday;
+ int save_mon = tm->tm_mon;
+ int w_offset = have_uweek ? 0 : 1;
+
+ tm->tm_mday = 1;
+ tm->tm_mon = 0;
+ day_of_the_week (tm);
+ if (have_mday)
+ tm->tm_mday = save_mday;
+ if (have_mon)
+ tm->tm_mon = save_mon;
+
+ if (!have_yday)
+ tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
+ + (week_no - 1) *7
+ + save_wday - w_offset);
+
+ if (!have_mday || !have_mon)
+ {
+ int t_mon = 0;
+ while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
+ <= tm->tm_yday)
+ t_mon++;
+ if (!have_mon)
+ tm->tm_mon = t_mon - 1;
+ if (!have_mday)
+ tm->tm_mday =
+ (tm->tm_yday
+ - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
+ }
+
+ tm->tm_wday = save_wday;
+ }
+
+ return (char *) rp;
+}
+
+
+char *
+strptime (buf, format, tm LOCALE_PARAM)
+ const char *buf;
+ const char *format;
+ struct tm *tm;
+ LOCALE_PARAM_DECL
+{
+ enum ptime_locale_status decided;
+
+#ifdef _NL_CURRENT
+ decided = not;
+#else
+ decided = raw;
+#endif
+ return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
+}
+
+#ifdef _LIBC
weak_alias (__strptime_l, strptime_l)
+#endif
diff --git a/time/wcsftime.c b/time/wcsftime.c
index 17bb53ede6..dcda6be18e 100644
--- a/time/wcsftime.c
+++ b/time/wcsftime.c
@@ -1,4 +1,30 @@
-#include <wctype.h>
+/* Copyright (C) 1991-1999, 2000, 2001, 2002, 2003, 2004
+ 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
#include <wchar.h>
-#define COMPILE_WIDE 1
-#include "strftime.c"
+#include <locale/localeinfo.h>
+
+
+size_t
+wcsftime (wchar_t *s, size_t maxsize, const wchar_t *format,
+ const struct tm *tp)
+{
+ return __wcsftime_l (s, maxsize, format, tp, _NL_CURRENT_LOCALE);
+}
+libc_hidden_def (wcsftime)
diff --git a/time/wcsftime_l.c b/time/wcsftime_l.c
index 969289710c..e9443ef64e 100644
--- a/time/wcsftime_l.c
+++ b/time/wcsftime_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004 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
@@ -16,7 +16,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <wchar.h>
+#include <wctype.h>
+
#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <wcsftime.c>
+#define COMPILE_WIDE 1
+#include "strftime_l.c"
weak_alias (__wcsftime_l, wcsftime_l)
diff --git a/wcsmbs/wcscoll.c b/wcsmbs/wcscoll.c
index 40bd584e8b..ed6db06e4e 100644
--- a/wcsmbs/wcscoll.c
+++ b/wcsmbs/wcscoll.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1999,2000,2001,2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -22,17 +22,8 @@
#define STRING_TYPE wchar_t
#define USTRING_TYPE wint_t
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRCOLL __wcscoll_l
-#else
-# define STRCOLL __wcscoll
-#endif
-#define STRCMP wcscmp
-#define STRLEN __wcslen
-#define WEIGHT_H "../locale/weightwc.h"
-#define SUFFIX WC
-#define L(arg) L##arg
-#define WIDE_CHAR_VERSION 1
+#define STRCOLL __wcscoll
+#define STRCOLL_L __wcscoll_l
#include "../string/strcoll.c"
diff --git a/wcsmbs/wcscoll_l.c b/wcsmbs/wcscoll_l.c
index 20007b29c9..04b0bf3649 100644
--- a/wcsmbs/wcscoll_l.c
+++ b/wcsmbs/wcscoll_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
@@ -17,7 +17,20 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <wcscoll.c>
+
+#include <wchar.h>
+#include "../locale/coll-lookup.h"
+
+#define STRING_TYPE wchar_t
+#define USTRING_TYPE wint_t
+#define STRCOLL __wcscoll_l
+#define STRCMP wcscmp
+#define STRLEN __wcslen
+#define WEIGHT_H "../locale/weightwc.h"
+#define SUFFIX WC
+#define L(arg) L##arg
+#define WIDE_CHAR_VERSION 1
+
+#include "../string/strcoll_l.c"
weak_alias (__wcscoll_l, wcscoll_l)
diff --git a/wcsmbs/wcstod.c b/wcsmbs/wcstod.c
index 5a39091c25..74fd557db6 100644
--- a/wcsmbs/wcstod.c
+++ b/wcsmbs/wcstod.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
@@ -17,9 +17,13 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <stddef.h>
+#include <xlocale.h>
-/* The actual implementation for all floating point sizes is in strtod.c. */
#define USE_WIDE_CHAR 1
+extern double ____wcstod_l_internal (const wchar_t *, wchar_t **, int,
+ __locale_t);
+
#include <stdlib/strtod.c>
diff --git a/wcsmbs/wcstod_l.c b/wcsmbs/wcstod_l.c
index 87f3a8f7bc..86ec18e6d5 100644
--- a/wcsmbs/wcstod_l.c
+++ b/wcsmbs/wcstod_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,11 +18,9 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define __need_wchar_t
#include <stddef.h>
-#include <locale.h>
+#include <xlocale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
extern double ____wcstod_l_internal (const wchar_t *, wchar_t **, int,
__locale_t);
@@ -30,6 +28,6 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
wchar_t **, int, int,
__locale_t);
-#include <wcstod.c>
+#define USE_WIDE_CHAR 1
-weak_alias (__wcstod_l, wcstod_l)
+#include <stdlib/strtod_l.c>
diff --git a/wcsmbs/wcstof.c b/wcsmbs/wcstof.c
index 02f91ef904..2d2fca3fde 100644
--- a/wcsmbs/wcstof.c
+++ b/wcsmbs/wcstof.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
@@ -17,27 +17,12 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <stddef.h>
+#include <xlocale.h>
-/* The actual implementation for all floating point sizes is in strtod.c.
- These macros tell it to produce the `float' version, `wcstof'. */
-
-#define FLOAT float
-#define FLT FLT
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __wcstof_l
-#else
-# define STRTOF wcstof
-#endif
-#define MPN2FLOAT __mpn_construct_float
-#define FLOAT_HUGE_VAL HUGE_VALF
#define USE_WIDE_CHAR 1
-#define SET_MANTISSA(flt, mant) \
- do { union ieee754_float u; \
- u.f = (flt); \
- if ((mant & 0x7fffff) == 0) \
- mant = 0x400000; \
- u.ieee.mantissa = (mant) & 0x7fffff; \
- (flt) = u.f; \
- } while (0)
-#include <stdlib/strtod.c>
+extern float ____wcstof_l_internal (const wchar_t *, wchar_t **, int,
+ __locale_t);
+
+#include <stdlib/strtof.c>
diff --git a/wcsmbs/wcstof_l.c b/wcsmbs/wcstof_l.c
index 542961e1fe..0ed31e0c7b 100644
--- a/wcsmbs/wcstof_l.c
+++ b/wcsmbs/wcstof_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Copyright (C) 1997,98,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,11 +18,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define __need_wchar_t
#include <stddef.h>
-#include <locale.h>
+#include <xlocale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
+
+#define USE_WIDE_CHAR 1
extern float ____wcstof_l_internal (const wchar_t *, wchar_t **, int,
__locale_t);
@@ -30,6 +30,4 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
wchar_t **, int, int,
__locale_t);
-#include <wcstof.c>
-
-weak_alias (__wcstof_l, wcstof_l)
+#include <stdlib/strtof_l.c>
diff --git a/wcsmbs/wcstold.c b/wcsmbs/wcstold.c
index 5c58aa69e6..d99b7278b9 100644
--- a/wcsmbs/wcstold.c
+++ b/wcsmbs/wcstold.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
@@ -17,46 +17,12 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <math.h>
-#include <wchar.h>
+#include <stddef.h>
+#include <xlocale.h>
-#ifndef __NO_LONG_DOUBLE_MATH
-/* The actual implementation for all floating point sizes is in strtod.c.
- These macros tell it to produce the `long double' version, `wcstold'. */
+#define USE_WIDE_CHAR 1
-# define FLOAT long double
-# define FLT LDBL
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRTOF __wcstold_l
-# else
-# define STRTOF wcstold
-# endif
-# define MPN2FLOAT __mpn_construct_long_double
-# define FLOAT_HUGE_VAL HUGE_VALL
-# define USE_WIDE_CHAR 1
-# define SET_MANTISSA(flt, mant) \
- do { union ieee854_long_double u; \
- u.d = (flt); \
- if ((mant & 0x7fffffffffffffffULL) == 0) \
- mant = 0x4000000000000000ULL; \
- u.ieee.mantissa0 = (((mant) >> 32) & 0x7fffffff) | 0x80000000; \
- u.ieee.mantissa1 = (mant) & 0xffffffff; \
- (flt) = u.d; \
- } while (0)
+extern long double ____wcstold_l_internal (const wchar_t *, wchar_t **, int,
+ __locale_t);
-# include <stdlib/strtod.c>
-#else
-/* There is no `long double' type, use the `double' implementations. */
-long double
-__wcstold_internal (const wchar_t *nptr, wchar_t **endptr, int group)
-{
- return __wcstod_internal (nptr, endptr, group);
-}
-libc_hidden_def (__wcstold_internal)
-
-long double
-wcstold (const wchar_t *nptr, wchar_t **endptr)
-{
- return __wcstod_internal (nptr, endptr, 0);
-}
-#endif
+#include <stdlib/strtold.c>
diff --git a/wcsmbs/wcstold_l.c b/wcsmbs/wcstold_l.c
index 91a92124cf..9526645f10 100644
--- a/wcsmbs/wcstold_l.c
+++ b/wcsmbs/wcstold_l.c
@@ -1,5 +1,5 @@
/* Convert string representing a number to integer value, using given locale.
- Copyright (C) 1997,98,99,2002 Free Software Foundation, Inc.
+ Copyright (C) 1997,98,99,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -18,15 +18,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define __need_wchar_t
-#include <math.h>
#include <stddef.h>
-#include <locale.h>
-#include <wchar.h>
+#include <xlocale.h>
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-
-#ifndef __NO_LONG_DOUBLE_MATH
+#define USE_WIDE_CHAR 1
extern long double ____wcstold_l_internal (const wchar_t *, wchar_t **, int,
__locale_t);
@@ -34,23 +29,4 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
wchar_t **, int, int,
__locale_t);
-# include <wcstold.c>
-#else
-/* There is no `long double' type, use the `double' implementations. */
-extern double ____wcstod_l_internal (const wchar_t *, wchar_t **, int,
- __locale_t);
-long double
-____wcstold_l_internal (const wchar_t *nptr, wchar_t **endptr, int group,
- __locale_t loc)
-{
- return ____wcstod_l_internal (nptr, endptr, group, loc);
-}
-
-long double
-__wcstold_l (const wchar_t *nptr, wchar_t **endptr, __locale_t loc)
-{
- return ____wcstod_l_internal (nptr, endptr, 0, loc);
-}
-#endif
-
-weak_alias (__wcstold_l, wcstold_l)
+#include <strtold_l.c>
diff --git a/wcsmbs/wcsxfrm.c b/wcsmbs/wcsxfrm.c
index 10f3d72673..9e7d10389b 100644
--- a/wcsmbs/wcsxfrm.c
+++ b/wcsmbs/wcsxfrm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2000, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -21,18 +21,7 @@
#include "../locale/coll-lookup.h"
#define STRING_TYPE wchar_t
-#define USTRING_TYPE wint_t
-#ifdef USE_IN_EXTENDED_LOCALE_MODEL
-# define STRXFRM __wcsxfrm_l
-#else
-# define STRXFRM wcsxfrm
-#endif
-#define STRCMP wcscmp
-#define STRLEN __wcslen
-#define STPNCPY __wcpncpy
-#define WEIGHT_H "../locale/weightwc.h"
-#define SUFFIX WC
-#define L(arg) L##arg
-#define WIDE_CHAR_VERSION 1
+#define STRXFRM wcsxfrm
+#define STRXFRM_L __wcsxfrm_l
#include "../string/strxfrm.c"
diff --git a/wcsmbs/wcsxfrm_l.c b/wcsmbs/wcsxfrm_l.c
index 13046237a9..de9fc93153 100644
--- a/wcsmbs/wcsxfrm_l.c
+++ b/wcsmbs/wcsxfrm_l.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
@@ -17,7 +17,20 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#define USE_IN_EXTENDED_LOCALE_MODEL 1
-#include <wcsxfrm.c>
+#include <wchar.h>
+#include "../locale/coll-lookup.h"
+
+#define STRING_TYPE wchar_t
+#define USTRING_TYPE wint_t
+#define STRXFRM __wcsxfrm_l
+#define STRCMP wcscmp
+#define STRLEN __wcslen
+#define STPNCPY __wcpncpy
+#define WEIGHT_H "../locale/weightwc.h"
+#define SUFFIX WC
+#define L(arg) L##arg
+#define WIDE_CHAR_VERSION 1
+
+#include "../string/strxfrm_l.c"
weak_alias (__wcsxfrm_l, wcsxfrm_l)