1 /* $NetBSD: setlocale.c,v 1.64 2013/09/13 13:13:32 joerg Exp $ */
4 * Copyright (c)2008 Citrus Project,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 #if defined(LIBC_SCCS) && !defined(lint)
31 __RCSID("$NetBSD: setlocale.c,v 1.64 2013/09/13 13:13:32 joerg Exp $");
32 #endif /* LIBC_SCCS and not lint */
34 #include <sys/types.h>
35 #include <sys/localedef.h>
43 #include "setlocale_local.h"
45 const char *_PathLocale
= NULL
;
47 static _locale_set_t all_categories
[_LC_LAST
] = {
48 [LC_ALL
] = &_generic_LC_ALL_setlocale
,
49 [LC_COLLATE
] = &_dummy_LC_COLLATE_setlocale
,
50 [LC_CTYPE
] = &_citrus_LC_CTYPE_setlocale
,
51 [LC_MONETARY
] = &_citrus_LC_MONETARY_setlocale
,
52 [LC_NUMERIC
] = &_citrus_LC_NUMERIC_setlocale
,
53 [LC_TIME
] = &_citrus_LC_TIME_setlocale
,
54 [LC_MESSAGES
] = &_citrus_LC_MESSAGES_setlocale
,
57 /* XXX Consider locking the list. Race condition leaks memory. */
58 static SLIST_HEAD(, _locale_cache_t
) caches
= {
63 _setlocale_cache(locale_t loc
, struct _locale_cache_t
*cache
)
65 const char *monetary_name
= loc
->part_name
[LC_MONETARY
];
66 const char *numeric_name
= loc
->part_name
[LC_NUMERIC
];
67 _NumericLocale
*numeric
= loc
->part_impl
[LC_NUMERIC
];
68 _MonetaryLocale
*monetary
= loc
->part_impl
[LC_MONETARY
];
71 struct _locale_cache_t
*old_cache
;
73 SLIST_FOREACH(old_cache
, &caches
, cache_link
) {
74 if (monetary_name
!= old_cache
->monetary_name
&&
75 strcmp(monetary_name
, old_cache
->monetary_name
) != 0)
77 if (numeric_name
!= old_cache
->numeric_name
&&
78 strcmp(numeric_name
, old_cache
->numeric_name
) != 0)
80 loc
->cache
= old_cache
;
86 cache
= malloc(sizeof(*cache
));
91 cache
->monetary_name
= monetary_name
;
92 cache
->numeric_name
= numeric_name
;
93 ldata
= &cache
->ldata
;
95 ldata
->decimal_point
= __UNCONST(numeric
->decimal_point
);
96 ldata
->thousands_sep
= __UNCONST(numeric
->thousands_sep
);
97 ldata
->grouping
= __UNCONST(numeric
->grouping
);
99 ldata
->int_curr_symbol
= __UNCONST(monetary
->int_curr_symbol
);
100 ldata
->currency_symbol
= __UNCONST(monetary
->currency_symbol
);
101 ldata
->mon_decimal_point
= __UNCONST(monetary
->mon_decimal_point
);
102 ldata
->mon_thousands_sep
= __UNCONST(monetary
->mon_thousands_sep
);
103 ldata
->mon_grouping
= __UNCONST(monetary
->mon_grouping
);
104 ldata
->positive_sign
= __UNCONST(monetary
->positive_sign
);
105 ldata
->negative_sign
= __UNCONST(monetary
->negative_sign
);
107 ldata
->int_frac_digits
= monetary
->int_frac_digits
;
108 ldata
->frac_digits
= monetary
->frac_digits
;
109 ldata
->p_cs_precedes
= monetary
->p_cs_precedes
;
110 ldata
->p_sep_by_space
= monetary
->p_sep_by_space
;
111 ldata
->n_cs_precedes
= monetary
->n_cs_precedes
;
112 ldata
->n_sep_by_space
= monetary
->n_sep_by_space
;
113 ldata
->p_sign_posn
= monetary
->p_sign_posn
;
114 ldata
->n_sign_posn
= monetary
->n_sign_posn
;
115 ldata
->int_p_cs_precedes
= monetary
->int_p_cs_precedes
;
116 ldata
->int_n_cs_precedes
= monetary
->int_n_cs_precedes
;
117 ldata
->int_p_sep_by_space
= monetary
-> int_p_sep_by_space
;
118 ldata
->int_n_sep_by_space
= monetary
->int_n_sep_by_space
;
119 ldata
->int_p_sign_posn
= monetary
->int_p_sign_posn
;
120 ldata
->int_n_sign_posn
= monetary
->int_n_sign_posn
;
121 SLIST_INSERT_HEAD(&caches
, cache
, cache_link
);
128 _find_category(int category
)
130 static int initialised
;
133 if (issetugid() || ((_PathLocale
== NULL
&&
134 (_PathLocale
= getenv("PATH_LOCALE")) == NULL
) ||
135 *_PathLocale
== '\0'))
136 _PathLocale
= _PATH_LOCALE
;
140 if (category
>= LC_ALL
&& category
< _LC_LAST
)
141 return all_categories
[category
];
146 _get_locale_env(const char *category
)
150 /* 1. check LC_ALL */
151 name
= (const char *)getenv("LC_ALL");
152 if (name
== NULL
|| *name
== '\0') {
154 name
= (const char *)getenv(category
);
155 if (name
== NULL
|| *name
== '\0') {
157 name
= getenv("LANG");
160 if (name
== NULL
|| *name
== '\0' || strchr(name
, '/'))
161 /* 4. if none is set, fall to "C" */
167 __setlocale(int category
, const char *name
)
171 struct _locale_cache_t
*cache
;
174 sl
= _find_category(category
);
177 cache
= malloc(sizeof(*cache
));
180 loc
= _current_locale();
181 result
= (*sl
)(name
, loc
);
182 _setlocale_cache(loc
, cache
);
183 return __UNCONST(result
);
187 setlocale(int category
, const char *locale
)
190 /* locale may be NULL */
192 __mb_len_max_runtime
= MB_LEN_MAX
;
193 return __setlocale(category
, locale
);