summaryrefslogtreecommitdiffstats
path: root/newlib/libc/locale/locale.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/locale/locale.c')
-rw-r--r--newlib/libc/locale/locale.c247
1 files changed, 136 insertions, 111 deletions
diff --git a/newlib/libc/locale/locale.c b/newlib/libc/locale/locale.c
index 33b535941..83d83a5ed 100644
--- a/newlib/libc/locale/locale.c
+++ b/newlib/libc/locale/locale.c
@@ -172,30 +172,22 @@ No supporting OS subroutines are required.
#include <newlib.h>
#include <errno.h>
-#include <locale.h>
+#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <reent.h>
#include <stdlib.h>
#include <wchar.h>
-#include "lmessages.h"
-#include "lmonetary.h"
-#include "lnumeric.h"
-#include "lctype.h"
-#include "timelocal.h"
+#include "setlocale.h"
#include "../stdlib/local.h"
-#define _LC_LAST 7
-#define ENCODING_LEN 31
-
-#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */
+#ifdef __CYGWIN__ /* Has to be kept available as exported symbol for
+ backward compatibility. Set it in setlocale, but
+ otherwise ignore it. Applications compiled after
+ 2010 don't use it anymore. */
int __EXPORT __mb_cur_max = 6;
-#else
-int __EXPORT __mb_cur_max = 1;
#endif
-int __nlocale_changed = 0;
-int __mlocale_changed = 0;
char *_PathLocale = NULL;
static
@@ -234,44 +226,56 @@ static char *categories[_LC_LAST] = {
*/
char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE;
-/*
- * Current locales for each category
- */
-static char current_categories[_LC_LAST][ENCODING_LEN + 1] = {
- "C",
- "C",
-#ifdef __CYGWIN__ /* Cygwin starts with LC_CTYPE set to "C.UTF-8". */
- "C.UTF-8",
+struct _thr_locale_t __global_locale =
+{
+ { "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
+#ifdef __CYGWIN__
+ __utf8_wctomb,
+ __utf8_mbtowc,
+#else
+ __ascii_wctomb,
+ __ascii_mbtowc,
+#endif
+ NULL,
+ 0,
+#ifndef __HAVE_LOCALE_INFO__
+ "\1",
+ "ASCII",
+ "ASCII",
#else
- "C",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#ifdef __CYGWIN__
+ NULL,
+#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 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 *loadlocale(struct _reent *, int);
static const char *__get_locale_env(struct _reent *, int);
#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 *
_DEFUN(_setlocale_r, (p, category, locale),
struct _reent *p _AND
@@ -297,13 +301,13 @@ _DEFUN(_setlocale_r, (p, category, locale),
}
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.
*/
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
@@ -395,7 +399,7 @@ _DEFUN(_setlocale_r, (p, category, locale),
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)
{
saverr = p->_errno;
@@ -422,18 +426,18 @@ currentlocale()
{
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)
- 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) {
- (void)strcat(current_locale_string, "/");
- (void)strcat(current_locale_string,
- current_categories[i]);
+ (void)strcat(global_locale_string, "/");
+ (void)strcat(global_locale_string,
+ __global_locale.categories[i]);
}
break;
}
- return (current_locale_string);
+ return (global_locale_string);
}
#endif /* _MB_CAPABLE */
@@ -441,10 +445,11 @@ currentlocale()
#ifdef __CYGWIN__
extern void __set_charset_from_locale (const char *locale, char *charset);
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__ */
-extern void __set_ctype (const char *charset);
+extern void __set_ctype (struct _reent *, const char *charset);
static char *
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
one in POSIX-style, or one in the old newlib style to maintain
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. */
char *locale = NULL;
char charset[ENCODING_LEN + 1];
@@ -468,8 +473,8 @@ loadlocale(struct _reent *p, int category)
int cjknarrow = 0;
/* Avoid doing everything twice if nothing has changed. */
- if (!strcmp (new_categories[category], current_categories[category]))
- return current_categories[category];
+ if (!strcmp (new_categories[category], __global_locale.categories[category]))
+ return __global_locale.categories[category];
#ifdef __CYGWIN__
/* This additional code handles the case that the incoming locale string
@@ -852,49 +857,61 @@ restart:
switch (category)
{
case LC_CTYPE:
- strcpy (lc_ctype_charset, charset);
- __mb_cur_max = mbc_max;
+#ifndef __HAVE_LOCALE_INFO__
+ 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;
__mbtowc = l_mbtowc;
- __set_ctype (charset);
+ __set_ctype (NULL, charset);
/* Determine the width for the "CJK Ambiguous Width" category of
characters. This is used in wcwidth(). Assume single width for
single-byte charsets, and double width for multi-byte charsets
other than UTF-8. For UTF-8, use double width for the East Asian
languages ("ja", "ko", "zh"), and single width for everything else.
Single width can also be forced with the "@cjknarrow" modifier. */
- lc_ctype_cjk_lang = !cjknarrow
+ __global_locale.cjk_lang = !cjknarrow
&& mbc_max > 1
&& (charset[0] != 'U'
|| strncmp (locale, "ja", 2) == 0
|| strncmp (locale, "ko", 2) == 0
|| strncmp (locale, "zh", 2) == 0);
#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__ */
break;
case LC_MESSAGES:
- strcpy (lc_message_charset, charset);
#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)
+#else
+ strcpy (__global_locale.message_codeset, charset);
#endif /* __HAVE_LOCALE_INFO__ */
break;
#ifdef __HAVE_LOCALE_INFO__
#ifdef __CYGWIN__
/* Right now only Cygwin supports a __collate_load_locale function at all. */
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;
#endif
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;
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;
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;
#endif /* __HAVE_LOCALE_INFO__ */
default:
@@ -904,7 +921,7 @@ restart:
if (ret)
FAIL;
#endif /* __HAVE_LOCALE_INFO__ */
- return strcpy(current_categories[category], new_categories[category]);
+ return strcpy(__global_locale.categories[category], new_categories[category]);
}
static const char *
@@ -934,88 +951,96 @@ __get_locale_env(struct _reent *p, int category)
char *
_DEFUN_VOID(__locale_charset)
{
-#if 0//def __HAVE_LOCALE_INFO__
- return __get_current_ctype_locale ()->codeset;
+#ifdef __HAVE_LOCALE_INFO__
+ return (char *) __get_current_ctype_locale ()->codeset;
#else
- return lc_ctype_charset;
+ return __global_locale.ctype_codeset;
#endif
}
int
_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];
#else
- return __mb_cur_max;
+ return __global_locale.mb_cur_max[0];
#endif
}
-
char *
_DEFUN_VOID(__locale_msgcharset)
{
#ifdef __HAVE_LOCALE_INFO__
return (char *) __get_current_messages_locale ()->codeset;
#else
- return lc_message_charset;
+ return (char *) __global_locale.message_codeset;
#endif
}
int
_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 *
_DEFUN(_localeconv_r, (data),
struct _reent *data)
{
#ifdef __HAVE_LOCALE_INFO__
- if (__nlocale_changed)
- {
- struct lc_numeric_T *n = __get_current_numeric_locale ();
- lconv.decimal_point = (char *) n->decimal_point;
- lconv.thousands_sep = (char *) n->thousands_sep;
- 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.currency_symbol = (char *) m->currency_symbol;
- lconv.mon_decimal_point = (char *) m->mon_decimal_point;
- lconv.mon_thousands_sep = (char *) m->mon_thousands_sep;
- lconv.mon_grouping = (char *) m->mon_grouping;
- lconv.positive_sign = (char *) m->positive_sign;
- lconv.negative_sign = (char *) m->negative_sign;
- lconv.int_frac_digits = m->int_frac_digits[0];
- lconv.frac_digits = m->frac_digits[0];
- lconv.p_cs_precedes = m->p_cs_precedes[0];
- lconv.p_sep_by_space = m->p_sep_by_space[0];
- lconv.n_cs_precedes = m->n_cs_precedes[0];
- lconv.n_sep_by_space = m->n_sep_by_space[0];
- lconv.p_sign_posn = m->p_sign_posn[0];
- lconv.n_sign_posn = m->n_sign_posn[0];
+ 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.thousands_sep = (char *) n->thousands_sep;
+ lconv.grouping = (char *) n->grouping;
+ lconv.int_curr_symbol = (char *) m->int_curr_symbol;
+ lconv.currency_symbol = (char *) m->currency_symbol;
+ lconv.mon_decimal_point = (char *) m->mon_decimal_point;
+ lconv.mon_thousands_sep = (char *) m->mon_thousands_sep;
+ lconv.mon_grouping = (char *) m->mon_grouping;
+ lconv.positive_sign = (char *) m->positive_sign;
+ lconv.negative_sign = (char *) m->negative_sign;
+ lconv.int_frac_digits = m->int_frac_digits[0];
+ lconv.frac_digits = m->frac_digits[0];
+ lconv.p_cs_precedes = m->p_cs_precedes[0];
+ lconv.p_sep_by_space = m->p_sep_by_space[0];
+ lconv.n_cs_precedes = m->n_cs_precedes[0];
+ lconv.n_sep_by_space = m->n_sep_by_space[0];
+ lconv.p_sign_posn = m->p_sign_posn[0];
+ lconv.n_sign_posn = m->n_sign_posn[0];
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
- lconv.int_p_cs_precedes = m->int_p_cs_precedes[0];
- lconv.int_p_sep_by_space = m->int_p_sep_by_space[0];
- lconv.int_n_cs_precedes = m->int_n_cs_precedes[0];
- lconv.int_n_sep_by_space = m->int_n_sep_by_space[0];
- lconv.int_n_sign_posn = m->int_n_sign_posn[0];
- lconv.int_p_sign_posn = m->int_p_sign_posn[0];
+ lconv.int_p_cs_precedes = m->int_p_cs_precedes[0];
+ lconv.int_p_sep_by_space = m->int_p_sep_by_space[0];
+ lconv.int_n_cs_precedes = m->int_n_cs_precedes[0];
+ lconv.int_n_sep_by_space = m->int_n_sep_by_space[0];
+ lconv.int_n_sign_posn = m->int_n_sign_posn[0];
+ lconv.int_p_sign_posn = m->int_p_sign_posn[0];
#else /* !__HAVE_LOCALE_INFO_EXTENDED__ */
- lconv.int_p_cs_precedes = m->p_cs_precedes[0];
- lconv.int_p_sep_by_space = m->p_sep_by_space[0];
- lconv.int_n_cs_precedes = m->n_cs_precedes[0];
- lconv.int_n_sep_by_space = m->n_sep_by_space[0];
- lconv.int_n_sign_posn = m->n_sign_posn[0];
- lconv.int_p_sign_posn = m->p_sign_posn[0];
+ lconv.int_p_cs_precedes = m->p_cs_precedes[0];
+ lconv.int_p_sep_by_space = m->p_sep_by_space[0];
+ lconv.int_n_cs_precedes = m->n_cs_precedes[0];
+ lconv.int_n_sep_by_space = m->n_sep_by_space[0];
+ lconv.int_n_sign_posn = m->n_sign_posn[0];
+ lconv.int_p_sign_posn = m->p_sign_posn[0];
#endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
- __mlocale_changed = 0;
- }
#endif /* __HAVE_LOCALE_INFO__ */
return (struct lconv *) &lconv;
}