mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-28 00:21:52 +03:00
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.
This commit is contained in:
69
ChangeLog
69
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>
|
2004-03-11 Jeroen Dekkers <jeroen@dekkers.cx>
|
||||||
|
|
||||||
* cppflags-iterator.mk: Change libof-$(cpp-src) to
|
* cppflags-iterator.mk: Change libof-$(cpp-src) to
|
||||||
|
@ -1 +1,5 @@
|
|||||||
#include <stdlib/monetary.h>
|
#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);
|
||||||
|
@ -78,6 +78,8 @@ libc_hidden_proto (__strerror_r)
|
|||||||
libc_hidden_proto (__strverscmp)
|
libc_hidden_proto (__strverscmp)
|
||||||
libc_hidden_proto (basename)
|
libc_hidden_proto (basename)
|
||||||
libc_hidden_proto (strcoll)
|
libc_hidden_proto (strcoll)
|
||||||
|
libc_hidden_proto (__strcoll_l)
|
||||||
|
libc_hidden_proto (__strxfrm_l)
|
||||||
|
|
||||||
libc_hidden_builtin_proto (memchr)
|
libc_hidden_builtin_proto (memchr)
|
||||||
libc_hidden_builtin_proto (memcpy)
|
libc_hidden_builtin_proto (memcpy)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# include <time/time.h>
|
# include <time/time.h>
|
||||||
#else
|
#else
|
||||||
# include <time/time.h>
|
# include <time/time.h>
|
||||||
|
# include <xlocale.h>
|
||||||
|
|
||||||
extern __typeof (strftime_l) __strftime_l;
|
extern __typeof (strftime_l) __strftime_l;
|
||||||
libc_hidden_proto (__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);
|
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
|
/* Use in the clock_* functions. Size of the field representing the
|
||||||
actual clock ID. */
|
actual clock ID. */
|
||||||
#ifndef _ISOMAC
|
#ifndef _ISOMAC
|
||||||
|
@ -29,6 +29,9 @@ libc_hidden_proto (__wcstoull_internal)
|
|||||||
libc_hidden_proto (__wcscasecmp_l)
|
libc_hidden_proto (__wcscasecmp_l)
|
||||||
libc_hidden_proto (__wcsncasecmp_l)
|
libc_hidden_proto (__wcsncasecmp_l)
|
||||||
|
|
||||||
|
libc_hidden_proto (__wcscoll_l)
|
||||||
|
libc_hidden_proto (__wcsxfrm_l)
|
||||||
|
|
||||||
libc_hidden_proto (fputws_unlocked)
|
libc_hidden_proto (fputws_unlocked)
|
||||||
libc_hidden_proto (putwc_unlocked)
|
libc_hidden_proto (putwc_unlocked)
|
||||||
libc_hidden_proto (putwc)
|
libc_hidden_proto (putwc)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* uselocale -- fetch and set the current per-thread locale
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -29,7 +29,7 @@
|
|||||||
locale_t
|
locale_t
|
||||||
__uselocale (locale_t newloc)
|
__uselocale (locale_t newloc)
|
||||||
{
|
{
|
||||||
locale_t oldloc = __libc_tsd_get (LOCALE);
|
locale_t oldloc = _NL_CURRENT_LOCALE;
|
||||||
|
|
||||||
if (newloc != NULL)
|
if (newloc != NULL)
|
||||||
{
|
{
|
||||||
|
632
stdlib/strfmon.c
632
stdlib/strfmon.c
@ -19,645 +19,21 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <langinfo.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <monetary.h>
|
#include <monetary.h>
|
||||||
#ifdef USE_IN_LIBIO
|
|
||||||
# include "../libio/libioP.h"
|
|
||||||
# include "../libio/strfile.h"
|
|
||||||
#endif
|
|
||||||
#include <printf.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <locale/localeinfo.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. */
|
|
||||||
#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
|
ssize_t
|
||||||
strfmon (char *s, size_t maxsize, const char *format, ...)
|
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
|
va_list ap;
|
||||||
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_start (ap, format);
|
va_start (ap, format);
|
||||||
|
|
||||||
dest = s;
|
ssize_t res = __vstrfmon_l (s, maxsize, _NL_CURRENT_LOCALE, format, ap);
|
||||||
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';
|
|
||||||
|
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
return dest - s;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Formatting a monetary value according to the given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
||||||
|
|
||||||
@ -18,7 +18,637 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#include <ctype.h>
|
||||||
#include <strfmon.c>
|
#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)
|
weak_alias (__strfmon_l, strfmon_l)
|
||||||
|
1554
stdlib/strtod.c
1554
stdlib/strtod.c
File diff suppressed because it is too large
Load Diff
1551
stdlib/strtod_l.c
1551
stdlib/strtod_l.c
File diff suppressed because it is too large
Load Diff
@ -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.
|
/* The actual implementation for all floating point sizes is in strtod.c.
|
||||||
These macros tell it to produce the `float' version, `strtof'. */
|
These macros tell it to produce the `float' version, `strtof'. */
|
||||||
|
|
||||||
#define FLOAT float
|
#define FLOAT float
|
||||||
#define FLT FLT
|
#define FLT FLT
|
||||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
#ifdef USE_WIDE_CHAR
|
||||||
# define STRTOF __strtof_l
|
#define STRTOF wcstof
|
||||||
|
#define STRTOF_L __wcstof_l
|
||||||
#else
|
#else
|
||||||
# define STRTOF strtof
|
# define STRTOF strtof
|
||||||
|
# define STRTOF_L __strtof_l
|
||||||
#endif
|
#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"
|
#include "strtod.c"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to float value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,14 +18,30 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
|
||||||
|
|
||||||
#include <xlocale.h>
|
#include <xlocale.h>
|
||||||
|
|
||||||
extern float ____strtof_l_internal (const char *, char **, int, __locale_t);
|
extern float ____strtof_l_internal (const char *, char **, int, __locale_t);
|
||||||
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
|
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
|
||||||
int, int, __locale_t);
|
int, int, __locale_t);
|
||||||
|
|
||||||
#include <strtof.c>
|
#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)
|
||||||
|
|
||||||
weak_alias (__strtof_l, strtof_l)
|
#include "strtod_l.c"
|
||||||
|
35
stdlib/strtold.c
Normal file
35
stdlib/strtold.c
Normal file
@ -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"
|
@ -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)
|
|
526
string/strcoll.c
526
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.
|
This file is part of the GNU C Library.
|
||||||
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
|
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
|
||||||
|
|
||||||
@ -17,540 +17,24 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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 <string.h>
|
||||||
|
|
||||||
#ifndef STRING_TYPE
|
#ifndef STRING_TYPE
|
||||||
# define STRING_TYPE char
|
# define STRING_TYPE char
|
||||||
# define USTRING_TYPE unsigned char
|
|
||||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
|
||||||
# define STRCOLL __strcoll_l
|
|
||||||
# else
|
|
||||||
# define STRCOLL strcoll
|
# define STRCOLL strcoll
|
||||||
# endif
|
# define STRCOLL_L __strcoll_l
|
||||||
# define STRCMP strcmp
|
|
||||||
# define STRLEN strlen
|
|
||||||
# define WEIGHT_H "../locale/weight.h"
|
|
||||||
# define SUFFIX MB
|
|
||||||
# define L(arg) arg
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CONCAT(a,b) CONCAT1(a,b)
|
|
||||||
#define CONCAT1(a,b) a##b
|
|
||||||
|
|
||||||
#include "../locale/localeinfo.h"
|
#include "../locale/localeinfo.h"
|
||||||
|
|
||||||
#ifndef USE_IN_EXTENDED_LOCALE_MODEL
|
|
||||||
int
|
int
|
||||||
STRCOLL (s1, s2)
|
STRCOLL (s1, s2)
|
||||||
const STRING_TYPE *s1;
|
const STRING_TYPE *s1;
|
||||||
const STRING_TYPE *s2;
|
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
|
return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#if !defined WIDE_CHAR_VERSION && !defined USE_IN_EXTENDED_LOCALE_MODEL
|
#if !defined WIDE_CHAR_VERSION
|
||||||
libc_hidden_def (strcoll)
|
libc_hidden_def (strcoll)
|
||||||
#endif
|
#endif
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
|
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
|
||||||
|
|
||||||
@ -17,7 +17,515 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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)
|
weak_alias (__strcoll_l, strcoll_l)
|
||||||
|
#endif
|
||||||
|
442
string/strxfrm.c
442
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.
|
This file is part of the GNU C Library.
|
||||||
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
|
Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
|
||||||
|
|
||||||
@ -17,451 +17,17 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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 <string.h>
|
||||||
#include <sys/param.h>
|
#include <locale/localeinfo.h>
|
||||||
|
|
||||||
#ifndef STRING_TYPE
|
#ifndef STRING_TYPE
|
||||||
# define STRING_TYPE char
|
# define STRING_TYPE char
|
||||||
# define USTRING_TYPE unsigned char
|
|
||||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
|
||||||
# define STRXFRM __strxfrm_l
|
|
||||||
# else
|
|
||||||
# define STRXFRM strxfrm
|
# define STRXFRM strxfrm
|
||||||
# endif
|
# define STRXFRM_L __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
|
#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
|
size_t
|
||||||
STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n)
|
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
|
return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCALE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
|
Written by Ulrich Drepper <drepper@gnu.org>, 1995.
|
||||||
|
|
||||||
@ -17,7 +17,430 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#include <assert.h>
|
||||||
#include <strxfrm.c>
|
#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)
|
weak_alias (__strxfrm_l, strxfrm_l)
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representation of a number into an integer value.
|
/* Convert string representation of a number into an integer value.
|
||||||
Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001,2002,2003
|
Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001,2002,2003,2004
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
@ -18,46 +18,10 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
#include <stdlib.h>
|
||||||
# include <config.h>
|
#include <wchar.h>
|
||||||
#endif
|
#include <locale/localeinfo.h>
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
/* Nonzero if we are defining `strtoul' or `strtoull', operating on
|
|
||||||
unsigned integers. */
|
|
||||||
#ifndef UNSIGNED
|
#ifndef UNSIGNED
|
||||||
# define UNSIGNED 0
|
# define UNSIGNED 0
|
||||||
# define INT LONG int
|
# define INT LONG int
|
||||||
@ -65,508 +29,83 @@ extern int errno;
|
|||||||
# define INT unsigned LONG int
|
# define INT unsigned LONG int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Determine the name. */
|
#if UNSIGNED
|
||||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
|
||||||
# if UNSIGNED
|
|
||||||
# ifdef USE_WIDE_CHAR
|
|
||||||
# ifdef QUAD
|
|
||||||
# define strtol __wcstoull_l
|
|
||||||
# else
|
|
||||||
# define strtol __wcstoul_l
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
# ifdef QUAD
|
|
||||||
# define strtol __strtoull_l
|
|
||||||
# else
|
|
||||||
# define strtol __strtoul_l
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
# ifdef USE_WIDE_CHAR
|
|
||||||
# ifdef QUAD
|
|
||||||
# define strtol __wcstoll_l
|
|
||||||
# else
|
|
||||||
# define strtol __wcstol_l
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
# ifdef QUAD
|
|
||||||
# define strtol __strtoll_l
|
|
||||||
# else
|
|
||||||
# define strtol __strtol_l
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# if UNSIGNED
|
|
||||||
# ifdef USE_WIDE_CHAR
|
# ifdef USE_WIDE_CHAR
|
||||||
# ifdef QUAD
|
# ifdef QUAD
|
||||||
# define strtol wcstoull
|
# define strtol wcstoull
|
||||||
|
# define __strtol_l __wcstoull_l
|
||||||
# else
|
# else
|
||||||
# define strtol wcstoul
|
# define strtol wcstoul
|
||||||
|
# define __strtol_l __wcstoul_l
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# ifdef QUAD
|
# ifdef QUAD
|
||||||
# define strtol strtoull
|
# define strtol strtoull
|
||||||
|
# define __strtol_l __strtoull_l
|
||||||
# else
|
# else
|
||||||
# define strtol strtoul
|
# define strtol strtoul
|
||||||
|
# define __strtol_l __strtoul_l
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# else
|
#else
|
||||||
# ifdef USE_WIDE_CHAR
|
# ifdef USE_WIDE_CHAR
|
||||||
# ifdef QUAD
|
# ifdef QUAD
|
||||||
# define strtol wcstoll
|
# define strtol wcstoll
|
||||||
|
# define __strtol_l __wcstoll_l
|
||||||
# else
|
# else
|
||||||
# define strtol wcstol
|
# define strtol wcstol
|
||||||
|
# define __strtol_l __wcstol_l
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# ifdef QUAD
|
# ifdef QUAD
|
||||||
# define strtol strtoll
|
# define strtol strtoll
|
||||||
# endif
|
# define __strtol_l __strtoll_l
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* If QUAD is defined, we are defining `strtoll' or `strtoull',
|
/* If QUAD is defined, we are defining `strtoll' or `strtoull',
|
||||||
operating on `long long int's. */
|
operating on `long long int's. */
|
||||||
#ifdef QUAD
|
#ifdef QUAD
|
||||||
# define LONG long long
|
# 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
|
#else
|
||||||
# define LONG long
|
# 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
|
#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
|
#ifdef USE_WIDE_CHAR
|
||||||
# include <wctype.h>
|
|
||||||
# define L_(Ch) L##Ch
|
|
||||||
# define UCHAR_TYPE wint_t
|
|
||||||
# define STRING_TYPE wchar_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
|
#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
|
#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
|
INT
|
||||||
INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
|
INTERNAL (strtol) (nptr, endptr, base, group)
|
||||||
const STRING_TYPE *nptr;
|
const STRING_TYPE *nptr;
|
||||||
STRING_TYPE **endptr;
|
STRING_TYPE **endptr;
|
||||||
int base;
|
int base;
|
||||||
int group;
|
int group;
|
||||||
LOCALE_PARAM_DECL
|
|
||||||
{
|
{
|
||||||
int negative;
|
return INTERNAL (__strtol_l) (nptr, endptr, base, group, _NL_CURRENT_LOCALE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#if defined _LIBC \
|
|
||||||
&& !(defined USE_IN_EXTENDED_LOCALE_MODEL && defined USE_WIDE_CHAR)
|
|
||||||
libc_hidden_def (INTERNAL (strtol))
|
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
|
INT
|
||||||
#ifdef weak_function
|
strtol (nptr, endptr, base)
|
||||||
weak_function
|
|
||||||
#endif
|
|
||||||
strtol (nptr, endptr, base LOCALE_PARAM)
|
|
||||||
const STRING_TYPE *nptr;
|
const STRING_TYPE *nptr;
|
||||||
STRING_TYPE **endptr;
|
STRING_TYPE **endptr;
|
||||||
int base;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,13 +18,496 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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>
|
#include <xlocale.h>
|
||||||
|
|
||||||
extern long int ____strtol_l_internal (const char *, char **, int, int,
|
#ifdef USE_NUMBER_GROUPING
|
||||||
__locale_t);
|
# include "../locale/localeinfo.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "strtol.c"
|
/* 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
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
weak_alias (__strtol_l, strtol_l)
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -18,17 +18,23 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.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. */
|
/* There is no `long double' type, use the `double' implementations. */
|
||||||
long double
|
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
|
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);
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,13 +18,11 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#define QUAD 1
|
||||||
|
|
||||||
#include <xlocale.h>
|
#include <xlocale.h>
|
||||||
|
|
||||||
extern long long int ____strtoll_l_internal (const char *, char **, int, int,
|
extern long long int ____strtoll_l_internal (const char *, char **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
#include <strtoll.c>
|
#include <strtol_l.c>
|
||||||
|
|
||||||
weak_alias (__strtoll_l, strtoll_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,13 +18,11 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#define UNSIGNED 1
|
||||||
|
|
||||||
#include <xlocale.h>
|
#include <xlocale.h>
|
||||||
|
|
||||||
extern unsigned long int ____strtoul_l_internal (const char *, char **, int,
|
extern unsigned long int ____strtoul_l_internal (const char *, char **, int,
|
||||||
int, __locale_t);
|
int, __locale_t);
|
||||||
|
|
||||||
#include "strtoul.c"
|
#include "strtol_l.c"
|
||||||
|
|
||||||
weak_alias (__strtoul_l, strtoul_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,13 +18,12 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#define QUAD 1
|
||||||
|
#define UNSIGNED 1
|
||||||
|
|
||||||
#include <xlocale.h>
|
#include <xlocale.h>
|
||||||
|
|
||||||
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
|
extern unsigned long long int ____strtoull_l_internal (const char *, char **,
|
||||||
int, int, __locale_t);
|
int, int, __locale_t);
|
||||||
|
|
||||||
#include <strtoull.c>
|
#include <strtol_l.c>
|
||||||
|
|
||||||
weak_alias (__strtoull_l, strtoull_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -22,11 +22,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <locale.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,
|
extern long int ____wcstol_l_internal (const wchar_t *, wchar_t **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
#include "wcstol.c"
|
#include "strtol_l.c"
|
||||||
|
|
||||||
weak_alias (__wcstol_l, wcstol_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -22,11 +22,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <locale.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 **,
|
extern long long int ____wcstoll_l_internal (const wchar_t *, wchar_t **,
|
||||||
int, int, __locale_t);
|
int, int, __locale_t);
|
||||||
|
|
||||||
#include <wcstoll.c>
|
#include <wcstol_l.c>
|
||||||
|
|
||||||
weak_alias (__wcstoll_l, wcstoll_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -22,11 +22,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <locale.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 **,
|
extern unsigned long int ____wcstoul_l_internal (const wchar_t *, wchar_t **,
|
||||||
int, int, __locale_t);
|
int, int, __locale_t);
|
||||||
|
|
||||||
#include <wcstoul.c>
|
#include <wcstol_l.c>
|
||||||
|
|
||||||
weak_alias (__wcstoul_l, wcstoul_l)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -22,12 +22,10 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <locale.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 *,
|
extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
|
||||||
wchar_t **, int, int,
|
wchar_t **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
#include <wcstoull.c>
|
#include <wcstoll_l.c>
|
||||||
|
|
||||||
weak_alias (__wcstoull_l, wcstoull_l)
|
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -21,16 +21,18 @@
|
|||||||
/* The actual implementation for all floating point sizes is in strtod.c.
|
/* The actual implementation for all floating point sizes is in strtod.c.
|
||||||
These macros tell it to produce the `long double' version, `strtold'. */
|
These macros tell it to produce the `long double' version, `strtold'. */
|
||||||
|
|
||||||
# define FLOAT long double
|
#define FLOAT long double
|
||||||
# define FLT LDBL
|
#define FLT LDBL
|
||||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
#ifdef USE_WIDE_CHAR
|
||||||
# define STRTOF __strtold_l
|
# define STRTOF wcstold_l
|
||||||
# else
|
# define __STRTOF __wcstold_l
|
||||||
# define STRTOF strtold
|
#else
|
||||||
# endif
|
# define STRTOF strtold_l
|
||||||
# define MPN2FLOAT __mpn_construct_long_double
|
# define __STRTOF __strtold_l
|
||||||
# define FLOAT_HUGE_VAL HUGE_VALL
|
#endif
|
||||||
# define SET_MANTISSA(flt, mant) \
|
#define MPN2FLOAT __mpn_construct_long_double
|
||||||
|
#define FLOAT_HUGE_VAL HUGE_VALL
|
||||||
|
#define SET_MANTISSA(flt, mant) \
|
||||||
do { union ieee854_long_double u; \
|
do { union ieee854_long_double u; \
|
||||||
u.d = (flt); \
|
u.d = (flt); \
|
||||||
u.ieee.mantissa0 = 0x8000; \
|
u.ieee.mantissa0 = 0x8000; \
|
||||||
@ -40,4 +42,4 @@
|
|||||||
(flt) = u.d; \
|
(flt) = u.d; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# include "strtod.c"
|
#include <strtod_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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -21,16 +21,18 @@
|
|||||||
/* The actual implementation for all floating point sizes is in strtod.c.
|
/* The actual implementation for all floating point sizes is in strtod.c.
|
||||||
These macros tell it to produce the `long double' version, `strtold'. */
|
These macros tell it to produce the `long double' version, `strtold'. */
|
||||||
|
|
||||||
# define FLOAT long double
|
#define FLOAT long double
|
||||||
# define FLT LDBL
|
#define FLT LDBL
|
||||||
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
#ifdef USE_WIDE_CHAR
|
||||||
# define STRTOF __strtold_l
|
# define STRTOF wcstold_l
|
||||||
# else
|
# define __STRTOF __wcstold_l
|
||||||
# define STRTOF strtold
|
#else
|
||||||
# endif
|
# define STRTOF strtold_l
|
||||||
# define MPN2FLOAT __mpn_construct_long_double
|
# define __STRTOF __strtold_l
|
||||||
# define FLOAT_HUGE_VAL HUGE_VALL
|
#endif
|
||||||
# define SET_MANTISSA(flt, mant) \
|
#define MPN2FLOAT __mpn_construct_long_double
|
||||||
|
#define FLOAT_HUGE_VAL HUGE_VALL
|
||||||
|
#define SET_MANTISSA(flt, mant) \
|
||||||
do { union ieee854_long_double u; \
|
do { union ieee854_long_double u; \
|
||||||
u.d = (flt); \
|
u.d = (flt); \
|
||||||
if ((mant & 0x7fffffffffffffffULL) == 0) \
|
if ((mant & 0x7fffffffffffffffULL) == 0) \
|
||||||
@ -40,4 +42,4 @@
|
|||||||
(flt) = u.d; \
|
(flt) = u.d; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# include "strtod.c"
|
#include <strtod_l.c>
|
@ -1,2 +0,0 @@
|
|||||||
#define DENORM_EXP (MIN_EXP - 1)
|
|
||||||
#include <sysdeps/ieee754/ldbl-96/strtold.c>
|
|
2
sysdeps/m68k/strtold_l.c
Normal file
2
sysdeps/m68k/strtold_l.c
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#define DENORM_EXP (MIN_EXP - 1)
|
||||||
|
#include <sysdeps/ieee754/ldbl-96/strtold_l.c>
|
1421
time/strftime.c
1421
time/strftime.c
File diff suppressed because it is too large
Load Diff
1426
time/strftime_l.c
1426
time/strftime_l.c
File diff suppressed because it is too large
Load Diff
1066
time/strptime.c
1066
time/strptime.c
File diff suppressed because it is too large
Load Diff
1052
time/strptime_l.c
1052
time/strptime_l.c
File diff suppressed because it is too large
Load Diff
@ -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>
|
#include <wchar.h>
|
||||||
#define COMPILE_WIDE 1
|
#include <locale/localeinfo.h>
|
||||||
#include "strftime.c"
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -16,7 +16,11 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
||||||
#include <wcsftime.c>
|
#define COMPILE_WIDE 1
|
||||||
|
#include "strftime_l.c"
|
||||||
|
|
||||||
weak_alias (__wcsftime_l, wcsftime_l)
|
weak_alias (__wcsftime_l, wcsftime_l)
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
||||||
|
|
||||||
@ -22,17 +22,8 @@
|
|||||||
|
|
||||||
#define STRING_TYPE wchar_t
|
#define STRING_TYPE wchar_t
|
||||||
#define USTRING_TYPE wint_t
|
#define USTRING_TYPE wint_t
|
||||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
#define STRCOLL __wcscoll
|
||||||
# define STRCOLL __wcscoll_l
|
#define STRCOLL_L __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
|
|
||||||
|
|
||||||
#include "../string/strcoll.c"
|
#include "../string/strcoll.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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
||||||
|
|
||||||
@ -17,7 +17,20 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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)
|
weak_alias (__wcscoll_l, wcscoll_l)
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
||||||
|
|
||||||
@ -17,9 +17,13 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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
|
#define USE_WIDE_CHAR 1
|
||||||
|
|
||||||
|
extern double ____wcstod_l_internal (const wchar_t *, wchar_t **, int,
|
||||||
|
__locale_t);
|
||||||
|
|
||||||
#include <stdlib/strtod.c>
|
#include <stdlib/strtod.c>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,11 +18,9 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define __need_wchar_t
|
|
||||||
#include <stddef.h>
|
#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,
|
extern double ____wcstod_l_internal (const wchar_t *, wchar_t **, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
@ -30,6 +28,6 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
|
|||||||
wchar_t **, int, int,
|
wchar_t **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
#include <wcstod.c>
|
#define USE_WIDE_CHAR 1
|
||||||
|
|
||||||
weak_alias (__wcstod_l, wcstod_l)
|
#include <stdlib/strtod_l.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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
||||||
|
|
||||||
@ -17,27 +17,12 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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 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>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,11 +18,11 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define __need_wchar_t
|
|
||||||
#include <stddef.h>
|
#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,
|
extern float ____wcstof_l_internal (const wchar_t *, wchar_t **, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
@ -30,6 +30,4 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
|
|||||||
wchar_t **, int, int,
|
wchar_t **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
#include <wcstof.c>
|
#include <stdlib/strtof_l.c>
|
||||||
|
|
||||||
weak_alias (__wcstof_l, wcstof_l)
|
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
||||||
|
|
||||||
@ -17,46 +17,12 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#include <math.h>
|
#include <stddef.h>
|
||||||
#include <wchar.h>
|
#include <xlocale.h>
|
||||||
|
|
||||||
#ifndef __NO_LONG_DOUBLE_MATH
|
#define USE_WIDE_CHAR 1
|
||||||
/* The actual implementation for all floating point sizes is in strtod.c.
|
|
||||||
These macros tell it to produce the `long double' version, `wcstold'. */
|
|
||||||
|
|
||||||
# define FLOAT long double
|
extern long double ____wcstold_l_internal (const wchar_t *, wchar_t **, int,
|
||||||
# define FLT LDBL
|
__locale_t);
|
||||||
# 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)
|
|
||||||
|
|
||||||
# include <stdlib/strtod.c>
|
#include <stdlib/strtold.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
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Convert string representing a number to integer value, using given locale.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
|
||||||
|
|
||||||
@ -18,15 +18,10 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define __need_wchar_t
|
|
||||||
#include <math.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <locale.h>
|
#include <xlocale.h>
|
||||||
#include <wchar.h>
|
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#define USE_WIDE_CHAR 1
|
||||||
|
|
||||||
#ifndef __NO_LONG_DOUBLE_MATH
|
|
||||||
|
|
||||||
extern long double ____wcstold_l_internal (const wchar_t *, wchar_t **, int,
|
extern long double ____wcstold_l_internal (const wchar_t *, wchar_t **, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
@ -34,23 +29,4 @@ extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
|
|||||||
wchar_t **, int, int,
|
wchar_t **, int, int,
|
||||||
__locale_t);
|
__locale_t);
|
||||||
|
|
||||||
# include <wcstold.c>
|
#include <strtold_l.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)
|
|
||||||
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
||||||
|
|
||||||
@ -21,18 +21,7 @@
|
|||||||
#include "../locale/coll-lookup.h"
|
#include "../locale/coll-lookup.h"
|
||||||
|
|
||||||
#define STRING_TYPE wchar_t
|
#define STRING_TYPE wchar_t
|
||||||
#define USTRING_TYPE wint_t
|
#define STRXFRM wcsxfrm
|
||||||
#ifdef USE_IN_EXTENDED_LOCALE_MODEL
|
#define STRXFRM_L __wcsxfrm_l
|
||||||
# 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
|
|
||||||
|
|
||||||
#include "../string/strxfrm.c"
|
#include "../string/strxfrm.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.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
|
||||||
|
|
||||||
@ -17,7 +17,20 @@
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#define USE_IN_EXTENDED_LOCALE_MODEL 1
|
#include <wchar.h>
|
||||||
#include <wcsxfrm.c>
|
#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)
|
weak_alias (__wcsxfrm_l, wcsxfrm_l)
|
||||||
|
Reference in New Issue
Block a user