POSIX-1.2008 per-thread locales, groundwork part 1

Introduce first cut of struct _thr_locale_t used for the locale_t definition.
Introduce global instance called __global_locale used by default.
Introduce internal inline functions __get_global_locale, __get_locale_r,
__get_current_locale.

Remove usage of global variables in favor of accessor functions pointing to
__global_locale for now.  Include all local headers in locale subdir from
setlocale.h to get single include for internal locale access.

Introduce __CTYPE_PTR macro to replace direct access to __ctype_ptr__
and use throughout in isxxx functions.

Signed-off by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2016-07-13 16:51:33 +02:00
parent 51b669f679
commit a6a477fa81
31 changed files with 610 additions and 484 deletions

View File

@ -98,13 +98,6 @@ char _ctype_b[128 + 256] = {
_CTYPE_DATA_128_255 _CTYPE_DATA_128_255
}; };
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
#ifndef _MB_CAPABLE
_CONST
#endif
char __EXPORT *__ctype_ptr = (char *) _ctype_b + 128;
#endif
#ifndef _MB_CAPABLE #ifndef _MB_CAPABLE
_CONST _CONST
#endif #endif
@ -135,7 +128,7 @@ _CONST char _ctype_[1 + 256] = {
}; };
# endif /* !__CYGWIN__ */ # endif /* !__CYGWIN__ */
#else /* !defined(ALLOW_NEGATIVE_CTYPE_INDEX) */ #else /* !ALLOW_NEGATIVE_CTYPE_INDEX */
_CONST char _ctype_[1 + 256] = { _CONST char _ctype_[1 + 256] = {
0, 0,
@ -143,30 +136,24 @@ _CONST char _ctype_[1 + 256] = {
_CTYPE_DATA_128_255 _CTYPE_DATA_128_255
}; };
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
#ifndef _MB_CAPABLE
_CONST
#endif
char *__ctype_ptr = (char *) _ctype_ + 1;
#endif
#ifndef _MB_CAPABLE #ifndef _MB_CAPABLE
_CONST _CONST
#endif #endif
char *__ctype_ptr__ = (char *) _ctype_; char *__ctype_ptr__ = (char *) _ctype_;
#endif #endif /* !ALLOW_NEGATIVE_CTYPE_INDEX */
#if defined(_MB_CAPABLE) #if defined(_MB_CAPABLE)
/* Cygwin has its own implementation which additionally maintains backward /* Cygwin has its own implementation which additionally maintains backward
compatibility with applications built under older Cygwin releases. */ compatibility with applications built under older Cygwin releases. */
#ifndef __CYGWIN__ #ifndef __CYGWIN__
void void
__set_ctype (const char *charset) __set_ctype (struct _reent *, const char *charset)
{ {
#if defined(_MB_EXTENDED_CHARSETS_ISO) || defined(_MB_EXTENDED_CHARSETS_WINDOWS) #if defined(_MB_EXTENDED_CHARSETS_ISO) || defined(_MB_EXTENDED_CHARSETS_WINDOWS)
int idx; int idx;
#endif #endif
char *ctype_ptr = NULL;
switch (*charset) switch (*charset)
{ {
@ -180,50 +167,32 @@ __set_ctype (const char *charset)
idx = 0; idx = 0;
else else
++idx; ++idx;
# if defined(ALLOW_NEGATIVE_CTYPE_INDEX) ctype_ptr = __ctype_iso[idx];
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION break;
__ctype_ptr = (char *) (__ctype_iso[idx] + 128);
#endif
__ctype_ptr__ = (char *) (__ctype_iso[idx] + 127);
# else
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
__ctype_ptr = (char *) __ctype_iso[idx] + 1;
#endif
__ctype_ptr__ = (char *) __ctype_iso[idx];
# endif
return;
#endif #endif
#if defined(_MB_EXTENDED_CHARSETS_WINDOWS) #if defined(_MB_EXTENDED_CHARSETS_WINDOWS)
case 'C': case 'C':
idx = __cp_index (charset + 2); idx = __cp_index (charset + 2);
if (idx < 0) if (idx < 0)
break; break;
# if defined(ALLOW_NEGATIVE_CTYPE_INDEX) ctype_ptr = __ctype_cp[idx];
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION break;
__ctype_ptr = (char *) (__ctype_cp[idx] + 128);
#endif
__ctype_ptr__ = (char *) (__ctype_cp[idx] + 127);
# else
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION
__ctype_ptr = (char *) __ctype_cp[idx] + 1;
#endif
__ctype_ptr__ = (char *) __ctype_cp[idx];
# endif
return;
#endif #endif
default: default:
break; break;
} }
if (!ctype_ptr)
{
# if defined(ALLOW_NEGATIVE_CTYPE_INDEX) # if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION ctype_ptr = _ctype_b;
__ctype_ptr = (char *) _ctype_b + 128;
#endif
__ctype_ptr__ = (char *) _ctype_b + 127;
# else # else
#ifdef _NEED_OLD_CTYPE_PTR_DEFINITION ctype_ptr = _ctype_;
__ctype_ptr = (char *) _ctype_ + 1; # endif
#endif }
__ctype_ptr__ = (char *) _ctype_; # if defined(ALLOW_NEGATIVE_CTYPE_INDEX)
__ctype_ptr__ = ctype_ptr + 127;
# else
__ctype_ptr__ = ctype_ptr;
# endif # endif
} }
#endif /* !__CYGWIN__ */ #endif /* !__CYGWIN__ */

View File

@ -41,6 +41,6 @@ No OS subroutines are required.
int int
_DEFUN(isalnum,(c),int c) _DEFUN(isalnum,(c),int c)
{ {
return(__ctype_ptr__[c+1] & (_U|_L|_N)); return(__CTYPE_PTR[c+1] & (_U|_L|_N));
} }

View File

@ -39,6 +39,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(isalpha,(c),int c) _DEFUN(isalpha,(c),int c)
{ {
return(__ctype_ptr__[c+1] & (_U|_L)); return(__CTYPE_PTR[c+1] & (_U|_L));
} }

View File

@ -38,5 +38,5 @@ No supporting OS subroutines are required.
int int
_DEFUN(isblank,(c),int c) _DEFUN(isblank,(c),int c)
{ {
return ((__ctype_ptr__[c+1] & _B) || (c == '\t')); return ((__CTYPE_PTR[c+1] & _B) || (c == '\t'));
} }

View File

@ -42,7 +42,7 @@ No supporting OS subroutines are required.
int int
_DEFUN(iscntrl,(c),int c) _DEFUN(iscntrl,(c),int c)
{ {
return(__ctype_ptr__[c+1] & _C); return(__CTYPE_PTR[c+1] & _C);
} }

View File

@ -39,5 +39,5 @@ No supporting OS subroutines are required.
int int
_DEFUN(isdigit,(c),int c) _DEFUN(isdigit,(c),int c)
{ {
return(__ctype_ptr__[c+1] & _N); return(__CTYPE_PTR[c+1] & _N);
} }

View File

@ -39,6 +39,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(islower,(c),int c) _DEFUN(islower,(c),int c)
{ {
return ((__ctype_ptr__[c+1] & (_U|_L)) == _L); return ((__CTYPE_PTR[c+1] & (_U|_L)) == _L);
} }

View File

@ -48,7 +48,7 @@ No supporting OS subroutines are required.
int int
_DEFUN(isgraph,(c),int c) _DEFUN(isgraph,(c),int c)
{ {
return(__ctype_ptr__[c+1] & (_P|_U|_L|_N)); return(__CTYPE_PTR[c+1] & (_P|_U|_L|_N));
} }

View File

@ -41,6 +41,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(ispunct,(c),int c) _DEFUN(ispunct,(c),int c)
{ {
return(__ctype_ptr__[c+1] & _P); return(__CTYPE_PTR[c+1] & _P);
} }

View File

@ -39,6 +39,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(isspace,(c),int c) _DEFUN(isspace,(c),int c)
{ {
return(__ctype_ptr__[c+1] & _S); return(__CTYPE_PTR[c+1] & _S);
} }

View File

@ -38,6 +38,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(isupper,(c),int c) _DEFUN(isupper,(c),int c)
{ {
return ((__ctype_ptr__[c+1] & (_U|_L)) == _U); return ((__CTYPE_PTR[c+1] & (_U|_L)) == _U);
} }

View File

@ -40,6 +40,6 @@ No supporting OS subroutines are required.
int int
_DEFUN(isxdigit,(c),int c) _DEFUN(isxdigit,(c),int c)
{ {
return(__ctype_ptr__[c+1] & ((_X)|(_N))); return(__CTYPE_PTR[c+1] & ((_X)|(_N)));
} }

View File

@ -44,18 +44,24 @@ int _EXFUN(toascii, (int __c));
_CONST _CONST
#endif #endif
extern __IMPORT char *__ctype_ptr__; extern __IMPORT char *__ctype_ptr__;
#ifdef __HAVE_LOCALE_INFO__
char *_EXFUN(__locale_ctype_ptr, (void));
# define __CTYPE_PTR (__locale_ctype_ptr ())
#else
# define __CTYPE_PTR (__ctype_ptr__)
#endif
#ifndef __cplusplus #ifndef __cplusplus
/* These macros are intentionally written in a manner that will trigger /* These macros are intentionally written in a manner that will trigger
a gcc -Wall warning if the user mistakenly passes a 'char' instead a gcc -Wall warning if the user mistakenly passes a 'char' instead
of an int containing an 'unsigned char'. Note that the sizeof will of an int containing an 'unsigned char'. Note that the sizeof will
always be 1, which is what we want for mapping EOF to __ctype_ptr__[0]; always be 1, which is what we want for mapping EOF to __CTYPE_PTR[0];
the use of a raw index inside the sizeof triggers the gcc warning if the use of a raw index inside the sizeof triggers the gcc warning if
__c was of type char, and sizeof masks side effects of the extra __c. __c was of type char, and sizeof masks side effects of the extra __c.
Meanwhile, the real index to __ctype_ptr__+1 must be cast to int, Meanwhile, the real index to __CTYPE_PTR+1 must be cast to int,
since isalpha(0x100000001LL) must equal isalpha(1), rather than being since isalpha(0x100000001LL) must equal isalpha(1), rather than being
an out-of-bounds reference on a 64-bit machine. */ an out-of-bounds reference on a 64-bit machine. */
#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) #define __ctype_lookup(__c) ((__CTYPE_PTR+sizeof(""[__c]))[(int)(__c)])
#define isalpha(__c) (__ctype_lookup(__c)&(_U|_L)) #define isalpha(__c) (__ctype_lookup(__c)&(_U|_L))
#define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U) #define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U)
@ -92,10 +98,10 @@ extern __IMPORT char *__ctype_ptr__;
function. */ function. */
# define toupper(__c) \ # define toupper(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \ __extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (toupper) (__x);}) (void) __CTYPE_PTR[__x]; (toupper) (__x);})
# define tolower(__c) \ # define tolower(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \ __extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (tolower) (__x);}) (void) __CTYPE_PTR[__x]; (tolower) (__x);})
# endif /* _MB_EXTENDED_CHARSETS* */ # endif /* _MB_EXTENDED_CHARSETS* */
# endif /* __GNUC__ */ # endif /* __GNUC__ */

View File

@ -20,6 +20,21 @@
#define LC_TIME 5 #define LC_TIME 5
#define LC_MESSAGES 6 #define LC_MESSAGES 6
#if __POSIX_VISIBLE >= 200809
#define LC_ALL_MASK (1 << LC_ALL)
#define LC_COLLATE_MASK (1 << LC_COLLATE)
#define LC_CTYPE_MASK (1 << LC_CTYPE)
#define LC_MONETARY_MASK (1 << LC_MONETARY)
#define LC_NUMERIC_MASK (1 << LC_NUMERIC)
#define LC_TIME_MASK (1 << LC_TIME)
#define LC_MESSAGES_MASK (1 << LC_MESSAGES)
#define LC_GLOBAL_LOCALE ((struct _thr_locale_t *) -1)
struct _thr_locale_t;
typedef struct _thr_locale_t *locale_t;
#endif
_BEGIN_STD_C _BEGIN_STD_C
struct lconv struct lconv

View File

@ -21,9 +21,6 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <limits.h>
#include <string.h>
#include "lctype.h"
#include "ldpart.h" #include "ldpart.h"
#include "setlocale.h" #include "setlocale.h"
@ -53,43 +50,63 @@ static char *_ctype_locale_buf;
static char _ctype_locale_buf[_CTYPE_BUF_SIZE]; static char _ctype_locale_buf[_CTYPE_BUF_SIZE];
#endif #endif
/* NULL locale indicates global locale (called from setlocale) */
int int
__ctype_load_locale(const char *name, void *f_wctomb, const char *charset, __ctype_load_locale (struct _thr_locale_t *locale, const char *name,
int mb_cur_max) void *f_wctomb, const char *charset, int mb_cur_max)
{ {
int ret; int ret;
struct lc_ctype_T ct;
char *bufp = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern int __set_lc_ctype_from_win (const char *, extern int __set_lc_ctype_from_win (const char *, const struct lc_ctype_T *,
const struct lc_ctype_T *, struct lc_ctype_T *, char **, void *,
struct lc_ctype_T *, char **, const char *, int);
void *, const char *, int); ret = __set_lc_ctype_from_win (name, &_C_ctype_locale, &ct, &bufp,
int old_ctype_using_locale = _ctype_using_locale; f_wctomb, charset, mb_cur_max);
_ctype_using_locale = 0;
ret = __set_lc_ctype_from_win (name, &_C_ctype_locale, &_ctype_locale,
&_ctype_locale_buf, f_wctomb, charset,
mb_cur_max);
/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
if (ret < 0) if (ret >= 0)
_ctype_using_locale = old_ctype_using_locale;
else
{ {
_ctype_using_locale = ret; struct lc_ctype_T *ctp = NULL;
if (ret > 0)
{
ctp = (struct lc_ctype_T *) calloc (1, sizeof *ctp);
if (!ctp)
return -1;
memcpy (ctp, &ct, sizeof *ctp);
}
locale->ctype = ret == 0 ? NULL : ctp;
if (locale->ctype_buf)
free (locale->ctype_buf);
locale->ctype_buf = bufp;
ret = 0; ret = 0;
} }
#elif !defined (__HAVE_LOCALE_INFO_EXTENDED__) #elif !defined (__HAVE_LOCALE_INFO_EXTENDED__)
ret = 0;
if (!strcmp (name, "C")) if (!strcmp (name, "C"))
_ctype_using_locale = 0; locale->ctype = NULL;
else else
{ {
_ctype_locale.codeset = strcpy (_ctype_locale_buf, charset); if (locale == __get_global_locale ())
char *mbc = _ctype_locale_buf + _CTYPE_BUF_SIZE - 2; bufp = _ctype_locale_buf;
else
bufp = (char *) malloc (_CTYPE_BUF_SIZE);
if (*bufp)
{
_ctype_locale.codeset = strcpy (bufp, charset);
char *mbc = bufp + _CTYPE_BUF_SIZE - 2;
mbc[0] = mb_cur_max; mbc[0] = mb_cur_max;
mbc[1] = '\0'; mbc[1] = '\0';
_ctype_locale.mb_cur_max = mbc; _ctype_locale.mb_cur_max = mbc;
_ctype_using_locale = 1; if (locale->ctype_buf && locale->ctype_buf != _ctype_locale_buf)
free (locale->ctype_buf);
locale->ctype_buf = bufp;
}
else
ret = -1;
} }
ret = 0;
#else #else
ret = __part_load_locale(name, &_ctype_using_locale, ret = __part_load_locale(name, &_ctype_using_locale,
_ctype_locale_buf, "LC_CTYPE", _ctype_locale_buf, "LC_CTYPE",
@ -103,9 +120,8 @@ __ctype_load_locale(const char *name, void *f_wctomb, const char *charset,
} }
struct lc_ctype_T * struct lc_ctype_T *
__get_current_ctype_locale(void) { __get_current_ctype_locale (void)
{
return (_ctype_using_locale struct _thr_locale_t *cur_locale = __get_current_locale ();
? &_ctype_locale return cur_locale->ctype ?: (struct lc_ctype_T *) &_C_ctype_locale;
: (struct lc_ctype_T *)&_C_ctype_locale);
} }

View File

@ -39,8 +39,9 @@ struct lc_ctype_T {
#endif #endif
}; };
struct lc_ctype_T *__get_current_ctype_locale(void); struct lc_ctype_T *__get_current_ctype_locale (void);
int __ctype_load_locale(const char *, void *, const char *, int); int __ctype_load_locale (struct _thr_locale_t *, const char *, void *,
const char *, int);
__END_DECLS __END_DECLS

View File

@ -28,7 +28,7 @@
#include <stddef.h> #include <stddef.h>
#include "lmessages.h" #include "setlocale.h"
#include "ldpart.h" #include "ldpart.h"
#define LCMESSAGES_SIZE_FULL (sizeof(struct lc_messages_T) / sizeof(char *)) #define LCMESSAGES_SIZE_FULL (sizeof(struct lc_messages_T) / sizeof(char *))
@ -53,35 +53,46 @@ static const struct lc_messages_T _C_messages_locale = {
#endif #endif
}; };
#ifndef __CYGWIN__
static struct lc_messages_T _messages_locale; static struct lc_messages_T _messages_locale;
static int _messages_using_locale; static int _messages_using_locale;
static char *_messages_locale_buf; static char *_messages_locale_buf;
#endif
int int
__messages_load_locale (const char *name, void *f_wctomb, const char *charset) __messages_load_locale (struct _thr_locale_t *locale, const char *name,
void *f_wctomb, const char *charset)
{ {
int ret;
struct lc_messages_T me;
char *bufp = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern int __set_lc_messages_from_win (const char *, extern int __set_lc_messages_from_win (const char *,
const struct lc_messages_T *, const struct lc_messages_T *,
struct lc_messages_T *, char **, struct lc_messages_T *, char **,
void *, const char *); void *, const char *);
int ret;
int old_messages_using_locale = _messages_using_locale; ret = __set_lc_messages_from_win (name, &_C_messages_locale, &me, &bufp,
_messages_using_locale = 0;
ret = __set_lc_messages_from_win (name, &_C_messages_locale,
&_messages_locale,
&_messages_locale_buf,
f_wctomb, charset); f_wctomb, charset);
/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
if (ret < 0) if (ret >= 0)
_messages_using_locale = old_messages_using_locale;
else
{ {
_messages_using_locale = ret; struct lc_messages_T *mep = NULL;
if (ret > 0)
{
mep = (struct lc_messages_T *) calloc (1, sizeof *mep);
if (!mep)
return -1;
memcpy (mep, &me, sizeof *mep);
}
locale->messages = ret == 0 ? NULL : mep;
if (locale->messages_buf)
free (locale->messages_buf);
locale->messages_buf = bufp;
ret = 0; ret = 0;
} }
return ret;
#else #else
/* /*
* Propose that we can have incomplete locale file (w/o "{yes,no}str"). * Propose that we can have incomplete locale file (w/o "{yes,no}str").
@ -91,19 +102,19 @@ __messages_load_locale (const char *name, void *f_wctomb, const char *charset)
_messages_locale.yesstr = empty; _messages_locale.yesstr = empty;
_messages_locale.nostr = empty; _messages_locale.nostr = empty;
return __part_load_locale(name, &_messages_using_locale, ret = __part_load_locale(name, &_messages_using_locale,
_messages_locale_buf, "LC_MESSAGES", _messages_locale_buf, "LC_MESSAGES",
LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN, LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
(const char **)&_messages_locale); (const char **)&_messages_locale);
#endif #endif
return ret;
} }
struct lc_messages_T * struct lc_messages_T *
__get_current_messages_locale(void) { __get_current_messages_locale (void)
{
return (_messages_using_locale struct _thr_locale_t *cur_locale = __get_current_locale ();
? &_messages_locale return cur_locale->messages ?: (struct lc_messages_T *) &_C_messages_locale;
: (struct lc_messages_T *)&_C_messages_locale);
} }
#ifdef LOCALE_DEBUG #ifdef LOCALE_DEBUG

View File

@ -49,8 +49,9 @@ struct lc_messages_T {
#endif #endif
}; };
struct lc_messages_T *__get_current_messages_locale(void); struct lc_messages_T *__get_current_messages_locale (void);
int __messages_load_locale(const char *, void *, const char *); int __messages_load_locale (struct _thr_locale_t *, const char *, void *,
const char *);
__END_DECLS __END_DECLS

View File

@ -28,10 +28,9 @@
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include "lmonetary.h" #include "setlocale.h"
#include "ldpart.h" #include "ldpart.h"
extern int __mlocale_changed;
extern const char * __fix_locale_grouping_str(const char *); extern const char * __fix_locale_grouping_str(const char *);
#define LCMONETARY_SIZE (sizeof(struct lc_monetary_T) / sizeof(char *)) #define LCMONETARY_SIZE (sizeof(struct lc_monetary_T) / sizeof(char *))
@ -75,11 +74,11 @@ static const struct lc_monetary_T _C_monetary_locale = {
#endif #endif
}; };
#ifndef __CYGWIN__
static struct lc_monetary_T _monetary_locale; static struct lc_monetary_T _monetary_locale;
static int _monetary_using_locale; static int _monetary_using_locale;
static char *_monetary_locale_buf; static char *_monetary_locale_buf;
#ifndef __CYGWIN__
static char static char
cnv(const char *str) { cnv(const char *str) {
int i = strtol(str, NULL, 10); int i = strtol(str, NULL, 10);
@ -90,32 +89,39 @@ cnv(const char *str) {
#endif #endif
int int
__monetary_load_locale(const char *name , void *f_wctomb, const char *charset) __monetary_load_locale (struct _thr_locale_t *locale, const char *name ,
void *f_wctomb, const char *charset)
{ {
int ret; int ret;
struct lc_monetary_T mo;
char *bufp = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern int __set_lc_monetary_from_win (const char *, extern int __set_lc_monetary_from_win (const char *,
const struct lc_monetary_T *, const struct lc_monetary_T *,
struct lc_monetary_T *, char **, struct lc_monetary_T *, char **,
void *, const char *); void *, const char *);
int old_monetary_using_locale = _monetary_using_locale; ret = __set_lc_monetary_from_win (name, &_C_monetary_locale, &mo, &bufp,
_monetary_using_locale = 0;
ret = __set_lc_monetary_from_win (name, &_C_monetary_locale,
&_monetary_locale,
&_monetary_locale_buf,
f_wctomb, charset); f_wctomb, charset);
/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
if (ret < 0) if (ret >= 0)
_monetary_using_locale = old_monetary_using_locale;
else
{ {
_monetary_using_locale = ret; struct lc_monetary_T *mop = NULL;
__mlocale_changed = 1;
if (ret > 0)
{
mop = (struct lc_monetary_T *) calloc (1, sizeof *mop);
if (!mop)
return -1;
memcpy (mop, &mo, sizeof *mop);
}
locale->monetary = ret == 0 ? NULL : mop;
if (locale->monetary_buf)
free (locale->monetary_buf);
locale->monetary_buf = bufp;
ret = 0; ret = 0;
} }
#else #else
__mlocale_changed = 1;
ret = __part_load_locale(name, &_monetary_using_locale, ret = __part_load_locale(name, &_monetary_using_locale,
_monetary_locale_buf, "LC_MONETARY", _monetary_locale_buf, "LC_MONETARY",
LCMONETARY_SIZE, LCMONETARY_SIZE, LCMONETARY_SIZE, LCMONETARY_SIZE,
@ -141,46 +147,8 @@ __monetary_load_locale(const char *name , void *f_wctomb, const char *charset)
} }
struct lc_monetary_T * struct lc_monetary_T *
__get_current_monetary_locale(void) { __get_current_monetary_locale (void)
{
return (_monetary_using_locale struct _thr_locale_t *cur_locale = __get_current_locale ();
? &_monetary_locale return cur_locale->monetary ?: (struct lc_monetary_T *) &_C_monetary_locale;
: (struct lc_monetary_T *)&_C_monetary_locale);
} }
#ifdef LOCALE_DEBUG
void
monetdebug() {
printf( "int_curr_symbol = %s\n"
"currency_symbol = %s\n"
"mon_decimal_point = %s\n"
"mon_thousands_sep = %s\n"
"mon_grouping = %s\n"
"positive_sign = %s\n"
"negative_sign = %s\n"
"int_frac_digits = %d\n"
"frac_digits = %d\n"
"p_cs_precedes = %d\n"
"p_sep_by_space = %d\n"
"n_cs_precedes = %d\n"
"n_sep_by_space = %d\n"
"p_sign_posn = %d\n"
"n_sign_posn = %d\n",
_monetary_locale.int_curr_symbol,
_monetary_locale.currency_symbol,
_monetary_locale.mon_decimal_point,
_monetary_locale.mon_thousands_sep,
_monetary_locale.mon_grouping,
_monetary_locale.positive_sign,
_monetary_locale.negative_sign,
_monetary_locale.int_frac_digits[0],
_monetary_locale.frac_digits[0],
_monetary_locale.p_cs_precedes[0],
_monetary_locale.p_sep_by_space[0],
_monetary_locale.n_cs_precedes[0],
_monetary_locale.n_sep_by_space[0],
_monetary_locale.p_sign_posn[0],
_monetary_locale.n_sign_posn[0]
);
}
#endif /* LOCALE_DEBUG */

View File

@ -68,8 +68,9 @@ struct lc_monetary_T {
#endif #endif
}; };
struct lc_monetary_T *__get_current_monetary_locale(void); struct lc_monetary_T *__get_current_monetary_locale (void);
int __monetary_load_locale(const char *, void *, const char *); int __monetary_load_locale (struct _thr_locale_t *, const char *, void *,
const char *);
__END_DECLS __END_DECLS

View File

@ -24,11 +24,9 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <limits.h> #include "setlocale.h"
#include "lnumeric.h"
#include "ldpart.h" #include "ldpart.h"
extern int __nlocale_changed;
extern const char *__fix_locale_grouping_str(const char *); extern const char *__fix_locale_grouping_str(const char *);
#define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *)) #define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
@ -46,36 +44,46 @@ static const struct lc_numeric_T _C_numeric_locale = {
#endif #endif
}; };
#ifndef __CYGWIN__
static struct lc_numeric_T _numeric_locale; static struct lc_numeric_T _numeric_locale;
static int _numeric_using_locale; static int _numeric_using_locale;
static char *_numeric_locale_buf; static char *_numeric_locale_buf;
#endif
int int
__numeric_load_locale(const char *name , void *f_wctomb, const char *charset) __numeric_load_locale (struct _thr_locale_t *locale, const char *name ,
void *f_wctomb, const char *charset)
{ {
int ret; int ret;
struct lc_numeric_T nm;
char *bufp = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern int __set_lc_numeric_from_win (const char *, extern int __set_lc_numeric_from_win (const char *,
const struct lc_numeric_T *, const struct lc_numeric_T *,
struct lc_numeric_T *, char **, struct lc_numeric_T *, char **,
void *, const char *); void *, const char *);
int old_numeric_using_locale = _numeric_using_locale; ret = __set_lc_numeric_from_win (name, &_C_numeric_locale, &nm, &bufp,
_numeric_using_locale = 0;
ret = __set_lc_numeric_from_win (name, &_C_numeric_locale,
&_numeric_locale, &_numeric_locale_buf,
f_wctomb, charset); f_wctomb, charset);
/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
if (ret < 0) if (ret >= 0)
_numeric_using_locale = old_numeric_using_locale;
else
{ {
_numeric_using_locale = ret; struct lc_numeric_T *nmp = NULL;
__nlocale_changed = 1;
if (ret > 0)
{
nmp = (struct lc_numeric_T *) calloc (1, sizeof *nmp);
if (!nmp)
return -1;
memcpy (nmp, &nm, sizeof *nmp);
}
locale->numeric = ret == 0 ? NULL : nmp;
if (locale->numeric_buf)
free (locale->numeric_buf);
locale->numeric_buf = bufp;
ret = 0; ret = 0;
} }
#else #else
__nlocale_changed = 1;
ret = __part_load_locale(name, &_numeric_using_locale, ret = __part_load_locale(name, &_numeric_using_locale,
_numeric_locale_buf, "LC_NUMERIC", _numeric_locale_buf, "LC_NUMERIC",
LCNUMERIC_SIZE, LCNUMERIC_SIZE, LCNUMERIC_SIZE, LCNUMERIC_SIZE,
@ -88,22 +96,8 @@ __numeric_load_locale(const char *name , void *f_wctomb, const char *charset)
} }
struct lc_numeric_T * struct lc_numeric_T *
__get_current_numeric_locale(void) { __get_current_numeric_locale (void)
{
return (_numeric_using_locale struct _thr_locale_t *cur_locale = __get_current_locale ();
? &_numeric_locale return cur_locale->numeric ?: (struct lc_numeric_T *) &_C_numeric_locale;
: (struct lc_numeric_T *)&_C_numeric_locale);
} }
#ifdef LOCALE_DEBUG
void
numericdebug(void) {
printf( "decimal_point = %s\n"
"thousands_sep = %s\n"
"grouping = %s\n",
_numeric_locale.decimal_point,
_numeric_locale.thousands_sep,
_numeric_locale.grouping
);
}
#endif /* LOCALE_DEBUG */

View File

@ -46,8 +46,9 @@ struct lc_numeric_T {
#endif #endif
}; };
struct lc_numeric_T *__get_current_numeric_locale(void); struct lc_numeric_T *__get_current_numeric_locale (void);
int __numeric_load_locale(const char *, void *, const char *); int __numeric_load_locale (struct _thr_locale_t *, const char *, void *,
const char *);
__END_DECLS __END_DECLS

View File

@ -172,30 +172,22 @@ No supporting OS subroutines are required.
#include <newlib.h> #include <newlib.h>
#include <errno.h> #include <errno.h>
#include <locale.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <reent.h> #include <reent.h>
#include <stdlib.h> #include <stdlib.h>
#include <wchar.h> #include <wchar.h>
#include "lmessages.h" #include "setlocale.h"
#include "lmonetary.h"
#include "lnumeric.h"
#include "lctype.h"
#include "timelocal.h"
#include "../stdlib/local.h" #include "../stdlib/local.h"
#define _LC_LAST 7 #ifdef __CYGWIN__ /* Has to be kept available as exported symbol for
#define ENCODING_LEN 31 backward compatibility. Set it in setlocale, but
otherwise ignore it. Applications compiled after
#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */ 2010 don't use it anymore. */
int __EXPORT __mb_cur_max = 6; int __EXPORT __mb_cur_max = 6;
#else
int __EXPORT __mb_cur_max = 1;
#endif #endif
int __nlocale_changed = 0;
int __mlocale_changed = 0;
char *_PathLocale = NULL; char *_PathLocale = NULL;
static static
@ -234,44 +226,56 @@ static char *categories[_LC_LAST] = {
*/ */
char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE; char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE;
/* struct _thr_locale_t __global_locale =
* Current locales for each category {
*/ { "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
static char current_categories[_LC_LAST][ENCODING_LEN + 1] = { #ifdef __CYGWIN__
"C", __utf8_wctomb,
"C", __utf8_mbtowc,
#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */
"C.UTF-8",
#else #else
"C", __ascii_wctomb,
__ascii_mbtowc,
#endif
NULL,
0,
#ifndef __HAVE_LOCALE_INFO__
"\1",
"ASCII",
"ASCII",
#else
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
#ifdef __CYGWIN__
NULL,
#endif
#endif #endif
"C",
"C",
"C",
"C",
}; };
/* /*
* The locales we are going to try and load * The locales we are going to try and load. These are only temporary
* variables and only used in setlocale.
*/ */
static char new_categories[_LC_LAST][ENCODING_LEN + 1]; static char new_categories[_LC_LAST][ENCODING_LEN + 1];
static char saved_categories[_LC_LAST][ENCODING_LEN + 1]; static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; /* Renamed from current_locale_string to make clear this is only the
*global* string for setlocale (LC_ALL, NULL). There's no equivalent
functionality for uselocale. */
static char global_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
static char *currentlocale(void); static char *currentlocale(void);
static char *loadlocale(struct _reent *, int); static char *loadlocale(struct _reent *, int);
static const char *__get_locale_env(struct _reent *, int); static const char *__get_locale_env(struct _reent *, int);
#endif /* _MB_CAPABLE */ #endif /* _MB_CAPABLE */
#ifdef __CYGWIN__
static char lc_ctype_charset[ENCODING_LEN + 1] = "UTF-8";
#else
static char lc_ctype_charset[ENCODING_LEN + 1] = "ASCII";
#endif
static char lc_message_charset[ENCODING_LEN + 1] = "ASCII";
static int lc_ctype_cjk_lang = 0;
char * char *
_DEFUN(_setlocale_r, (p, category, locale), _DEFUN(_setlocale_r, (p, category, locale),
struct _reent *p _AND struct _reent *p _AND
@ -297,13 +301,13 @@ _DEFUN(_setlocale_r, (p, category, locale),
} }
if (locale == NULL) if (locale == NULL)
return category != LC_ALL ? current_categories[category] : currentlocale(); return category != LC_ALL ? __global_locale.categories[category] : currentlocale();
/* /*
* Default to the current locale for everything. * Default to the current locale for everything.
*/ */
for (i = 1; i < _LC_LAST; ++i) for (i = 1; i < _LC_LAST; ++i)
strcpy (new_categories[i], current_categories[i]); strcpy (new_categories[i], __global_locale.categories[i]);
/* /*
* Now go fill up new_categories from the locale argument * Now go fill up new_categories from the locale argument
@ -395,7 +399,7 @@ _DEFUN(_setlocale_r, (p, category, locale),
for (i = 1; i < _LC_LAST; ++i) for (i = 1; i < _LC_LAST; ++i)
{ {
strcpy (saved_categories[i], current_categories[i]); strcpy (saved_categories[i], __global_locale.categories[i]);
if (loadlocale (p, i) == NULL) if (loadlocale (p, i) == NULL)
{ {
saverr = p->_errno; saverr = p->_errno;
@ -422,18 +426,18 @@ currentlocale()
{ {
int i; int i;
(void)strcpy(current_locale_string, current_categories[1]); (void)strcpy(global_locale_string, __global_locale.categories[1]);
for (i = 2; i < _LC_LAST; ++i) for (i = 2; i < _LC_LAST; ++i)
if (strcmp(current_categories[1], current_categories[i])) { if (strcmp(__global_locale.categories[1], __global_locale.categories[i])) {
for (i = 2; i < _LC_LAST; ++i) { for (i = 2; i < _LC_LAST; ++i) {
(void)strcat(current_locale_string, "/"); (void)strcat(global_locale_string, "/");
(void)strcat(current_locale_string, (void)strcat(global_locale_string,
current_categories[i]); __global_locale.categories[i]);
} }
break; break;
} }
return (current_locale_string); return (global_locale_string);
} }
#endif /* _MB_CAPABLE */ #endif /* _MB_CAPABLE */
@ -441,10 +445,11 @@ currentlocale()
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern void __set_charset_from_locale (const char *locale, char *charset); extern void __set_charset_from_locale (const char *locale, char *charset);
extern char *__set_locale_from_locale_alias (const char *, char *); extern char *__set_locale_from_locale_alias (const char *, char *);
extern int __collate_load_locale (const char *, void *, const char *); extern int __collate_load_locale (struct _thr_locale_t *, const char *, void *,
const char *);
#endif /* __CYGWIN__ */ #endif /* __CYGWIN__ */
extern void __set_ctype (const char *charset); extern void __set_ctype (struct _reent *, const char *charset);
static char * static char *
loadlocale(struct _reent *p, int category) loadlocale(struct _reent *p, int category)
@ -455,7 +460,7 @@ loadlocale(struct _reent *p, int category)
The string must be in one of the allowed locale strings, either The string must be in one of the allowed locale strings, either
one in POSIX-style, or one in the old newlib style to maintain one in POSIX-style, or one in the old newlib style to maintain
backward compatibility. If the local string is correct, the charset backward compatibility. If the local string is correct, the charset
is extracted and stored in lc_ctype_charset or lc_message_charset is extracted and stored in ctype_codeset or message_charset
dependent on the cateogry. */ dependent on the cateogry. */
char *locale = NULL; char *locale = NULL;
char charset[ENCODING_LEN + 1]; char charset[ENCODING_LEN + 1];
@ -468,8 +473,8 @@ loadlocale(struct _reent *p, int category)
int cjknarrow = 0; int cjknarrow = 0;
/* Avoid doing everything twice if nothing has changed. */ /* Avoid doing everything twice if nothing has changed. */
if (!strcmp (new_categories[category], current_categories[category])) if (!strcmp (new_categories[category], __global_locale.categories[category]))
return current_categories[category]; return __global_locale.categories[category];
#ifdef __CYGWIN__ #ifdef __CYGWIN__
/* This additional code handles the case that the incoming locale string /* This additional code handles the case that the incoming locale string
@ -852,49 +857,61 @@ restart:
switch (category) switch (category)
{ {
case LC_CTYPE: case LC_CTYPE:
strcpy (lc_ctype_charset, charset); #ifndef __HAVE_LOCALE_INFO__
__mb_cur_max = mbc_max; strcpy (__global_locale.ctype_codeset, charset);
__global_locale.mb_cur_max[0] = mbc_max;
#endif
#ifdef __CYGWIN__
__mb_cur_max = mbc_max; /* Only for backward compat */
#endif
__wctomb = l_wctomb; __wctomb = l_wctomb;
__mbtowc = l_mbtowc; __mbtowc = l_mbtowc;
__set_ctype (charset); __set_ctype (NULL, charset);
/* Determine the width for the "CJK Ambiguous Width" category of /* Determine the width for the "CJK Ambiguous Width" category of
characters. This is used in wcwidth(). Assume single width for characters. This is used in wcwidth(). Assume single width for
single-byte charsets, and double width for multi-byte charsets single-byte charsets, and double width for multi-byte charsets
other than UTF-8. For UTF-8, use double width for the East Asian other than UTF-8. For UTF-8, use double width for the East Asian
languages ("ja", "ko", "zh"), and single width for everything else. languages ("ja", "ko", "zh"), and single width for everything else.
Single width can also be forced with the "@cjknarrow" modifier. */ Single width can also be forced with the "@cjknarrow" modifier. */
lc_ctype_cjk_lang = !cjknarrow __global_locale.cjk_lang = !cjknarrow
&& mbc_max > 1 && mbc_max > 1
&& (charset[0] != 'U' && (charset[0] != 'U'
|| strncmp (locale, "ja", 2) == 0 || strncmp (locale, "ja", 2) == 0
|| strncmp (locale, "ko", 2) == 0 || strncmp (locale, "ko", 2) == 0
|| strncmp (locale, "zh", 2) == 0); || strncmp (locale, "zh", 2) == 0);
#ifdef __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
ret = __ctype_load_locale (locale, (void *) l_wctomb, charset, mbc_max); ret = __ctype_load_locale (__get_global_locale (), locale,
(void *) l_wctomb, charset, mbc_max);
#endif /* __HAVE_LOCALE_INFO__ */ #endif /* __HAVE_LOCALE_INFO__ */
break; break;
case LC_MESSAGES: case LC_MESSAGES:
strcpy (lc_message_charset, charset);
#ifdef __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
ret = __messages_load_locale (locale, (void *) l_wctomb, charset); ret = __messages_load_locale (__get_global_locale (), locale,
(void *) l_wctomb, charset);
if (!ret) if (!ret)
#else
strcpy (__global_locale.message_codeset, charset);
#endif /* __HAVE_LOCALE_INFO__ */ #endif /* __HAVE_LOCALE_INFO__ */
break; break;
#ifdef __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
#ifdef __CYGWIN__ #ifdef __CYGWIN__
/* Right now only Cygwin supports a __collate_load_locale function at all. */ /* Right now only Cygwin supports a __collate_load_locale function at all. */
case LC_COLLATE: case LC_COLLATE:
ret = __collate_load_locale (locale, (void *) l_mbtowc, charset); ret = __collate_load_locale (__get_global_locale (), locale,
(void *) l_mbtowc, charset);
break; break;
#endif #endif
case LC_MONETARY: case LC_MONETARY:
ret = __monetary_load_locale (locale, (void *) l_wctomb, charset); ret = __monetary_load_locale (__get_global_locale (), locale,
(void *) l_wctomb, charset);
break; break;
case LC_NUMERIC: case LC_NUMERIC:
ret = __numeric_load_locale (locale, (void *) l_wctomb, charset); ret = __numeric_load_locale (__get_global_locale (), locale,
(void *) l_wctomb, charset);
break; break;
case LC_TIME: case LC_TIME:
ret = __time_load_locale (locale, (void *) l_wctomb, charset); ret = __time_load_locale (__get_global_locale (), locale,
(void *) l_wctomb, charset);
break; break;
#endif /* __HAVE_LOCALE_INFO__ */ #endif /* __HAVE_LOCALE_INFO__ */
default: default:
@ -904,7 +921,7 @@ restart:
if (ret) if (ret)
FAIL; FAIL;
#endif /* __HAVE_LOCALE_INFO__ */ #endif /* __HAVE_LOCALE_INFO__ */
return strcpy(current_categories[category], new_categories[category]); return strcpy(__global_locale.categories[category], new_categories[category]);
} }
static const char * static const char *
@ -934,56 +951,66 @@ __get_locale_env(struct _reent *p, int category)
char * char *
_DEFUN_VOID(__locale_charset) _DEFUN_VOID(__locale_charset)
{ {
#if 0//def __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
return __get_current_ctype_locale ()->codeset; return (char *) __get_current_ctype_locale ()->codeset;
#else #else
return lc_ctype_charset; return __global_locale.ctype_codeset;
#endif #endif
} }
int int
_DEFUN_VOID(__locale_mb_cur_max) _DEFUN_VOID(__locale_mb_cur_max)
{ {
#if 0//def __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
return __get_current_ctype_locale ()->mb_cur_max[0]; return __get_current_ctype_locale ()->mb_cur_max[0];
#else #else
return __mb_cur_max; return __global_locale.mb_cur_max[0];
#endif #endif
} }
char * char *
_DEFUN_VOID(__locale_msgcharset) _DEFUN_VOID(__locale_msgcharset)
{ {
#ifdef __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
return (char *) __get_current_messages_locale ()->codeset; return (char *) __get_current_messages_locale ()->codeset;
#else #else
return lc_message_charset; return (char *) __global_locale.message_codeset;
#endif #endif
} }
int int
_DEFUN_VOID(__locale_cjk_lang) _DEFUN_VOID(__locale_cjk_lang)
{ {
return lc_ctype_cjk_lang; #ifdef __HAVE_LOCALE_INFO__
return __get_current_locale ()->cjk_lang;
#else
return __global_locale.cjk_lang;
#endif
} }
#ifdef __HAVE_LOCALE_INFO__
char *
_DEFUN_VOID(__locale_ctype_ptr)
{
/* Only check if the current thread/reent has a locale. ctype_ptr is unused
in __global_locale, rather the global variable __ctype_ptr__ is used. */
return __get_locale_r (_REENT) ? __get_locale_r (_REENT)->ctype_ptr
: __ctype_ptr__;
}
#endif
struct lconv * struct lconv *
_DEFUN(_localeconv_r, (data), _DEFUN(_localeconv_r, (data),
struct _reent *data) struct _reent *data)
{ {
#ifdef __HAVE_LOCALE_INFO__ #ifdef __HAVE_LOCALE_INFO__
if (__nlocale_changed)
{
struct lc_numeric_T *n = __get_current_numeric_locale (); struct lc_numeric_T *n = __get_current_numeric_locale ();
struct lc_monetary_T *m = __get_current_monetary_locale ();
lconv.decimal_point = (char *) n->decimal_point; lconv.decimal_point = (char *) n->decimal_point;
lconv.thousands_sep = (char *) n->thousands_sep; lconv.thousands_sep = (char *) n->thousands_sep;
lconv.grouping = (char *) n->grouping; lconv.grouping = (char *) n->grouping;
__nlocale_changed = 0;
}
if (__mlocale_changed)
{
struct lc_monetary_T *m = __get_current_monetary_locale ();
lconv.int_curr_symbol = (char *) m->int_curr_symbol; lconv.int_curr_symbol = (char *) m->int_curr_symbol;
lconv.currency_symbol = (char *) m->currency_symbol; lconv.currency_symbol = (char *) m->currency_symbol;
lconv.mon_decimal_point = (char *) m->mon_decimal_point; lconv.mon_decimal_point = (char *) m->mon_decimal_point;
@ -1014,8 +1041,6 @@ _DEFUN(_localeconv_r, (data),
lconv.int_n_sign_posn = m->n_sign_posn[0]; lconv.int_n_sign_posn = m->n_sign_posn[0];
lconv.int_p_sign_posn = m->p_sign_posn[0]; lconv.int_p_sign_posn = m->p_sign_posn[0];
#endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */ #endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
__mlocale_changed = 0;
}
#endif /* __HAVE_LOCALE_INFO__ */ #endif /* __HAVE_LOCALE_INFO__ */
return (struct lconv *) &lconv; return (struct lconv *) &lconv;
} }

View File

@ -32,11 +32,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "lctype.h" #include "setlocale.h"
#include "timelocal.h"
#include "lnumeric.h"
#include "lmonetary.h"
#include "lmessages.h"
#ifndef __CYGWIN__ #ifndef __CYGWIN__
#define TRANSITION_PERIOD_HACK #define TRANSITION_PERIOD_HACK

View File

@ -29,8 +29,89 @@
#ifndef _SETLOCALE_H_ #ifndef _SETLOCALE_H_
#define _SETLOCALE_H_ #define _SETLOCALE_H_
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include "lctype.h"
#include "lmessages.h"
#include "lnumeric.h"
#include "timelocal.h"
#include "lmonetary.h"
#define ENCODING_LEN 31 #define ENCODING_LEN 31
#define CATEGORY_LEN 11 #define CATEGORY_LEN 11
#define _LC_LAST 7
#ifdef __CYGWIN__
struct lc_collate_T;
#endif
struct _thr_locale_t
{
char categories[_LC_LAST][ENCODING_LEN + 1];
int (*__wctomb) (struct _reent *, char *, wchar_t,
const char *, mbstate_t *);
int (*__mbtowc) (struct _reent *, wchar_t *, const char *,
size_t, const char *, mbstate_t *);
char *ctype_ptr; /* Unused in __global_locale */
int cjk_lang;
#ifndef __HAVE_LOCALE_INFO__
char mb_cur_max[2];
char ctype_codeset[ENCODING_LEN + 1];
char message_codeset[ENCODING_LEN + 1];
#else
struct lc_ctype_T *ctype;
char *ctype_buf;
struct lc_monetary_T *monetary;
char *monetary_buf;
struct lc_numeric_T *numeric;
char *numeric_buf;
struct lc_time_T *time;
char *time_buf;
struct lc_messages_T *messages;
char *messages_buf;
#ifdef __CYGWIN__
struct lc_collate_T *collate;
#endif
/* Append more categories here. */
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
extern struct _thr_locale_t __global_locale;
/* In POSIX terms the global locale is the process-wide locale. Use this
function to always refer to the global locale. */
_ELIDABLE_INLINE struct _thr_locale_t *
__get_global_locale ()
{
return &__global_locale;
}
/* Per REENT locale. This is newlib-internal. */
_ELIDABLE_INLINE struct _thr_locale_t *
__get_locale_r (struct _reent *r)
{
return r->_locale;
}
/* In POSIX terms the current locale is the locale used by all functions
using locale info without providing a locale as parameter (*_l functions).
The current locale is either the locale of the current thread, if the
thread called uselocale, or the global locale if not. */
_ELIDABLE_INLINE struct _thr_locale_t *
__get_current_locale ()
{
return _REENT->_locale ?: &__global_locale;
}
#ifdef __cplusplus
}
#endif
extern char *_PathLocale; extern char *_PathLocale;

View File

@ -30,11 +30,7 @@
#include <stddef.h> #include <stddef.h>
#include "ldpart.h" #include "ldpart.h"
#include "timelocal.h" #include "setlocale.h"
static struct lc_time_T _time_locale;
static int _time_using_locale;
static char *time_locale_buf;
#define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *)) #define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
@ -149,33 +145,42 @@ static const struct lc_time_T _C_time_locale = {
#endif #endif
}; };
struct lc_time_T * #ifndef __CYGWIN__
__get_current_time_locale(void) { static struct lc_time_T _time_locale;
return (_time_using_locale static int _time_using_locale;
? &_time_locale static char *time_locale_buf;
: (struct lc_time_T *)&_C_time_locale); #endif
}
int int
__time_load_locale(const char *name, void *f_wctomb, const char *charset) { __time_load_locale (struct _thr_locale_t *locale, const char *name,
void *f_wctomb, const char *charset)
{
int ret; int ret;
struct lc_time_T ti;
char *bufp = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
extern int __set_lc_time_from_win (const char *, extern int __set_lc_time_from_win (const char *, const struct lc_time_T *,
const struct lc_time_T *, struct lc_time_T *, char **, void *,
struct lc_time_T *, const char *);
char **, void *, const char *); ret = __set_lc_time_from_win (name, &_C_time_locale, &ti, &bufp,
int old_time_using_locale = _time_using_locale; f_wctomb, charset);
_time_using_locale = 0;
ret = __set_lc_time_from_win (name, &_C_time_locale, &_time_locale,
&time_locale_buf, f_wctomb, charset);
/* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */
if (ret < 0) if (ret >= 0)
_time_using_locale = old_time_using_locale;
else
{ {
_time_using_locale = ret; struct lc_time_T *tip = NULL;
if (ret > 0)
{
tip = (struct lc_time_T *) calloc (1, sizeof *tip);
if (!tip)
return -1;
memcpy (tip, &ti, sizeof *tip);
}
locale->time = ret == 0 ? NULL : tip;
if (locale->time_buf)
free (locale->time_buf);
locale->time_buf = bufp;
ret = 0; ret = 0;
} }
#else #else
@ -186,3 +191,10 @@ __time_load_locale(const char *name, void *f_wctomb, const char *charset) {
#endif #endif
return (ret); return (ret);
} }
struct lc_time_T *
__get_current_time_locale (void)
{
struct _thr_locale_t *cur_locale = __get_current_locale ();
return cur_locale->time ?: (struct lc_time_T *) &_C_time_locale;
}

View File

@ -77,8 +77,9 @@ struct lc_time_T {
#endif #endif
}; };
struct lc_time_T *__get_current_time_locale(void); struct lc_time_T *__get_current_time_locale (void);
int __time_load_locale(const char *, void *, const char *); int __time_load_locale (struct _thr_locale_t *, const char *, void *,
const char *);
__END_DECLS __END_DECLS

View File

@ -68,6 +68,7 @@ __isinfd = isinf NOSIGFE
__isinff = isinff NOSIGFE __isinff = isinff NOSIGFE
__isnand = isnan NOSIGFE __isnand = isnan NOSIGFE
__isnanf = isnanf NOSIGFE __isnanf = isnanf NOSIGFE
__locale_ctype_ptr NOSIGFE
__locale_mb_cur_max NOSIGFE __locale_mb_cur_max NOSIGFE
__main NOSIGFE __main NOSIGFE
__mempcpy = mempcpy NOSIGFE __mempcpy = mempcpy NOSIGFE

View File

@ -1,6 +1,7 @@
#include "winsup.h" #include "winsup.h"
extern "C" { extern "C" {
#include <ctype.h> #include <ctype.h>
#include "../locale/setlocale.h"
#include <stdlib.h> #include <stdlib.h>
#include <wctype.h> #include <wctype.h>
@ -18,9 +19,10 @@ extern const char __ctype_cp[22][128 + 256]; /* Newlib */
extern const char __ctype_iso[15][128 + 256]; /* Newlib */ extern const char __ctype_iso[15][128 + 256]; /* Newlib */
void void
__set_ctype (const char *charset) __set_ctype (struct _reent *reent, const char *charset)
{ {
int idx; int idx;
char *ctype_ptr = NULL;
switch (*charset) switch (*charset)
{ {
@ -36,8 +38,8 @@ __set_ctype (const char *charset)
memcpy (_ctype_b, __ctype_iso[idx], 128); memcpy (_ctype_b, __ctype_iso[idx], 128);
memcpy (_ctype_b + 256, __ctype_iso[idx] + 256, 128); memcpy (_ctype_b + 256, __ctype_iso[idx] + 256, 128);
} }
__ctype_ptr__ = (char *) (__ctype_iso[idx] + 127); ctype_ptr = (char *) __ctype_iso[idx];
return; break;
case 'C': case 'C':
idx = __cp_index (charset + 2); idx = __cp_index (charset + 2);
if (idx < 0) if (idx < 0)
@ -47,17 +49,24 @@ __set_ctype (const char *charset)
memcpy (_ctype_b, __ctype_cp[idx], 128); memcpy (_ctype_b, __ctype_cp[idx], 128);
memcpy (_ctype_b + 256, __ctype_cp[idx] + 256, 128); memcpy (_ctype_b + 256, __ctype_cp[idx] + 256, 128);
} }
__ctype_ptr__ = (char *) (__ctype_cp[idx] + 127); ctype_ptr = (char *) __ctype_cp[idx];
return; break;
default: default:
break; break;
} }
if (!ctype_ptr)
{
if (CYGWIN_VERSION_CHECK_FOR_OLD_CTYPE) if (CYGWIN_VERSION_CHECK_FOR_OLD_CTYPE)
{ {
memset (_ctype_b, 0, 128); memset (_ctype_b, 0, 128);
memset (_ctype_b + 256, 0, 128); memset (_ctype_b + 256, 0, 128);
} }
__ctype_ptr__ = (char *) _ctype_b + 127; ctype_ptr = (char *) _ctype_b;
}
if (reent)
__get_locale_r (reent)->ctype_ptr = ctype_ptr + 127;
else
__ctype_ptr__ = ctype_ptr + 127;
} }
} /* extern "C" */ } /* extern "C" */

View File

@ -17,11 +17,7 @@ details. */
#include "cygheap.h" #include "cygheap.h"
#include "tls_pbuf.h" #include "tls_pbuf.h"
/* Internal headers from newlib */ /* Internal headers from newlib */
#include "../locale/timelocal.h" #include "../locale/setlocale.h"
#include "../locale/lctype.h"
#include "../locale/lnumeric.h"
#include "../locale/lmonetary.h"
#include "../locale/lmessages.h"
#include "lc_msg.h" #include "lc_msg.h"
#include "lc_era.h" #include "lc_era.h"
@ -689,8 +685,6 @@ __set_lc_time_from_win (const char *name,
if (tmp != new_lc_time_buf) if (tmp != new_lc_time_buf)
rebase_locale_buf (_time_locale, _time_locale + 1, tmp, rebase_locale_buf (_time_locale, _time_locale + 1, tmp,
new_lc_time_buf, lc_time_ptr); new_lc_time_buf, lc_time_ptr);
if (*lc_time_buf)
free (*lc_time_buf);
*lc_time_buf = tmp; *lc_time_buf = tmp;
return 1; return 1;
} }
@ -764,8 +758,6 @@ __set_lc_ctype_from_win (const char *name,
if (tmp != new_lc_ctype_buf) if (tmp != new_lc_ctype_buf)
rebase_locale_buf (_ctype_locale, _ctype_locale + 1, tmp, rebase_locale_buf (_ctype_locale, _ctype_locale + 1, tmp,
new_lc_ctype_buf, lc_ctype_ptr); new_lc_ctype_buf, lc_ctype_ptr);
if (*lc_ctype_buf)
free (*lc_ctype_buf);
*lc_ctype_buf = tmp; *lc_ctype_buf = tmp;
return 1; return 1;
} }
@ -841,8 +833,6 @@ __set_lc_numeric_from_win (const char *name,
if (tmp != new_lc_numeric_buf) if (tmp != new_lc_numeric_buf)
rebase_locale_buf (_numeric_locale, _numeric_locale + 1, tmp, rebase_locale_buf (_numeric_locale, _numeric_locale + 1, tmp,
new_lc_numeric_buf, lc_numeric_ptr); new_lc_numeric_buf, lc_numeric_ptr);
if (*lc_numeric_buf)
free (*lc_numeric_buf);
*lc_numeric_buf = tmp; *lc_numeric_buf = tmp;
return 1; return 1;
} }
@ -981,8 +971,6 @@ __set_lc_monetary_from_win (const char *name,
if (tmp != new_lc_monetary_buf) if (tmp != new_lc_monetary_buf)
rebase_locale_buf (_monetary_locale, _monetary_locale + 1, tmp, rebase_locale_buf (_monetary_locale, _monetary_locale + 1, tmp,
new_lc_monetary_buf, lc_monetary_ptr); new_lc_monetary_buf, lc_monetary_ptr);
if (*lc_monetary_buf)
free (*lc_monetary_buf);
*lc_monetary_buf = tmp; *lc_monetary_buf = tmp;
return 1; return 1;
} }
@ -1083,36 +1071,59 @@ __set_lc_messages_from_win (const char *name,
_messages_locale->wnostr = (const wchar_t *) wc; _messages_locale->wnostr = (const wchar_t *) wc;
wcpcpy (wc, msg->nostr); wcpcpy (wc, msg->nostr);
} }
/* Aftermath. */
if (*lc_messages_buf)
free (*lc_messages_buf);
*lc_messages_buf = new_lc_messages_buf; *lc_messages_buf = new_lc_messages_buf;
return 1; return 1;
} }
LCID collate_lcid = 0; struct lc_collate_T
static mbtowc_p collate_mbtowc = __ascii_mbtowc; {
char collate_charset[ENCODING_LEN + 1] = "ASCII"; LCID lcid;
mbtowc_p mbtowc;
char codeset[ENCODING_LEN + 1];
};
/* Called from newlib's setlocale() if category is LC_COLLATE. Stores /* Called from newlib's setlocale() if category is LC_COLLATE. Stores
LC_COLLATE locale information. This is subsequently accessed by the LC_COLLATE locale information. This is subsequently accessed by the
below functions strcoll, strxfrm, wcscoll, wcsxfrm. */ below functions strcoll, strxfrm, wcscoll, wcsxfrm. */
extern "C" int extern "C" int
__collate_load_locale (const char *name, mbtowc_p f_mbtowc, const char *charset) __collate_load_locale (struct _thr_locale_t *locale, const char *name,
mbtowc_p f_mbtowc, const char *charset)
{ {
LCID lcid = __get_lcid_from_locale (name); LCID lcid = __get_lcid_from_locale (name);
if (lcid == (LCID) -1) if (lcid == (LCID) -1)
return -1; return -1;
collate_lcid = lcid; struct lc_collate_T *cop;
collate_mbtowc = f_mbtowc; if (lcid)
stpcpy (collate_charset, charset); {
cop = (struct lc_collate_T *) calloc (1, sizeof *cop);
if (!cop)
return -1;
cop->lcid = lcid;
cop->mbtowc = f_mbtowc;
stpcpy (cop->codeset, charset);
}
return 0; return 0;
} }
extern "C" LCID
__get_current_collate_lcid ()
{
struct _thr_locale_t *cur_locale = __get_current_locale ();
return cur_locale->collate ? cur_locale->collate->lcid : 0;
}
extern "C" const char * extern "C" const char *
__get_current_collate_codeset (void) __get_current_collate_codeset (void)
{ {
return collate_charset; struct _thr_locale_t *cur_locale = __get_current_locale ();
return cur_locale->collate ? cur_locale->collate->codeset : "ASCII";
}
static mbtowc_p
__get_current_collate_mbtowc ()
{
struct _thr_locale_t *cur_locale = __get_current_locale ();
return cur_locale->collate ? cur_locale->collate->mbtowc : __ascii_mbtowc;
} }
/* We use the Windows functions for locale-specific string comparison and /* We use the Windows functions for locale-specific string comparison and
@ -1122,6 +1133,7 @@ extern "C" int
wcscoll (const wchar_t *__restrict ws1, const wchar_t *__restrict ws2) wcscoll (const wchar_t *__restrict ws1, const wchar_t *__restrict ws2)
{ {
int ret; int ret;
LCID collate_lcid = __get_current_collate_lcid ();
if (!collate_lcid) if (!collate_lcid)
return wcscmp (ws1, ws2); return wcscmp (ws1, ws2);
@ -1138,11 +1150,14 @@ strcoll (const char *__restrict s1, const char *__restrict s2)
wchar_t *ws1, *ws2; wchar_t *ws1, *ws2;
tmp_pathbuf tp; tmp_pathbuf tp;
int ret; int ret;
LCID collate_lcid = __get_current_collate_lcid ();
if (!collate_lcid) if (!collate_lcid)
return strcmp (s1, s2); return strcmp (s1, s2);
/* The ANSI version of CompareString uses the default charset of the lcid, /* The ANSI version of CompareString uses the default charset of the lcid,
so we must use the Unicode version. */ so we must use the Unicode version. */
mbtowc_p collate_mbtowc = __get_current_collate_mbtowc ();
const char *collate_charset = __get_current_collate_codeset ();
n1 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s1, 0) + 1; n1 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s1, 0) + 1;
ws1 = (n1 > NT_MAX_PATH ? (wchar_t *) malloc (n1 * sizeof (wchar_t)) ws1 = (n1 > NT_MAX_PATH ? (wchar_t *) malloc (n1 * sizeof (wchar_t))
: tp.w_get ()); : tp.w_get ());
@ -1176,6 +1191,7 @@ extern "C" size_t
wcsxfrm (wchar_t *__restrict ws1, const wchar_t *__restrict ws2, size_t wsn) wcsxfrm (wchar_t *__restrict ws1, const wchar_t *__restrict ws2, size_t wsn)
{ {
size_t ret; size_t ret;
LCID collate_lcid = __get_current_collate_lcid ();
if (!collate_lcid) if (!collate_lcid)
return wcslcpy (ws1, ws2, wsn); return wcslcpy (ws1, ws2, wsn);
@ -1211,11 +1227,14 @@ strxfrm (char *__restrict s1, const char *__restrict s2, size_t sn)
size_t n2; size_t n2;
wchar_t *ws2; wchar_t *ws2;
tmp_pathbuf tp; tmp_pathbuf tp;
LCID collate_lcid = __get_current_collate_lcid ();
if (!collate_lcid) if (!collate_lcid)
return strlcpy (s1, s2, sn); return strlcpy (s1, s2, sn);
/* The ANSI version of LCMapString uses the default charset of the lcid, /* The ANSI version of LCMapString uses the default charset of the lcid,
so we must use the Unicode version. */ so we must use the Unicode version. */
mbtowc_p collate_mbtowc = __get_current_collate_mbtowc ();
const char *collate_charset = __get_current_collate_codeset ();
n2 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s2, 0) + 1; n2 = lc_mbstowcs (collate_mbtowc, collate_charset, NULL, s2, 0) + 1;
ws2 = (n2 > NT_MAX_PATH ? (wchar_t *) malloc (n2 * sizeof (wchar_t)) ws2 = (n2 > NT_MAX_PATH ? (wchar_t *) malloc (n2 * sizeof (wchar_t))
: tp.w_get ()); : tp.w_get ());

View File

@ -63,9 +63,8 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/regcomp.c,v 1.36 2007/06/11 03:05:54 delp
#include "cname.h" #include "cname.h"
#ifdef __CYGWIN__ #ifdef __CYGWIN__
/* These are defined in nlsfuncs.cc. */ /* Defined in nlsfuncs.cc. */
extern LCID collate_lcid; extern LCID __get_current_collate_lcid ();
extern char collate_charset[];
#endif #endif
/* /*
@ -832,7 +831,7 @@ p_b_term(struct parse *p, cset *cs)
CHadd(p, cs, start); CHadd(p, cs, start);
else { else {
#ifdef __CYGWIN__ #ifdef __CYGWIN__
if (!collate_lcid) { if (!__get_current_collate_lcid ()) {
#else #else
if (__collate_load_error) { if (__collate_load_error) {
#endif #endif