1 /*-
2 * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 */
26
27 #define _GNU_SOURCE
28 #include "setlocale.h"
29
30 #undef offsetoff
31 #define _O(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
32
33 #define _NLITEM(cat,memb) { { .cat = __get_##cat##_locale }, \
34 _O (struct lc_##cat##_T, memb) }
35
36 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
37 static struct _nl_item_t
38 {
39 union {
40 const struct lc_ctype_T * (*ctype)(struct __locale_t *);
41 const struct lc_time_T * (*time)(struct __locale_t *);
42 const struct lc_numeric_T * (*numeric)(struct __locale_t *);
43 const struct lc_monetary_T * (*monetary)(struct __locale_t *);
44 const struct lc_messages_T * (*messages)(struct __locale_t *);
45 void * (*base)(struct __locale_t *);
46 };
47 _off_t offset;
48 } nl_ext[] =
49 {
50 /* First element has an nl_item value of _NL_LOCALE_EXTENDED_FIRST_ENTRY */
51 _NLITEM (ctype, outdigits[0]),
52 _NLITEM (ctype, outdigits[1]),
53 _NLITEM (ctype, outdigits[2]),
54 _NLITEM (ctype, outdigits[3]),
55 _NLITEM (ctype, outdigits[4]),
56 _NLITEM (ctype, outdigits[5]),
57 _NLITEM (ctype, outdigits[6]),
58 _NLITEM (ctype, outdigits[7]),
59 _NLITEM (ctype, outdigits[8]),
60 _NLITEM (ctype, outdigits[9]),
61 _NLITEM (ctype, woutdigits[0]),
62 _NLITEM (ctype, woutdigits[1]),
63 _NLITEM (ctype, woutdigits[2]),
64 _NLITEM (ctype, woutdigits[3]),
65 _NLITEM (ctype, woutdigits[4]),
66 _NLITEM (ctype, woutdigits[5]),
67 _NLITEM (ctype, woutdigits[6]),
68 _NLITEM (ctype, woutdigits[7]),
69 _NLITEM (ctype, woutdigits[8]),
70 _NLITEM (ctype, woutdigits[9]),
71 _NLITEM (time, codeset),
72 _NLITEM (time, wmon[0]),
73 _NLITEM (time, wmon[1]),
74 _NLITEM (time, wmon[2]),
75 _NLITEM (time, wmon[3]),
76 _NLITEM (time, wmon[4]),
77 _NLITEM (time, wmon[5]),
78 _NLITEM (time, wmon[6]),
79 _NLITEM (time, wmon[7]),
80 _NLITEM (time, wmon[8]),
81 _NLITEM (time, wmon[9]),
82 _NLITEM (time, wmon[10]),
83 _NLITEM (time, wmon[11]),
84 _NLITEM (time, wmonth[0]),
85 _NLITEM (time, wmonth[1]),
86 _NLITEM (time, wmonth[2]),
87 _NLITEM (time, wmonth[3]),
88 _NLITEM (time, wmonth[4]),
89 _NLITEM (time, wmonth[5]),
90 _NLITEM (time, wmonth[6]),
91 _NLITEM (time, wmonth[7]),
92 _NLITEM (time, wmonth[8]),
93 _NLITEM (time, wmonth[9]),
94 _NLITEM (time, wmonth[10]),
95 _NLITEM (time, wmonth[11]),
96 _NLITEM (time, wwday[0]),
97 _NLITEM (time, wwday[1]),
98 _NLITEM (time, wwday[2]),
99 _NLITEM (time, wwday[3]),
100 _NLITEM (time, wwday[4]),
101 _NLITEM (time, wwday[5]),
102 _NLITEM (time, wwday[6]),
103 _NLITEM (time, wweekday[0]),
104 _NLITEM (time, wweekday[1]),
105 _NLITEM (time, wweekday[2]),
106 _NLITEM (time, wweekday[3]),
107 _NLITEM (time, wweekday[4]),
108 _NLITEM (time, wweekday[5]),
109 _NLITEM (time, wweekday[6]),
110 _NLITEM (time, wX_fmt),
111 _NLITEM (time, wx_fmt),
112 _NLITEM (time, wc_fmt),
113 _NLITEM (time, wam_pm[0]),
114 _NLITEM (time, wam_pm[1]),
115 _NLITEM (time, wdate_fmt),
116 _NLITEM (time, wampm_fmt),
117 _NLITEM (time, wera),
118 _NLITEM (time, wera_d_fmt),
119 _NLITEM (time, wera_d_t_fmt),
120 _NLITEM (time, wera_t_fmt),
121 _NLITEM (time, walt_digits),
122 _NLITEM (numeric, codeset),
123 _NLITEM (numeric, grouping),
124 _NLITEM (numeric, wdecimal_point),
125 _NLITEM (numeric, wthousands_sep),
126 _NLITEM (monetary, int_curr_symbol),
127 _NLITEM (monetary, currency_symbol),
128 _NLITEM (monetary, mon_decimal_point),
129 _NLITEM (monetary, mon_thousands_sep),
130 _NLITEM (monetary, mon_grouping),
131 _NLITEM (monetary, positive_sign),
132 _NLITEM (monetary, negative_sign),
133 _NLITEM (monetary, int_frac_digits),
134 _NLITEM (monetary, frac_digits),
135 _NLITEM (monetary, p_cs_precedes),
136 _NLITEM (monetary, p_sep_by_space),
137 _NLITEM (monetary, n_cs_precedes),
138 _NLITEM (monetary, n_sep_by_space),
139 _NLITEM (monetary, p_sign_posn),
140 _NLITEM (monetary, n_sign_posn),
141 _NLITEM (monetary, int_p_cs_precedes),
142 _NLITEM (monetary, int_p_sep_by_space),
143 _NLITEM (monetary, int_n_cs_precedes),
144 _NLITEM (monetary, int_n_sep_by_space),
145 _NLITEM (monetary, int_p_sign_posn),
146 _NLITEM (monetary, int_n_sign_posn),
147 _NLITEM (monetary, codeset),
148 _NLITEM (monetary, wint_curr_symbol),
149 _NLITEM (monetary, wcurrency_symbol),
150 _NLITEM (monetary, wmon_decimal_point),
151 _NLITEM (monetary, wmon_thousands_sep),
152 _NLITEM (monetary, wpositive_sign),
153 _NLITEM (monetary, wnegative_sign),
154 _NLITEM (messages, wyesexpr),
155 _NLITEM (messages, wnoexpr),
156 _NLITEM (messages, wyesstr),
157 _NLITEM (messages, wnostr),
158 };
159 #endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
160
161 #define _REL(BASE) ((int)item-BASE)
162
nl_langinfo_l(nl_item item,struct __locale_t * locale)163 char *nl_langinfo_l (nl_item item, struct __locale_t *locale)
164 {
165 char *ret, *cs;
166 static char *csym = NULL;
167 char *nptr;
168
169 switch (item) {
170 #ifdef __HAVE_LOCALE_INFO__
171 case _NL_MESSAGES_CODESET:
172 ret = (char *) __locale_msgcharset();
173 goto do_codeset;
174 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
175 case _NL_TIME_CODESET:
176 ret = (char *) __get_time_locale (locale)->codeset;
177 goto do_codeset;
178 case _NL_NUMERIC_CODESET:
179 ret = (char *) __get_numeric_locale (locale)->codeset;
180 goto do_codeset;
181 case _NL_MONETARY_CODESET:
182 ret = (char *) __get_monetary_locale (locale)->codeset;
183 goto do_codeset;
184 #endif /* __HAVE_LOCALE_INFO_EXTENDED__ */
185 #endif /* __HAVE_LOCALE_INFO__ */
186 case CODESET:
187 #ifdef _MB_CAPABLE
188 ret = (char *) __locale_charset (locale);
189 #endif
190 #ifdef __HAVE_LOCALE_INFO__
191 do_codeset:
192 #endif
193 #if !defined (_MB_CAPABLE)
194 ret = "US-ASCII";
195 #endif /* __CYGWIN__ */
196 break;
197 case D_T_FMT:
198 ret = (char *) __get_time_locale (locale)->c_fmt;
199 break;
200 case D_FMT:
201 ret = (char *) __get_time_locale (locale)->x_fmt;
202 break;
203 case T_FMT:
204 ret = (char *) __get_time_locale (locale)->X_fmt;
205 break;
206 case T_FMT_AMPM:
207 ret = (char *) __get_time_locale (locale)->ampm_fmt;
208 break;
209 case AM_STR:
210 ret = (char *) __get_time_locale (locale)->am_pm[0];
211 break;
212 case PM_STR:
213 ret = (char *) __get_time_locale (locale)->am_pm[1];
214 break;
215 case DAY_1: case DAY_2: case DAY_3:
216 case DAY_4: case DAY_5: case DAY_6: case DAY_7:
217 ret = (char*) __get_time_locale (locale)->weekday[_REL(DAY_1)];
218 break;
219 case ABDAY_1: case ABDAY_2: case ABDAY_3:
220 case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
221 ret = (char*) __get_time_locale (locale)->wday[_REL(ABDAY_1)];
222 break;
223 case MON_1: case MON_2: case MON_3: case MON_4:
224 case MON_5: case MON_6: case MON_7: case MON_8:
225 case MON_9: case MON_10: case MON_11: case MON_12:
226 ret = (char*) __get_time_locale (locale)->month[_REL(MON_1)];
227 break;
228 case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
229 case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
230 case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
231 ret = (char*) __get_time_locale (locale)->mon[_REL(ABMON_1)];
232 break;
233 case ERA:
234 ret = (char*) __get_time_locale (locale)->era;
235 break;
236 case ERA_D_FMT:
237 ret = (char*) __get_time_locale (locale)->era_d_fmt;
238 break;
239 case ERA_D_T_FMT:
240 ret = (char*) __get_time_locale (locale)->era_d_t_fmt;
241 break;
242 case ERA_T_FMT:
243 ret = (char*) __get_time_locale (locale)->era_t_fmt;
244 break;
245 case ALT_DIGITS:
246 ret = (char*) __get_time_locale (locale)->alt_digits;
247 break;
248 case _DATE_FMT: /* GNU extension */
249 ret = (char*) __get_time_locale (locale)->date_fmt;
250 break;
251 case RADIXCHAR:
252 ret = (char*) __get_numeric_locale (locale)->decimal_point;
253 break;
254 case THOUSEP:
255 ret = (char*) __get_numeric_locale (locale)->thousands_sep;
256 break;
257 case YESEXPR:
258 ret = (char*) __get_messages_locale (locale)->yesexpr;
259 break;
260 case NOEXPR:
261 ret = (char*) __get_messages_locale (locale)->noexpr;
262 break;
263 /*
264 * All items marked with LEGACY are available, but not recomended
265 * by SUSv2 to be used in portable applications since they're subject
266 * to remove in future specification editions
267 */
268 case YESSTR: /* LEGACY */
269 ret = (char*) __get_messages_locale (locale)->yesstr;
270 break;
271 case NOSTR: /* LEGACY */
272 ret = (char*) __get_messages_locale (locale)->nostr;
273 break;
274 case CRNCYSTR:
275 ret = "";
276 cs = (char*) __get_monetary_locale (locale)->currency_symbol;
277 if (*cs != '\0') {
278 char pos = __localeconv_l (locale)->p_cs_precedes;
279
280 if (pos == __localeconv_l (locale)->n_cs_precedes) {
281 char psn = '\0';
282
283 if (pos == CHAR_MAX) {
284 if (strcmp(cs, __get_monetary_locale (locale)->mon_decimal_point) == 0)
285 psn = '.';
286 } else
287 psn = pos ? '-' : '+';
288 if (psn != '\0') {
289 int clen = strlen(cs);
290
291 nptr = realloc(csym, clen + 2);
292 if (!nptr && csym)
293 free (csym);
294
295 csym = nptr;
296
297 if (csym != NULL) {
298 *csym = psn;
299 strcpy(csym + 1, cs);
300 ret = csym;
301 }
302 }
303 }
304 }
305 break;
306 case D_MD_ORDER: /* local extension */
307 ret = (char *) __get_time_locale (locale)->md_order;
308 break;
309 #ifdef __HAVE_LOCALE_INFO__
310 case _NL_CTYPE_MB_CUR_MAX:
311 ret = (char *) __get_ctype_locale (locale)->mb_cur_max;
312 break;
313 #endif
314 default:
315 /* Relies on the fact that LC_ALL is 0, and all other
316 LC_ constants are in ascending order. */
317 if (item > NL_LOCALE_NAME(LC_ALL)
318 && item < NL_LOCALE_NAME(_LC_LAST)) {
319 return locale->categories[item
320 - NL_LOCALE_NAME(LC_ALL)];
321 }
322 #ifdef __HAVE_LOCALE_INFO_EXTENDED__
323 if (item > _NL_LOCALE_EXTENDED_FIRST_ENTRY
324 && item < _NL_LOCALE_EXTENDED_LAST_ENTRY) {
325 int idx = item - _NL_LOCALE_EXTENDED_FIRST_ENTRY - 1;
326 return *(char **) ((char *) (*nl_ext[idx].base)(locale)
327 + nl_ext[idx].offset);
328 }
329 #endif
330 ret = "";
331 }
332 return (ret);
333 }
334
nl_langinfo(nl_item item)335 char *nl_langinfo (nl_item item)
336 {
337 return nl_langinfo_l (item, __get_current_locale ());
338 }
339