2 * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
37 #include "setlocale.h"
40 #define _O(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
42 #define _NLITEM(cat,memb) { { cat:__get_##cat##_locale }, \
43 _O (struct lc_##cat##_T, memb) }
45 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
46 static struct _nl_item_t
49 const struct lc_ctype_T
* (*ctype
)(struct __locale_t
*);
50 const struct lc_time_T
* (*time
)(struct __locale_t
*);
51 const struct lc_numeric_T
* (*numeric
)(struct __locale_t
*);
52 const struct lc_monetary_T
* (*monetary
)(struct __locale_t
*);
53 const struct lc_messages_T
* (*messages
)(struct __locale_t
*);
54 void * (*base
)(struct __locale_t
*);
59 /* First element has an nl_item value of _NL_LOCALE_EXTENDED_FIRST_ENTRY */
60 _NLITEM (ctype
, outdigits
[0]),
61 _NLITEM (ctype
, outdigits
[1]),
62 _NLITEM (ctype
, outdigits
[2]),
63 _NLITEM (ctype
, outdigits
[3]),
64 _NLITEM (ctype
, outdigits
[4]),
65 _NLITEM (ctype
, outdigits
[5]),
66 _NLITEM (ctype
, outdigits
[6]),
67 _NLITEM (ctype
, outdigits
[7]),
68 _NLITEM (ctype
, outdigits
[8]),
69 _NLITEM (ctype
, outdigits
[9]),
70 _NLITEM (ctype
, woutdigits
[0]),
71 _NLITEM (ctype
, woutdigits
[1]),
72 _NLITEM (ctype
, woutdigits
[2]),
73 _NLITEM (ctype
, woutdigits
[3]),
74 _NLITEM (ctype
, woutdigits
[4]),
75 _NLITEM (ctype
, woutdigits
[5]),
76 _NLITEM (ctype
, woutdigits
[6]),
77 _NLITEM (ctype
, woutdigits
[7]),
78 _NLITEM (ctype
, woutdigits
[8]),
79 _NLITEM (ctype
, woutdigits
[9]),
80 _NLITEM (time
, codeset
),
81 _NLITEM (time
, wmon
[0]),
82 _NLITEM (time
, wmon
[1]),
83 _NLITEM (time
, wmon
[2]),
84 _NLITEM (time
, wmon
[3]),
85 _NLITEM (time
, wmon
[4]),
86 _NLITEM (time
, wmon
[5]),
87 _NLITEM (time
, wmon
[6]),
88 _NLITEM (time
, wmon
[7]),
89 _NLITEM (time
, wmon
[8]),
90 _NLITEM (time
, wmon
[9]),
91 _NLITEM (time
, wmon
[10]),
92 _NLITEM (time
, wmon
[11]),
93 _NLITEM (time
, wmonth
[0]),
94 _NLITEM (time
, wmonth
[1]),
95 _NLITEM (time
, wmonth
[2]),
96 _NLITEM (time
, wmonth
[3]),
97 _NLITEM (time
, wmonth
[4]),
98 _NLITEM (time
, wmonth
[5]),
99 _NLITEM (time
, wmonth
[6]),
100 _NLITEM (time
, wmonth
[7]),
101 _NLITEM (time
, wmonth
[8]),
102 _NLITEM (time
, wmonth
[9]),
103 _NLITEM (time
, wmonth
[10]),
104 _NLITEM (time
, wmonth
[11]),
105 _NLITEM (time
, wwday
[0]),
106 _NLITEM (time
, wwday
[1]),
107 _NLITEM (time
, wwday
[2]),
108 _NLITEM (time
, wwday
[3]),
109 _NLITEM (time
, wwday
[4]),
110 _NLITEM (time
, wwday
[5]),
111 _NLITEM (time
, wwday
[6]),
112 _NLITEM (time
, wweekday
[0]),
113 _NLITEM (time
, wweekday
[1]),
114 _NLITEM (time
, wweekday
[2]),
115 _NLITEM (time
, wweekday
[3]),
116 _NLITEM (time
, wweekday
[4]),
117 _NLITEM (time
, wweekday
[5]),
118 _NLITEM (time
, wweekday
[6]),
119 _NLITEM (time
, wX_fmt
),
120 _NLITEM (time
, wx_fmt
),
121 _NLITEM (time
, wc_fmt
),
122 _NLITEM (time
, wam_pm
[0]),
123 _NLITEM (time
, wam_pm
[1]),
124 _NLITEM (time
, wdate_fmt
),
125 _NLITEM (time
, wampm_fmt
),
126 _NLITEM (time
, wera
),
127 _NLITEM (time
, wera_d_fmt
),
128 _NLITEM (time
, wera_d_t_fmt
),
129 _NLITEM (time
, wera_t_fmt
),
130 _NLITEM (time
, walt_digits
),
131 _NLITEM (numeric
, codeset
),
132 _NLITEM (numeric
, grouping
),
133 _NLITEM (numeric
, wdecimal_point
),
134 _NLITEM (numeric
, wthousands_sep
),
135 _NLITEM (monetary
, int_curr_symbol
),
136 _NLITEM (monetary
, currency_symbol
),
137 _NLITEM (monetary
, mon_decimal_point
),
138 _NLITEM (monetary
, mon_thousands_sep
),
139 _NLITEM (monetary
, mon_grouping
),
140 _NLITEM (monetary
, positive_sign
),
141 _NLITEM (monetary
, negative_sign
),
142 _NLITEM (monetary
, int_frac_digits
),
143 _NLITEM (monetary
, frac_digits
),
144 _NLITEM (monetary
, p_cs_precedes
),
145 _NLITEM (monetary
, p_sep_by_space
),
146 _NLITEM (monetary
, n_cs_precedes
),
147 _NLITEM (monetary
, n_sep_by_space
),
148 _NLITEM (monetary
, p_sign_posn
),
149 _NLITEM (monetary
, n_sign_posn
),
150 _NLITEM (monetary
, int_p_cs_precedes
),
151 _NLITEM (monetary
, int_p_sep_by_space
),
152 _NLITEM (monetary
, int_n_cs_precedes
),
153 _NLITEM (monetary
, int_n_sep_by_space
),
154 _NLITEM (monetary
, int_p_sign_posn
),
155 _NLITEM (monetary
, int_n_sign_posn
),
156 _NLITEM (monetary
, codeset
),
157 _NLITEM (monetary
, wint_curr_symbol
),
158 _NLITEM (monetary
, wcurrency_symbol
),
159 _NLITEM (monetary
, wmon_decimal_point
),
160 _NLITEM (monetary
, wmon_thousands_sep
),
161 _NLITEM (monetary
, wpositive_sign
),
162 _NLITEM (monetary
, wnegative_sign
),
163 _NLITEM (messages
, wyesexpr
),
164 _NLITEM (messages
, wnoexpr
),
165 _NLITEM (messages
, wyesstr
),
166 _NLITEM (messages
, wnostr
),
168 #endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
170 #define _REL(BASE) ((int)item-BASE)
172 char *nl_langinfo_l (nl_item item
, struct __locale_t
*locale
)
178 static char *csym
= NULL
;
182 #ifdef __HAVE_LOCALE_INFO__
183 case _NL_MESSAGES_CODESET
:
184 ret
= (char *) __get_messages_locale (locale
)->codeset
;
186 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
187 case _NL_TIME_CODESET
:
188 ret
= (char *) __get_time_locale (locale
)->codeset
;
190 case _NL_NUMERIC_CODESET
:
191 ret
= (char *) __get_numeric_locale (locale
)->codeset
;
193 case _NL_MONETARY_CODESET
:
194 ret
= (char *) __get_monetary_locale (locale
)->codeset
;
197 case _NL_COLLATE_CODESET
:
199 ret
= (char *) __get_collate_locale (locale
)->codeset
;
202 #endif /* __CYGWIN__ */
203 #endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
204 #endif /* __HAVE_LOCALE_INFO__ */
207 ret
= (char *) __locale_charset (locale
);
211 /* Convert charset to Linux compatible codeset string. */
212 if (ret
[0] == 'A'/*SCII*/)
213 ret
= "ANSI_X3.4-1968";
214 else if (ret
[0] == 'E')
216 if (strcmp (ret
, "EUCJP") == 0)
218 else if (strcmp (ret
, "EUCKR") == 0)
220 else if (strcmp (ret
, "EUCCN") == 0)
223 else if (ret
[0] == 'C'/*Pxxxx*/)
225 if (strcmp (ret
+ 2, "874") == 0)
227 else if (strcmp (ret
+ 2, "20866") == 0)
229 else if (strcmp (ret
+ 2, "21866") == 0)
231 else if (strcmp (ret
+ 2, "101") == 0)
233 else if (strcmp (ret
+ 2, "102") == 0)
235 else if (strcmp (ret
+ 2, "103") == 0)
238 else if (ret
[0] == 'S'/*JIS*/)
240 /* Cygwin uses MSFT's implementation of SJIS, which differs
241 in some codepoints from the real thing, especially
242 0x5c: yen sign instead of backslash,
243 0x7e: overline instead of tilde.
244 We can't use the real SJIS since otherwise Win32
245 pathnames would become invalid. OTOH, if we return
246 "SJIS" here, then libiconv will do mb<->wc conversion
247 differently to our internal functions. Therefore we
248 return what we really implement, CP932. This is handled
252 #elif !defined (_MB_CAPABLE)
254 #endif /* __CYGWIN__ */
257 ret
= (char *) __get_time_locale (locale
)->c_fmt
;
260 ret
= (char *) __get_time_locale (locale
)->x_fmt
;
263 ret
= (char *) __get_time_locale (locale
)->X_fmt
;
266 ret
= (char *) __get_time_locale (locale
)->ampm_fmt
;
269 ret
= (char *) __get_time_locale (locale
)->am_pm
[0];
272 ret
= (char *) __get_time_locale (locale
)->am_pm
[1];
274 case DAY_1
: case DAY_2
: case DAY_3
:
275 case DAY_4
: case DAY_5
: case DAY_6
: case DAY_7
:
276 ret
= (char*) __get_time_locale (locale
)->weekday
[_REL(DAY_1
)];
278 case ABDAY_1
: case ABDAY_2
: case ABDAY_3
:
279 case ABDAY_4
: case ABDAY_5
: case ABDAY_6
: case ABDAY_7
:
280 ret
= (char*) __get_time_locale (locale
)->wday
[_REL(ABDAY_1
)];
282 case MON_1
: case MON_2
: case MON_3
: case MON_4
:
283 case MON_5
: case MON_6
: case MON_7
: case MON_8
:
284 case MON_9
: case MON_10
: case MON_11
: case MON_12
:
285 ret
= (char*) __get_time_locale (locale
)->month
[_REL(MON_1
)];
287 case ABMON_1
: case ABMON_2
: case ABMON_3
: case ABMON_4
:
288 case ABMON_5
: case ABMON_6
: case ABMON_7
: case ABMON_8
:
289 case ABMON_9
: case ABMON_10
: case ABMON_11
: case ABMON_12
:
290 ret
= (char*) __get_time_locale (locale
)->mon
[_REL(ABMON_1
)];
293 ret
= (char*) __get_time_locale (locale
)->era
;
296 ret
= (char*) __get_time_locale (locale
)->era_d_fmt
;
299 ret
= (char*) __get_time_locale (locale
)->era_d_t_fmt
;
302 ret
= (char*) __get_time_locale (locale
)->era_t_fmt
;
305 ret
= (char*) __get_time_locale (locale
)->alt_digits
;
307 case _DATE_FMT
: /* GNU extension */
308 ret
= (char*) __get_time_locale (locale
)->date_fmt
;
311 ret
= (char*) __get_numeric_locale (locale
)->decimal_point
;
314 ret
= (char*) __get_numeric_locale (locale
)->thousands_sep
;
317 ret
= (char*) __get_messages_locale (locale
)->yesexpr
;
320 ret
= (char*) __get_messages_locale (locale
)->noexpr
;
323 * All items marked with LEGACY are available, but not recomended
324 * by SUSv2 to be used in portable applications since they're subject
325 * to remove in future specification editions
327 case YESSTR
: /* LEGACY */
328 ret
= (char*) __get_messages_locale (locale
)->yesstr
;
330 case NOSTR
: /* LEGACY */
331 ret
= (char*) __get_messages_locale (locale
)->nostr
;
335 cs
= (char*) __get_monetary_locale (locale
)->currency_symbol
;
337 char pos
= __localeconv_l (locale
)->p_cs_precedes
;
339 if (pos
== __localeconv_l (locale
)->n_cs_precedes
) {
342 if (pos
== CHAR_MAX
) {
343 if (strcmp(cs
, __get_monetary_locale (locale
)->mon_decimal_point
) == 0)
346 psn
= pos
? '-' : '+';
348 int clen
= strlen(cs
);
350 nptr
= realloc(csym
, clen
+ 2);
358 strcpy(csym
+ 1, cs
);
365 case D_MD_ORDER
: /* local extension */
366 ret
= (char *) __get_time_locale (locale
)->md_order
;
368 #ifdef __HAVE_LOCALE_INFO__
369 case _NL_CTYPE_MB_CUR_MAX
:
370 ret
= (char *) __get_ctype_locale (locale
)->mb_cur_max
;
374 /* Relies on the fact that LC_ALL is 0, and all other
375 LC_ constants are in ascending order. */
376 if (item
> NL_LOCALE_NAME(LC_ALL
)
377 && item
< NL_LOCALE_NAME(_LC_LAST
)) {
378 return locale
->categories
[item
379 - NL_LOCALE_NAME(LC_ALL
)];
381 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
382 if (item
> _NL_LOCALE_EXTENDED_FIRST_ENTRY
383 && item
< _NL_LOCALE_EXTENDED_LAST_ENTRY
) {
384 int idx
= item
- _NL_LOCALE_EXTENDED_FIRST_ENTRY
- 1;
385 return *(char **) ((char *) (*nl_ext
[idx
].base
)(locale
)
386 + nl_ext
[idx
].offset
);
394 char *nl_langinfo (nl_item item
)
396 return nl_langinfo_l (item
, __get_current_locale ());