4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-16 19:40:07 +08:00
Corinna Vinschen 88208d3735 POSIX-1.2008 per-thread locales, groundwork part 2
Move all locale category structure definitions into setlocale.h and remove
other headers in locale subdir.  Create inline accessor functions for
current category struct pointers and use throughout.  Use pointers to
"C" locale category structs by default in __global_locale.

Signed-off by: Corinna Vinschen <corinna@vinschen.de>
2016-08-15 10:56:56 +02:00

431 lines
13 KiB
C

/*-
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <locale.h>
#include <langinfo.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "setlocale.h"
#ifndef __CYGWIN__
#define TRANSITION_PERIOD_HACK
#endif
#undef offsetoff
#define _O(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
#define _NLITEM(cat,memb) { { cat:__get_current_##cat##_locale }, \
_O (struct lc_##cat##_T, memb) }
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
static struct _nl_item_t
{
union {
const struct lc_ctype_T * (*ctype)(void);
const struct lc_time_T * (*time)(void);
const struct lc_numeric_T * (*numeric)(void);
const struct lc_monetary_T * (*monetary)(void);
const struct lc_messages_T * (*messages)(void);
void * (*base)(void);
};
_off_t offset;
} nl_ext[] =
{
/* First element has an nl_item value of _NL_LOCALE_EXTENDED_FIRST_ENTRY */
_NLITEM (ctype, outdigits[0]),
_NLITEM (ctype, outdigits[1]),
_NLITEM (ctype, outdigits[2]),
_NLITEM (ctype, outdigits[3]),
_NLITEM (ctype, outdigits[4]),
_NLITEM (ctype, outdigits[5]),
_NLITEM (ctype, outdigits[6]),
_NLITEM (ctype, outdigits[7]),
_NLITEM (ctype, outdigits[8]),
_NLITEM (ctype, outdigits[9]),
_NLITEM (ctype, woutdigits[0]),
_NLITEM (ctype, woutdigits[1]),
_NLITEM (ctype, woutdigits[2]),
_NLITEM (ctype, woutdigits[3]),
_NLITEM (ctype, woutdigits[4]),
_NLITEM (ctype, woutdigits[5]),
_NLITEM (ctype, woutdigits[6]),
_NLITEM (ctype, woutdigits[7]),
_NLITEM (ctype, woutdigits[8]),
_NLITEM (ctype, woutdigits[9]),
_NLITEM (time, codeset),
_NLITEM (time, wmon[1]),
_NLITEM (time, wmon[2]),
_NLITEM (time, wmon[3]),
_NLITEM (time, wmon[4]),
_NLITEM (time, wmon[5]),
_NLITEM (time, wmon[6]),
_NLITEM (time, wmon[7]),
_NLITEM (time, wmon[8]),
_NLITEM (time, wmon[9]),
_NLITEM (time, wmon[10]),
_NLITEM (time, wmon[11]),
_NLITEM (time, wmon[12]),
_NLITEM (time, wmonth[1]),
_NLITEM (time, wmonth[2]),
_NLITEM (time, wmonth[3]),
_NLITEM (time, wmonth[4]),
_NLITEM (time, wmonth[5]),
_NLITEM (time, wmonth[6]),
_NLITEM (time, wmonth[7]),
_NLITEM (time, wmonth[8]),
_NLITEM (time, wmonth[9]),
_NLITEM (time, wmonth[10]),
_NLITEM (time, wmonth[11]),
_NLITEM (time, wmonth[12]),
_NLITEM (time, wwday[1]),
_NLITEM (time, wwday[2]),
_NLITEM (time, wwday[3]),
_NLITEM (time, wwday[4]),
_NLITEM (time, wwday[5]),
_NLITEM (time, wwday[6]),
_NLITEM (time, wwday[7]),
_NLITEM (time, wweekday[1]),
_NLITEM (time, wweekday[2]),
_NLITEM (time, wweekday[3]),
_NLITEM (time, wweekday[4]),
_NLITEM (time, wweekday[5]),
_NLITEM (time, wweekday[6]),
_NLITEM (time, wweekday[7]),
_NLITEM (time, wX_fmt),
_NLITEM (time, wx_fmt),
_NLITEM (time, wc_fmt),
_NLITEM (time, wam_pm[0]),
_NLITEM (time, wam_pm[1]),
_NLITEM (time, wdate_fmt),
_NLITEM (time, wampm_fmt),
_NLITEM (time, wera),
_NLITEM (time, wera_d_fmt),
_NLITEM (time, wera_d_t_fmt),
_NLITEM (time, wera_t_fmt),
_NLITEM (time, walt_digits),
_NLITEM (numeric, codeset),
_NLITEM (numeric, grouping),
_NLITEM (numeric, wdecimal_point),
_NLITEM (numeric, wthousands_sep),
_NLITEM (monetary, int_curr_symbol),
_NLITEM (monetary, currency_symbol),
_NLITEM (monetary, mon_decimal_point),
_NLITEM (monetary, mon_thousands_sep),
_NLITEM (monetary, mon_grouping),
_NLITEM (monetary, positive_sign),
_NLITEM (monetary, negative_sign),
_NLITEM (monetary, int_frac_digits),
_NLITEM (monetary, frac_digits),
_NLITEM (monetary, p_cs_precedes),
_NLITEM (monetary, p_sep_by_space),
_NLITEM (monetary, n_cs_precedes),
_NLITEM (monetary, n_sep_by_space),
_NLITEM (monetary, p_sign_posn),
_NLITEM (monetary, n_sign_posn),
_NLITEM (monetary, int_p_cs_precedes),
_NLITEM (monetary, int_p_sep_by_space),
_NLITEM (monetary, int_n_cs_precedes),
_NLITEM (monetary, int_n_sep_by_space),
_NLITEM (monetary, int_p_sign_posn),
_NLITEM (monetary, int_n_sign_posn),
_NLITEM (monetary, codeset),
_NLITEM (monetary, wint_curr_symbol),
_NLITEM (monetary, wcurrency_symbol),
_NLITEM (monetary, wmon_decimal_point),
_NLITEM (monetary, wmon_thousands_sep),
_NLITEM (monetary, wpositive_sign),
_NLITEM (monetary, wnegative_sign),
_NLITEM (messages, codeset),
_NLITEM (messages, wyesexpr),
_NLITEM (messages, wnoexpr),
_NLITEM (messages, wyesstr),
_NLITEM (messages, wnostr),
};
#endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
#define _REL(BASE) ((int)item-BASE)
extern char *__locale_charset ();
char *
_DEFUN(nl_langinfo, (item),
nl_item item) {
char *ret, *cs;
#ifndef __CYGWIN__
char *s;
#endif
static char *csym = NULL;
#ifdef TRANSITION_PERIOD_HACK
static char *cset = NULL;
#endif /* TRANSITION_PERIOD_HACK */
char *nptr;
switch (item) {
#ifdef __HAVE_LOCALE_INFO__
case _NL_MESSAGES_CODESET:
ret = (char *) __get_current_messages_locale ()->codeset;
goto do_codeset;
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
case _NL_TIME_CODESET:
ret = (char *) __get_current_time_locale ()->codeset;
goto do_codeset;
case _NL_NUMERIC_CODESET:
ret = (char *) __get_current_numeric_locale ()->codeset;
goto do_codeset;
case _NL_MONETARY_CODESET:
ret = (char *) __get_current_monetary_locale ()->codeset;
goto do_codeset;
#ifdef __CYGWIN__
case _NL_COLLATE_CODESET:
{
ret = (char *) __get_current_collate_locale ()->codeset;
goto do_codeset;
}
#endif /* __CYGWIN__ */
#endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
#endif /* __HAVE_LOCALE_INFO__ */
case CODESET:
#ifdef __CYGWIN__
ret = __locale_charset ();
#endif
do_codeset:
#ifdef __CYGWIN__
/* Convert charset to Linux compatible codeset string. */
if (ret[0] == 'A'/*SCII*/)
ret = "ANSI_X3.4-1968";
else if (ret[0] == 'E')
{
if (strcmp (ret, "EUCJP") == 0)
ret = "EUC-JP";
else if (strcmp (ret, "EUCKR") == 0)
ret = "EUC-KR";
else if (strcmp (ret, "EUCCN") == 0)
ret = "GB2312";
}
else if (ret[0] == 'C'/*Pxxxx*/)
{
if (strcmp (ret + 2, "874") == 0)
ret = "TIS-620";
else if (strcmp (ret + 2, "20866") == 0)
ret = "KOI8-R";
else if (strcmp (ret + 2, "21866") == 0)
ret = "KOI8-U";
else if (strcmp (ret + 2, "101") == 0)
ret = "GEORGIAN-PS";
else if (strcmp (ret + 2, "102") == 0)
ret = "PT154";
}
else if (ret[0] == 'S'/*JIS*/)
{
/* Cygwin uses MSFT's implementation of SJIS, which differs
in some codepoints from the real thing, especially
0x5c: yen sign instead of backslash,
0x7e: overline instead of tilde.
We can't use the real SJIS since otherwise Win32
pathnames would become invalid. OTOH, if we return
"SJIS" here, then libiconv will do mb<->wc conversion
differently to our internal functions. Therefore we
return what we really implement, CP932. This is handled
fine by libiconv. */
ret = "CP932";
}
#else
ret = "";
if ((s = setlocale(LC_CTYPE, NULL)) != NULL) {
if ((cs = strchr(s, '.')) != NULL) {
ret = cs + 1;
#ifdef TRANSITION_PERIOD_HACK
if (strncmp(ret, "ISO_", 4) == 0) {
int slen = strlen(ret);
nptr = realloc(cset, slen);
if (!nptr && cset)
free (cset);
cset = nptr;
if (cset != NULL) {
strcpy(cset, "ISO");
strcat(cset, ret + 4);
ret = cset;
} else
ret = "";
} else if (strcmp(ret, "EUC") == 0) {
if (strncmp(s, "ja_JP", 5) == 0)
ret = "eucJP";
else if (strncmp(s, "ko_KR", 5) == 0)
ret = "eucKR";
else if (strncmp(s, "zh_CN", 5) == 0)
ret = "eucCN";
} else if (strcmp(ret, "ASCII") == 0)
ret = "US-ASCII";
#endif /* TRANSITION_PERIOD_HACK */
} else if (strcmp(s, "C") == 0 ||
strcmp(s, "POSIX") == 0
#ifdef TRANSITION_PERIOD_HACK
|| strstr(s, "ASCII") != NULL
#endif /* TRANSITION_PERIOD_HACK */
)
ret = "US-ASCII";
}
#endif /* __CYGWIN__ */
break;
case D_T_FMT:
ret = (char *) __get_current_time_locale()->c_fmt;
break;
case D_FMT:
ret = (char *) __get_current_time_locale()->x_fmt;
break;
case T_FMT:
ret = (char *) __get_current_time_locale()->X_fmt;
break;
case T_FMT_AMPM:
ret = (char *) __get_current_time_locale()->ampm_fmt;
break;
case AM_STR:
ret = (char *) __get_current_time_locale()->am_pm[0];
break;
case PM_STR:
ret = (char *) __get_current_time_locale()->am_pm[1];
break;
case DAY_1: case DAY_2: case DAY_3:
case DAY_4: case DAY_5: case DAY_6: case DAY_7:
ret = (char*) __get_current_time_locale()->weekday[_REL(DAY_1)];
break;
case ABDAY_1: case ABDAY_2: case ABDAY_3:
case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
ret = (char*) __get_current_time_locale()->wday[_REL(ABDAY_1)];
break;
case MON_1: case MON_2: case MON_3: case MON_4:
case MON_5: case MON_6: case MON_7: case MON_8:
case MON_9: case MON_10: case MON_11: case MON_12:
ret = (char*) __get_current_time_locale()->month[_REL(MON_1)];
break;
case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
ret = (char*) __get_current_time_locale()->mon[_REL(ABMON_1)];
break;
case ERA:
ret = (char*) __get_current_time_locale()->era;
break;
case ERA_D_FMT:
ret = (char*) __get_current_time_locale()->era_d_fmt;
break;
case ERA_D_T_FMT:
ret = (char*) __get_current_time_locale()->era_d_t_fmt;
break;
case ERA_T_FMT:
ret = (char*) __get_current_time_locale()->era_t_fmt;
break;
case ALT_DIGITS:
ret = (char*) __get_current_time_locale()->alt_digits;
break;
case _DATE_FMT: /* GNU extension */
ret = (char*) __get_current_time_locale()->date_fmt;
break;
case RADIXCHAR:
ret = (char*) __get_current_numeric_locale()->decimal_point;
break;
case THOUSEP:
ret = (char*) __get_current_numeric_locale()->thousands_sep;
break;
case YESEXPR:
ret = (char*) __get_current_messages_locale()->yesexpr;
break;
case NOEXPR:
ret = (char*) __get_current_messages_locale()->noexpr;
break;
/*
* All items marked with LEGACY are available, but not recomended
* by SUSv2 to be used in portable applications since they're subject
* to remove in future specification editions
*/
case YESSTR: /* LEGACY */
ret = (char*) __get_current_messages_locale()->yesstr;
break;
case NOSTR: /* LEGACY */
ret = (char*) __get_current_messages_locale()->nostr;
break;
case CRNCYSTR:
ret = "";
cs = (char*) __get_current_monetary_locale()->currency_symbol;
if (*cs != '\0') {
char pos = localeconv()->p_cs_precedes;
if (pos == localeconv()->n_cs_precedes) {
char psn = '\0';
if (pos == CHAR_MAX) {
if (strcmp(cs, __get_current_monetary_locale()->mon_decimal_point) == 0)
psn = '.';
} else
psn = pos ? '-' : '+';
if (psn != '\0') {
int clen = strlen(cs);
nptr = realloc(csym, clen + 2);
if (!nptr && csym)
free (csym);
csym = nptr;
if (csym != NULL) {
*csym = psn;
strcpy(csym + 1, cs);
ret = csym;
}
}
}
}
break;
case D_MD_ORDER: /* local extension */
ret = (char *) __get_current_time_locale()->md_order;
break;
#ifdef __HAVE_LOCALE_INFO__
case _NL_CTYPE_MB_CUR_MAX:
ret = (char *) __get_current_ctype_locale()->mb_cur_max;
break;
#endif
default:
#ifdef __HAVE_LOCALE_INFO_EXTENDED__
if (item > _NL_LOCALE_EXTENDED_FIRST_ENTRY
&& item < _NL_LOCALE_EXTENDED_LAST_ENTRY) {
int idx = item - _NL_LOCALE_EXTENDED_FIRST_ENTRY - 1;
return *(char **) ((char *) (*nl_ext[idx].base)()
+ nl_ext[idx].offset);
}
#endif
ret = "";
}
return (ret);
}