......@@ -72,6 +72,10 @@
# define __glob glob
# define __getlogin_r(buf, len) getlogin_r (buf, len)
# define __lstat64(fname, buf) lstat (fname, buf)
# ifdef __MINGW32__
/* Avoid GCC warning. mingw has an unused __stat64 macro. */
# undef __stat64
# endif
# define __stat64(fname, buf) stat (fname, buf)
# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
# define struct_stat64 struct stat
......
......@@ -254,7 +254,7 @@ glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
# ifdef PTHREAD_RWLOCK_INITIALIZER
# if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
# if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
/* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
......
......@@ -308,7 +308,7 @@ typedef pthread_mutex_t gl_lock_t;
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
# ifdef PTHREAD_RWLOCK_INITIALIZER
# if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
typedef pthread_rwlock_t gl_rwlock_t;
# define gl_rwlock_define(STORAGECLASS, NAME) \
......@@ -316,8 +316,13 @@ typedef pthread_rwlock_t gl_rwlock_t;
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
# if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
# define gl_rwlock_initializer \
PTHREAD_RWLOCK_INITIALIZER
# if defined PTHREAD_RWLOCK_INITIALIZER
# define gl_rwlock_initializer \
PTHREAD_RWLOCK_INITIALIZER
# else
# define gl_rwlock_initializer \
PTHREAD_RWLOCK_INITIALIZER_NP
# endif
# define glthread_rwlock_init(LOCK) \
(pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
# else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
......
......@@ -21,52 +21,15 @@
#include "hard-locale.h"
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GLIBC__
# define GLIBC_VERSION __GLIBC__
#elif defined __UCLIBC__
# define GLIBC_VERSION 2
#else
# define GLIBC_VERSION 0
#endif
/* Return true if the current CATEGORY locale is hard, i.e. if you
can't get away with assuming traditional C or POSIX behavior. */
bool
hard_locale (int category)
{
bool hard = true;
char const *p = setlocale (category, NULL);
if (p)
{
if (2 <= GLIBC_VERSION)
{
if (strcmp (p, "C") == 0 || strcmp (p, "POSIX") == 0)
hard = false;
}
else
{
char *locale = strdup (p);
if (locale)
{
/* Temporarily set the locale to the "C" and "POSIX" locales
to find their names, so that we can determine whether one
or the other is the caller's locale. */
if (((p = setlocale (category, "C"))
&& strcmp (p, locale) == 0)
|| ((p = setlocale (category, "POSIX"))
&& strcmp (p, locale) == 0))
hard = false;
char locale[SETLOCALE_NULL_MAX];
/* Restore the caller's locale. */
setlocale (category, locale);
free (locale);
}
}
}
if (setlocale_null_r (category, locale, sizeof (locale)))
return false;
return hard;
return !(strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0);
}
......@@ -20,6 +20,9 @@
# include <stdbool.h>
bool hard_locale (int);
/* Return true if the specified CATEGORY of the current locale is hard, i.e.
different from the C or POSIX locale that has a fixed behavior.
CATEGORY must be one of the LC_* values, but not LC_ALL. */
extern bool hard_locale (int category);
#endif /* HARD_LOCALE_H_ */
/* Character set conversion.
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, see <https://www.gnu.org/licenses/>. */
struct mapping { int standard_name; const char vendor_name[10 + 1]; };
%struct-type
%language=ANSI-C
%define slot-name standard_name
%define hash-function-name mapping_hash
%define lookup-function-name mapping_lookup
%readonly-tables
%global-table
%define word-array-name mappings
%pic
%%
ASCII, "00367"
ISO-8859-1, "ISO8859-1"
ISO-8859-2, "ISO8859-2"
ISO-8859-4, "ISO8859-4"
ISO-8859-5, "ISO8859-5"
ISO-8859-6, "ISO8859-6"
ISO-8859-7, "ISO8859-7"
ISO-8859-8, "ISO8859-8"
ISO-8859-9, "ISO8859-9"
ISO-8859-13, "ISO8859-13"
ISO-8859-15, "ISO8859-15"
CP437, "IBM-437"
CP850, "IBM-850"
CP852, "IBM-852"
CP855, "IBM-855"
CP856, "IBM-856"
CP861, "IBM-861"
CP862, "IBM-862"
CP864, "IBM-864"
CP866, "IBM-866"
CP869, "IBM-869"
CP874, "TIS-620"
CP922, "IBM-922"
CP932, "IBM-eucJC"
CP943, "IBM-943"
CP949, "IBM-949"
CP1046, "IBM-1046"
CP1124, "IBM-1124"
CP1125, "IBM-1125"
CP1250, "IBM-1250"
CP1251, "IBM-1251"
CP1252, "IBM-1252"
CP1253, "IBM-1253"
CP1254, "IBM-1254"
CP1255, "IBM-1255"
CP1256, "IBM-1256"
GB2312, "IBM-eucCN"
EUC-JP, "EUCJP"
EUC-KR, "IBM-eucKR"
EUC-TW, "IBM-eucTW"
GBK, "IBM-936"
......@@ -36,6 +36,7 @@
#define ICONV_FLAVOR_IRIX "iconv_open-irix.h"
#define ICONV_FLAVOR_OSF "iconv_open-osf.h"
#define ICONV_FLAVOR_SOLARIS "iconv_open-solaris.h"
#define ICONV_FLAVOR_ZOS "iconv_open-zos.h"
#ifdef ICONV_FLAVOR
# include ICONV_FLAVOR
......
......@@ -36,11 +36,9 @@ extern int integer_length (unsigned int x);
The result is >= 0, <= sizeof (unsigned long) * CHAR_BIT. */
extern int integer_length_l (unsigned long x);
#if HAVE_UNSIGNED_LONG_LONG_INT
/* Returns the integer length of x.
The result is >= 0, <= sizeof (unsigned long long) * CHAR_BIT. */
extern int integer_length_ll (unsigned long long x);
#endif
#ifdef __cplusplus
}
......
......@@ -189,7 +189,7 @@
# define _PRI64_PREFIX "l"
# elif defined _MSC_VER || defined __MINGW32__
# define _PRI64_PREFIX "I64"
# elif @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1
# elif LONG_MAX >> 30 == 1
# define _PRI64_PREFIX _LONG_LONG_FORMAT_PREFIX
# endif
# if !defined PRId64 || @PRI_MACROS_BROKEN@
......@@ -206,7 +206,7 @@
# define _PRIu64_PREFIX "l"
# elif defined _MSC_VER || defined __MINGW32__
# define _PRIu64_PREFIX "I64"
# elif @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1
# elif ULONG_MAX >> 31 == 1
# define _PRIu64_PREFIX _LONG_LONG_FORMAT_PREFIX
# endif
# if !defined PRIo64 || @PRI_MACROS_BROKEN@
......@@ -682,7 +682,7 @@
# define _SCN64_PREFIX "l"
# elif defined _MSC_VER || defined __MINGW32__
# define _SCN64_PREFIX "I64"
# elif @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1
# elif LONG_MAX >> 30 == 1
# define _SCN64_PREFIX _LONG_LONG_FORMAT_PREFIX
# endif
# if !defined SCNd64 || @PRI_MACROS_BROKEN@
......@@ -699,7 +699,7 @@
# define _SCNu64_PREFIX "l"
# elif defined _MSC_VER || defined __MINGW32__
# define _SCNu64_PREFIX "I64"
# elif @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1
# elif ULONG_MAX >> 31 == 1
# define _SCNu64_PREFIX _LONG_LONG_FORMAT_PREFIX
# endif
# if !defined SCNo64 || @PRI_MACROS_BROKEN@
......
......@@ -58,6 +58,9 @@
#elif defined WINDOWS_NATIVE
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
/* For the use of setlocale() below, the Gnulib override in setlocale.c is
not needed; see the platform lists in setlocale_null.m4. */
# undef setlocale
#endif
#if defined OS2
# define INCL_DOS
......@@ -150,7 +153,8 @@ static const struct table_entry alias_table[] =
{ "ISO8859-2", "ISO-8859-2" },
{ "ISO8859-4", "ISO-8859-4" },
{ "ISO8859-5", "ISO-8859-5" },
{ "ISO8859-7", "ISO-8859-7" }
{ "ISO8859-7", "ISO-8859-7" },
{ "US-ASCII", "ASCII" }
# define alias_table_defined
# endif
# if defined __APPLE__ && defined __MACH__ /* Mac OS X */
......@@ -812,8 +816,11 @@ static const struct table_entry locale_table[] =
/* Determine the current locale's character encoding, and canonicalize it
into one of the canonical names listed in localcharset.h.
The result must not be freed; it is statically allocated.
into one of the canonical names listed below.
The result must not be freed; it is statically allocated. The result
becomes invalid when setlocale() is used to change the global locale, or
when the value of one of the environment variables LC_ALL, LC_CTYPE, LANG
is changed; threads in multithreaded programs should not do this.
If the canonical name cannot be determined, the result is a non-canonical
name. */
......@@ -825,6 +832,13 @@ locale_charset (void)
{
const char *codeset;
/* This function must be multithread-safe. To achieve this without using
thread-local storage, we use a simple strcpy or memcpy to fill this static
buffer. Filling it through, for example, strcpy + strcat would not be
guaranteed to leave the buffer's contents intact if another thread is
currently accessing it. If necessary, the contents is first assembled in
a stack-allocated buffer. */
#if HAVE_LANGINFO_CODESET || defined WINDOWS_NATIVE || defined OS2
# if HAVE_LANGINFO_CODESET
......@@ -839,7 +853,7 @@ locale_charset (void)
if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
{
const char *locale;
static char buf[2 + 10 + 1];
static char resultbuf[2 + 10 + 1];
locale = getenv ("LC_ALL");
if (locale == NULL || locale[0] == '\0')
......@@ -863,11 +877,12 @@ locale_charset (void)
modifier = strchr (dot, '@');
if (modifier == NULL)
return dot;
if (modifier - dot < sizeof (buf))
if (modifier - dot < sizeof (resultbuf))
{
memcpy (buf, dot, modifier - dot);
buf [modifier - dot] = '\0';
return buf;
/* This way of filling resultbuf is multithread-safe. */
memcpy (resultbuf, dot, modifier - dot);
resultbuf [modifier - dot] = '\0';
return resultbuf;
}
}
}
......@@ -883,8 +898,13 @@ locale_charset (void)
converting to GetConsoleOutputCP(). This leads to correct results,
except when SetConsoleOutputCP has been called and a raster font is
in use. */
sprintf (buf, "CP%u", GetACP ());
codeset = buf;
{
char buf[2 + 10 + 1];
sprintf (buf, "CP%u", GetACP ());
strcpy (resultbuf, buf);
codeset = resultbuf;
}
}
# endif
......@@ -894,34 +914,28 @@ locale_charset (void)
# elif defined WINDOWS_NATIVE
static char buf[2 + 10 + 1];
char buf[2 + 10 + 1];
static char resultbuf[2 + 10 + 1];
/* The Windows API has a function returning the locale's codepage as
a number, but the value doesn't change according to what the
'setlocale' call specified. So we use it as a last resort, in
case the string returned by 'setlocale' doesn't specify the
codepage. */
char *current_locale = setlocale (LC_ALL, NULL);
char *pdot;
/* If they set different locales for different categories,
'setlocale' will return a semi-colon separated list of locale
values. To make sure we use the correct one, we choose LC_CTYPE. */
if (strchr (current_locale, ';'))
current_locale = setlocale (LC_CTYPE, NULL);
char *current_locale = setlocale (LC_CTYPE, NULL);
char *pdot = strrchr (current_locale, '.');
pdot = strrchr (current_locale, '.');
if (pdot && 2 + strlen (pdot + 1) + 1 <= sizeof (buf))
sprintf (buf, "CP%s", pdot + 1);
else
{
/* The Windows API has a function returning the locale's codepage as a
number: GetACP().
When the output goes to a console window, it needs to be provided in
GetOEMCP() encoding if the console is using a raster font, or in
GetConsoleOutputCP() encoding if it is using a TrueType font.
But in GUI programs and for output sent to files and pipes, GetACP()
encoding is the best bet. */
number: GetACP().
When the output goes to a console window, it needs to be provided in
GetOEMCP() encoding if the console is using a raster font, or in
GetConsoleOutputCP() encoding if it is using a TrueType font.
But in GUI programs and for output sent to files and pipes, GetACP()
encoding is the best bet. */
sprintf (buf, "CP%u", GetACP ());
}
/* For a locale name such as "French_France.65001", in Windows 10,
......@@ -929,12 +943,15 @@ locale_charset (void)
if (strcmp (buf + 2, "65001") == 0 || strcmp (buf + 2, "utf8") == 0)
codeset = "UTF-8";
else
codeset = buf;
{
strcpy (resultbuf, buf);
codeset = resultbuf;
}
# elif defined OS2
const char *locale;
static char buf[2 + 10 + 1];
static char resultbuf[2 + 10 + 1];
ULONG cp[3];
ULONG cplen;
......@@ -963,11 +980,12 @@ locale_charset (void)
modifier = strchr (dot, '@');
if (modifier == NULL)
return dot;
if (modifier - dot < sizeof (buf))
if (modifier - dot < sizeof (resultbuf))
{
memcpy (buf, dot, modifier - dot);
buf [modifier - dot] = '\0';
return buf;
/* This way of filling resultbuf is multithread-safe. */
memcpy (resultbuf, dot, modifier - dot);
resultbuf [modifier - dot] = '\0';
return resultbuf;
}
}
......@@ -983,8 +1001,11 @@ locale_charset (void)
codeset = "";
else
{
char buf[2 + 10 + 1];
sprintf (buf, "CP%u", cp[0]);
codeset = buf;
strcpy (resultbuf, buf);
codeset = resultbuf;
}
}
......
......@@ -26,7 +26,10 @@ extern "C" {
/* Determine the current locale's character encoding, and canonicalize it
into one of the canonical names listed below.
The result must not be freed; it is statically allocated.
The result must not be freed; it is statically allocated. The result
becomes invalid when setlocale() is used to change the global locale, or
when the value of one of the environment variables LC_ALL, LC_CTYPE, LANG
is changed; threads in multithreaded programs should not do this.
If the canonical name cannot be determined, the result is a non-canonical
name. */
extern const char * locale_charset (void);
......@@ -45,15 +48,15 @@ extern const char * locale_charset (void);
(darwin = Mac OS X, windows = native Windows)
ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin minix cygwin
ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
ISO-8859-3 Y glibc solaris cygwin
ISO-8859-4 Y hpux osf solaris freebsd netbsd openbsd darwin
ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
ISO-8859-6 Y glibc aix hpux solaris cygwin
ISO-8859-7 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
ISO-8859-8 Y glibc aix hpux osf solaris cygwin
ISO-8859-9 Y glibc aix hpux irix osf solaris freebsd darwin cygwin
ISO-8859-7 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
ISO-8859-8 Y glibc aix hpux osf solaris cygwin zos
ISO-8859-9 Y glibc aix hpux irix osf solaris freebsd darwin cygwin zos
ISO-8859-13 glibc hpux solaris freebsd netbsd openbsd darwin cygwin
ISO-8859-14 glibc cygwin
ISO-8859-15 glibc aix irix osf solaris freebsd netbsd openbsd darwin cygwin
......@@ -76,7 +79,7 @@ extern const char * locale_charset (void);
CP874 windows dos
CP922 aix
CP932 aix cygwin windows dos
CP943 aix
CP943 aix zos
CP949 osf darwin windows dos
CP950 windows dos
CP1046 aix
......@@ -92,17 +95,17 @@ extern const char * locale_charset (void);
CP1255 glibc windows
CP1256 windows
CP1257 windows
GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin cygwin
GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin cygwin zos
EUC-JP Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin
EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin
EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin zos
EUC-TW glibc aix hpux irix osf solaris netbsd
BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin cygwin
BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin cygwin zos
BIG5-HKSCS glibc hpux solaris netbsd darwin
GBK glibc aix osf solaris freebsd darwin cygwin windows dos
GB18030 glibc hpux solaris freebsd netbsd darwin
SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin
JOHAB glibc solaris windows
TIS-620 glibc aix hpux osf solaris cygwin
TIS-620 glibc aix hpux osf solaris cygwin zos
VISCII Y glibc
TCVN5712-1 glibc
ARMSCII-8 glibc freebsd netbsd darwin
......@@ -116,7 +119,7 @@ extern const char * locale_charset (void);
HP-KANA8 hpux
DEC-KANJI osf
DEC-HANYU osf
UTF-8 Y glibc aix hpux osf solaris netbsd darwin cygwin
UTF-8 Y glibc aix hpux osf solaris netbsd darwin cygwin zos
Note: Names which are not marked as being a MIME name should not be used in
Internet protocols for information interchange (mail, news, etc.).
......
......@@ -206,6 +206,11 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
# endif
#endif
#if @GNULIB_SETLOCALE_NULL@
/* Included here for convenience. */
# include "setlocale_null.h"
#endif
#if /*@GNULIB_NEWLOCALE@ ||*/ (@GNULIB_LOCALENAME@ && @HAVE_NEWLOCALE@)
# if @REPLACE_NEWLOCALE@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
......
......@@ -44,17 +44,55 @@ is_using_utf8 (void)
return mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
}
/* Return true if the locale is compatible enough with the C locale so
that the locale is single-byte, bytes are in collating-sequence
order, and there are no multi-character collating elements. */
static bool
using_simple_locale (bool multibyte)
{
/* The native character set is known to be compatible with
the C locale. The following test isn't perfect, but it's good
enough in practice, as only ASCII and EBCDIC are in common use
and this test correctly accepts ASCII and rejects EBCDIC. */
enum { native_c_charset =
('\b' == 8 && '\t' == 9 && '\n' == 10 && '\v' == 11 && '\f' == 12
&& '\r' == 13 && ' ' == 32 && '!' == 33 && '"' == 34 && '#' == 35
&& '%' == 37 && '&' == 38 && '\'' == 39 && '(' == 40 && ')' == 41
&& '*' == 42 && '+' == 43 && ',' == 44 && '-' == 45 && '.' == 46
&& '/' == 47 && '0' == 48 && '9' == 57 && ':' == 58 && ';' == 59
&& '<' == 60 && '=' == 61 && '>' == 62 && '?' == 63 && 'A' == 65
&& 'Z' == 90 && '[' == 91 && '\\' == 92 && ']' == 93 && '^' == 94
&& '_' == 95 && 'a' == 97 && 'z' == 122 && '{' == 123 && '|' == 124
&& '}' == 125 && '~' == 126)
};
if (!native_c_charset || multibyte)
return false;
/* As a heuristic, use strcoll to compare native character order.
If this agrees with byte order the locale should be simple.
This heuristic should work for all known practical locales,
although it would be invalid for artificially-constructed locales
where the native order is the collating-sequence order but there
are multi-character collating elements. */
for (int i = 0; i < UCHAR_MAX; i++)
if (strcoll (((char []) {i, 0}), ((char []) {i + 1, 0})) <= 0)
return false;
return true;
}
/* Initialize *LOCALEINFO from the current locale. */
void
init_localeinfo (struct localeinfo *localeinfo)
{
int i;
localeinfo->multibyte = MB_CUR_MAX > 1;
localeinfo->simple = using_simple_locale (localeinfo->multibyte);
localeinfo->using_utf8 = is_using_utf8 ();
for (i = CHAR_MIN; i <= CHAR_MAX; i++)
for (int i = CHAR_MIN; i <= CHAR_MAX; i++)
{
char c = i;
unsigned char uc = i;
......
......@@ -28,6 +28,12 @@ struct localeinfo
/* MB_CUR_MAX > 1. */
bool multibyte;
/* The locale is simple, like the C locale. These locales can be
processed more efficiently, as they are single-byte, their native
character set is in collating-sequence order, and they do not
have multi-character collating elements. */
bool simple;
/* The locale uses UTF-8. */
bool using_utf8;
......
......@@ -34,6 +34,7 @@
#include <string.h>
#include "flexmember.h"
#include "setlocale_null.h"
/* We cannot support uselocale() on platforms where the locale_t type is fake.
See intl-thread-locale.m4 for details. */
......@@ -1151,6 +1152,10 @@ extern char * getlocalename_l(int, locale_t);
# endif
#endif
/* We want to use the system's setlocale() function here, not the gnulib
override. */
#undef setlocale
#if HAVE_CFPREFERENCESCOPYAPPVALUE
/* Mac OS X 10.4 or newer */
......@@ -2725,7 +2730,7 @@ get_locale_t_name (int category, locale_t locale)
if (locale == LC_GLOBAL_LOCALE)
{
/* Query the global locale. */
const char *name = setlocale (category, NULL);
const char *name = setlocale_null (category);
if (name != NULL)
return struniq (name);
else
......@@ -3187,6 +3192,8 @@ gl_locale_name_thread_unsafe (int category, const char *categoryname)
return "";
}
# endif
# elif defined _AIX && HAVE_NAMELESS_LOCALES
return get_locale_t_name (category, thread_locale);
# elif defined __CYGWIN__
/* Cygwin < 2.6 lacks uselocale and thread-local locales altogether.
Cygwin <= 2.6.1 lacks NL_LOCALE_NAME, requiring peeking inside
......@@ -3241,20 +3248,15 @@ gl_locale_name_posix (int category, const char *categoryname)
#if defined WINDOWS_NATIVE
if (LC_MIN <= category && category <= LC_MAX)
{
const char *locname = setlocale (category, NULL);
LCID lcid;
/* If CATEGORY is LC_ALL, the result might be a semi-colon
separated list of locales. We need only one, so we take the
one corresponding to LC_CTYPE, as the most important for
character translations. */
if (category == LC_ALL && strchr (locname, ';'))
locname = setlocale (LC_CTYPE, NULL);
const char *locname =
/* setlocale_null (category) is identical to setlocale (category, NULL)
on this platform. */
setlocale (category, NULL);
/* Convert locale name to LCID. We don't want to use
LocaleNameToLCID because (a) it is only available since Vista,
and (b) it doesn't accept locale names returned by 'setlocale'. */
lcid = get_lcid (locname);
LCID lcid = get_lcid (locname);
if (lcid > 0)
return gl_locale_name_from_win32_LCID (lcid);
......@@ -3266,7 +3268,7 @@ gl_locale_name_posix (int category, const char *categoryname)
/* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
On some systems this can be done by the 'setlocale' function itself. */
#if defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
locname = setlocale (category, NULL);
locname = setlocale_null (category);
#else
/* On other systems we ignore what setlocale reports and instead look at the
environment variables directly. This is necessary
......
......@@ -112,14 +112,10 @@ enum
among all elementary types. */
sa_alignment_long = sa_alignof (long),
sa_alignment_double = sa_alignof (double),
#if HAVE_LONG_LONG_INT
sa_alignment_longlong = sa_alignof (long long),
#endif
sa_alignment_longdouble = sa_alignof (long double),
sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1)
#if HAVE_LONG_LONG_INT
| (sa_alignment_longlong - 1)
#endif
| (sa_alignment_longdouble - 1)
) + 1
};
......
......@@ -214,12 +214,17 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
if ((c3 ^ 0x80) < 0x40)
{
if (pwc != NULL)
*pwc = ((unsigned int) (c & 0x0f) << 12)
| ((unsigned int) (c2 ^ 0x80) << 6)
| (unsigned int) (c3 ^ 0x80);
res = 3;
goto success;
unsigned int wc
= (((unsigned int) (c & 0x0f) << 12)
| ((unsigned int) (c2 ^ 0x80) << 6)
| (unsigned int) (c3 ^ 0x80));
if (wc <= WCHAR_MAX)
{
if (pwc != NULL)
*pwc = wc;
res = 3;
goto success;
}
}
}
}
......@@ -253,13 +258,19 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
if ((c4 ^ 0x80) < 0x40)
{
if (pwc != NULL)
*pwc = ((unsigned int) (c & 0x07) << 18)
| ((unsigned int) (c2 ^ 0x80) << 12)
| ((unsigned int) (c3 ^ 0x80) << 6)
| (unsigned int) (c4 ^ 0x80);
res = 4;
goto success;
unsigned int wc
= (((unsigned int) (c & 0x07) << 18)
| ((unsigned int) (c2 ^ 0x80)
<< 12)
| ((unsigned int) (c3 ^ 0x80) << 6)
| (unsigned int) (c4 ^ 0x80));
if (wc <= WCHAR_MAX)
{
if (pwc != NULL)
*pwc = wc;
res = 4;
goto success;
}
}
}
}
......
......@@ -56,13 +56,10 @@ mbsinit (const mbstate_t *ps)
{
# if defined _WIN32 && !defined __CYGWIN__
/* Native Windows. */
# ifdef __MINGW32__
/* On mingw, 'mbstate_t' is defined as 'int'. */
return ps == NULL || *ps == 0;
# else
/* MSVC defines 'mbstate_t' as an 8-byte struct; the first 4-bytes matter. */
/* MSVC defines 'mbstate_t' as an 8-byte struct; the first 4 bytes matter.
On mingw, 'mbstate_t' is sometimes defined as 'int', sometimes defined as
an 8-byte struct, of which the first 4 bytes matter. */
return ps == NULL || *(const unsigned int *)ps == 0;
# endif
# else
/* Minix, HP-UX 11.00, Solaris 2.6, Interix, ... */
/* Maybe this definition works, maybe not... */
......
......@@ -141,7 +141,7 @@ shr (long_int a, int b)
long_int one = 1;
return (-one >> 1 == -1
? a >> b
: a / (one << b) - (a % (one << b) < 0));
: (a + (a < 0)) / (one << b) - (a < 0));
}
/* Bounds for the intersection of __time64_t and long_int. */
......@@ -211,8 +211,8 @@ ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
Take care to avoid integer overflow here. */
int a4 = shr (year1, 2) + shr (TM_YEAR_BASE, 2) - ! (year1 & 3);
int b4 = shr (year0, 2) + shr (TM_YEAR_BASE, 2) - ! (year0 & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
int a100 = (a4 + (a4 < 0)) / 25 - (a4 < 0);
int b100 = (b4 + (b4 < 0)) / 25 - (b4 < 0);
int a400 = shr (a100, 2);
int b400 = shr (b100, 2);
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
......
......@@ -28,16 +28,33 @@
# include <stdio.h>
#endif
/* nl_langinfo() must be multithread-safe. To achieve this without using
thread-local storage:
1. We use a specific static buffer for each possible argument.
So that different threads can call nl_langinfo with different arguments,
without interfering.
2. We use a simple strcpy or memcpy to fill this static buffer. Filling it
through, for example, strcpy + strcat would not be guaranteed to leave
the buffer's contents intact if another thread is currently accessing
it. If necessary, the contents is first assembled in a stack-allocated
buffer. */
#if !REPLACE_NL_LANGINFO || GNULIB_defined_CODESET
/* Return the codeset of the current locale, if this is easily deducible.
Otherwise, return "". */
static char *
ctype_codeset (void)
{
static char buf[2 + 10 + 1];
char const *locale = setlocale (LC_CTYPE, NULL);
char *codeset = buf;
static char result[2 + 10 + 1];
char buf[2 + 10 + 1];
char locale[SETLOCALE_NULL_MAX];
char *codeset;
size_t codesetlen;
if (setlocale_null_r (LC_CTYPE, locale, sizeof (locale)))
locale[0] = '\0';
codeset = buf;
codeset[0] = '\0';
if (locale && locale[0])
......@@ -79,11 +96,16 @@ ctype_codeset (void)
/* For a locale name such as "French_France.65001", in Windows 10,
setlocale now returns "French_France.utf8" instead. */
if (strcmp (buf + 2, "65001") == 0 || strcmp (buf + 2, "utf8") == 0)
return "UTF-8";
return (char *) "UTF-8";
else
return memcpy (buf, "CP", 2);
{
memcpy (buf, "CP", 2);
strcpy (result, buf);
return result;
}
# else
return codeset;
strcpy (result, codeset);
return result;
#endif
}
#endif
......@@ -175,7 +197,7 @@ rpl_nl_langinfo (nl_item item)
char *
nl_langinfo (nl_item item)
{
static char nlbuf[100];
char buf[100];
struct tm tmm = { 0 };
switch (item)
......@@ -215,14 +237,22 @@ nl_langinfo (nl_item item)
case T_FMT_AMPM:
return (char *) "%I:%M:%S %p";
case AM_STR:
if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm))
return (char *) "AM";
return nlbuf;
{
static char result[80];
if (!strftime (buf, sizeof result, "%p", &tmm))
return (char *) "AM";
strcpy (result, buf);
return result;
}
case PM_STR:
tmm.tm_hour = 12;
if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm))
return (char *) "PM";
return nlbuf;
{
static char result[80];
tmm.tm_hour = 12;
if (!strftime (buf, sizeof result, "%p", &tmm))
return (char *) "PM";
strcpy (result, buf);
return result;
}
case DAY_1:
case DAY_2:
case DAY_3:
......@@ -231,14 +261,16 @@ nl_langinfo (nl_item item)
case DAY_6:
case DAY_7:
{
static char result[7][50];
static char const days[][sizeof "Wednesday"] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"
};
tmm.tm_wday = item - DAY_1;
if (!strftime (nlbuf, sizeof nlbuf, "%A", &tmm))
if (!strftime (buf, sizeof result[0], "%A", &tmm))
return (char *) days[item - DAY_1];
return nlbuf;
strcpy (result[item - DAY_1], buf);
return result[item - DAY_1];
}
case ABDAY_1:
case ABDAY_2:
......@@ -248,13 +280,15 @@ nl_langinfo (nl_item item)
case ABDAY_6:
case ABDAY_7:
{
static char result[7][30];
static char const abdays[][sizeof "Sun"] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
tmm.tm_wday = item - ABDAY_1;
if (!strftime (nlbuf, sizeof nlbuf, "%a", &tmm))
if (!strftime (buf, sizeof result[0], "%a", &tmm))
return (char *) abdays[item - ABDAY_1];
return nlbuf;
strcpy (result[item - ABDAY_1], buf);
return result[item - ABDAY_1];
}
{
static char const months[][sizeof "September"] = {
......@@ -273,10 +307,14 @@ nl_langinfo (nl_item item)
case MON_10:
case MON_11:
case MON_12:
tmm.tm_mon = item - MON_1;
if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm))
return (char *) months[item - MON_1];
return nlbuf;
{
static char result[12][50];
tmm.tm_mon = item - MON_1;
if (!strftime (buf, sizeof result[0], "%B", &tmm))
return (char *) months[item - MON_1];
strcpy (result[item - MON_1], buf);
return result[item - MON_1];
}
case ALTMON_1:
case ALTMON_2:
case ALTMON_3:
......@@ -289,15 +327,19 @@ nl_langinfo (nl_item item)
case ALTMON_10:
case ALTMON_11:
case ALTMON_12:
tmm.tm_mon = item - ALTMON_1;
/* The platforms without nl_langinfo() don't support strftime with %OB.
We don't even need to try. */
#if 0
if (!strftime (nlbuf, sizeof nlbuf, "%OB", &tmm))
#endif
if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm))
return (char *) months[item - ALTMON_1];
return nlbuf;
{
static char result[12][50];
tmm.tm_mon = item - ALTMON_1;
/* The platforms without nl_langinfo() don't support strftime with
%OB. We don't even need to try. */
#if 0
if (!strftime (buf, sizeof result[0], "%OB", &tmm))
#endif
if (!strftime (buf, sizeof result[0], "%B", &tmm))
return (char *) months[item - ALTMON_1];
strcpy (result[item - ALTMON_1], buf);
return result[item - ALTMON_1];
}
}
case ABMON_1:
case ABMON_2:
......@@ -312,14 +354,16 @@ nl_langinfo (nl_item item)
case ABMON_11:
case ABMON_12:
{
static char result[12][30];
static char const abmonths[][sizeof "Jan"] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Sep", "Oct", "Nov", "Dec"
};
tmm.tm_mon = item - ABMON_1;
if (!strftime (nlbuf, sizeof nlbuf, "%b", &tmm))
if (!strftime (buf, sizeof result[0], "%b", &tmm))
return (char *) abmonths[item - ABMON_1];
return nlbuf;
strcpy (result[item - ABMON_1], buf);
return result[item - ABMON_1];
}
case ERA:
return (char *) "";
......