Print this page
2964 need POSIX 2008 locale object support
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libc/port/locale/setlocale.c
+++ new/usr/src/lib/libc/port/locale/setlocale.c
1 1 /*
2 + * Copyright 2014 Garrett D'Amore <garrett@damore.org>
2 3 * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
3 4 * Copyright (c) 1996 - 2002 FreeBSD Project
4 5 * Copyright (c) 1991, 1993
5 6 * The Regents of the University of California. All rights reserved.
6 7 *
7 8 * This code is derived from software contributed to Berkeley by
8 9 * Paul Borman at Krystal Technologies.
9 10 *
10 11 * Redistribution and use in source and binary forms, with or without
11 12 * modification, are permitted provided that the following conditions
12 13 * are met:
13 14 * 1. Redistributions of source code must retain the above copyright
14 15 * notice, this list of conditions and the following disclaimer.
15 16 * 2. Redistributions in binary form must reproduce the above copyright
16 17 * notice, this list of conditions and the following disclaimer in the
17 18 * documentation and/or other materials provided with the distribution.
18 19 * 4. Neither the name of the University nor the names of its contributors
19 20 * may be used to endorse or promote products derived from this software
20 21 * without specific prior written permission.
21 22 *
22 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 33 * SUCH DAMAGE.
33 34 */
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
34 35
35 36 #include "lint.h"
36 37 #include <sys/types.h>
37 38 #include <sys/stat.h>
38 39 #include <errno.h>
39 40 #include <limits.h>
40 41 #include <locale.h>
41 42 #include <stdlib.h>
42 43 #include <string.h>
43 44 #include <unistd.h>
44 -#include <alloca.h>
45 45 #include <stdio.h>
46 46 #include "collate.h"
47 -#include "lmonetary.h" /* for __monetary_load_locale() */
48 -#include "lnumeric.h" /* for __numeric_load_locale() */
49 -#include "lmessages.h" /* for __messages_load_locale() */
47 +#include "lnumeric.h" /* for struct lc_numeric */
48 +#include "lctype.h" /* for struct lc_ctype */
50 49 #include "setlocale.h"
51 -#include "ldpart.h"
52 -#include "timelocal.h" /* for __time_load_locale() */
53 50 #include "../i18n/_loc_path.h"
51 +#include "localeimpl.h"
52 +#include "../i18n/_locale.h"
54 53
55 54 /*
56 - * Category names for getenv() Note that this was modified
57 - * for Solaris. See <iso/locale_iso.h>.
58 - */
59 -#define NUM_CATS 7
60 -static char *categories[7] = {
61 - "LC_CTYPE",
62 - "LC_NUMERIC",
63 - "LC_TIME",
64 - "LC_COLLATE",
65 - "LC_MONETARY",
66 - "LC_MESSAGES",
67 - "LC_ALL",
68 -};
69 -
70 -/*
71 - * Current locales for each category
72 - */
73 -static char current_categories[NUM_CATS][ENCODING_LEN + 1] = {
74 - "C",
75 - "C",
76 - "C",
77 - "C",
78 - "C",
79 - "C",
80 - "C",
81 -};
82 -
83 -/*
84 55 * Path to locale storage directory. See ../i18n/_loc_path.h
85 56 */
86 57 char *_PathLocale = _DFLT_LOC_PATH;
87 58
88 -/*
89 - * The locales we are going to try and load
90 - */
91 -static char new_categories[NUM_CATS][ENCODING_LEN + 1];
92 -static char saved_categories[NUM_CATS][ENCODING_LEN + 1];
93 -static char current_locale_string[NUM_CATS * (ENCODING_LEN + 1 + 1)];
59 +static char *current_locale(locale_t, int);
60 +static void install_legacy(locale_t, int);
94 61
95 -static char *currentlocale(void);
96 -static char *loadlocale(int);
97 -static const char *__get_locale_env(int);
98 -
99 62 char *
100 -setlocale(int category, const char *locale)
63 +setlocale(int category, const char *locname)
101 64 {
102 - int i, j, saverr;
103 - const char *env, *r;
65 + locale_t oldloc;
66 + locale_t newloc;
67 + int mask;
104 68
105 - if (category < 0 || category >= NUM_CATS) {
69 + if (category < 0 || category > LC_ALL) {
106 70 errno = EINVAL;
107 71 return (NULL);
108 72 }
109 73
110 - if (locale == NULL)
111 - return (category != LC_ALL ?
112 - current_categories[category] : currentlocale());
74 + if (locname == NULL)
75 + return (current_locale(__global_locale, category));
113 76
114 - /*
115 - * Default to the current locale for everything.
116 - */
117 - for (i = 0; i < NUM_CATS; ++i)
118 - (void) strcpy(new_categories[i], current_categories[i]);
77 + if ((oldloc = duplocale(__global_locale)) == NULL)
78 + return (NULL);
119 79
120 - /*
121 - * Now go fill up new_categories from the locale argument
122 - */
123 - if (!*locale) {
124 - if (category == LC_ALL) {
125 - for (i = 0; i < NUM_CATS; ++i) {
126 - if (i == LC_ALL)
127 - continue;
128 - env = __get_locale_env(i);
129 - if (strlen(env) > ENCODING_LEN) {
130 - errno = EINVAL;
131 - return (NULL);
132 - }
133 - (void) strcpy(new_categories[i], env);
134 - }
135 - } else {
136 - env = __get_locale_env(category);
137 - if (strlen(env) > ENCODING_LEN) {
138 - errno = EINVAL;
139 - return (NULL);
140 - }
141 - (void) strcpy(new_categories[category], env);
142 - }
143 - } else if (category != LC_ALL) {
144 - if (strlen(locale) > ENCODING_LEN) {
145 - errno = EINVAL;
146 - return (NULL);
147 - }
148 - (void) strcpy(new_categories[category], locale);
149 - } else {
150 - if ((r = strchr(locale, '/')) == NULL) {
151 - if (strlen(locale) > ENCODING_LEN) {
152 - errno = EINVAL;
153 - return (NULL);
154 - }
155 - for (i = 0; i < NUM_CATS; ++i)
156 - (void) strcpy(new_categories[i], locale);
157 - } else {
158 - char *buf;
159 - char *save;
80 + mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
160 81
161 - buf = alloca(strlen(locale) + 1);
162 - (void) strcpy(buf, locale);
163 -
164 - save = NULL;
165 - r = strtok_r(buf, "/", &save);
166 - for (i = 0; i < NUM_CATS; i++) {
167 - if (i == LC_ALL)
168 - continue;
169 - if (r == NULL) {
170 - /*
171 - * Composite Locale is inadequately
172 - * specified! (Or with empty fields.)
173 - * The old code would fill fields
174 - * out from the last one, but I think
175 - * this is suboptimal.
176 - */
177 - errno = EINVAL;
178 - return (NULL);
179 - }
180 - (void) strlcpy(new_categories[i], r,
181 - ENCODING_LEN);
182 - r = strtok_r(NULL, "/", &save);
183 - }
184 - if (r != NULL) {
185 - /*
186 - * Too many components - we had left over
187 - * data in the LC_ALL. It is malformed.
188 - */
189 - errno = EINVAL;
190 - return (NULL);
191 - }
192 - }
82 + newloc = newlocale(mask, locname, oldloc);
83 + if (newloc == NULL) {
84 + freelocale(oldloc);
85 + return (NULL);
193 86 }
194 87
195 - if (category != LC_ALL)
196 - return (loadlocale(category));
88 + oldloc = __global_locale;
89 + __global_locale = newloc;
197 90
198 - for (i = 0; i < NUM_CATS; ++i) {
199 - (void) strcpy(saved_categories[i], current_categories[i]);
200 - if (i == LC_ALL)
201 - continue;
202 - if (loadlocale(i) == NULL) {
203 - saverr = errno;
204 - for (j = 0; j < i; j++) {
205 - (void) strcpy(new_categories[j],
206 - saved_categories[j]);
207 - if (i == LC_ALL)
208 - continue;
209 - if (loadlocale(j) == NULL) {
210 - (void) strcpy(new_categories[j], "C");
211 - (void) loadlocale(j);
212 - }
213 - }
214 - errno = saverr;
215 - return (NULL);
216 - }
217 - }
218 - return (currentlocale());
91 + install_legacy(newloc, mask);
92 +
93 + freelocale(oldloc);
94 + return (current_locale(newloc, category));
219 95 }
220 96
221 97 static char *
222 -currentlocale(void)
98 +current_locale(locale_t loc, int cat)
223 99 {
224 - int i;
225 100 int composite = 0;
101 + static char buf[LC_ALL * (ENCODING_LEN + 1 + 1)];
226 102
103 + if (cat != LC_ALL) {
104 + return (loc->locdata[cat]->l_lname);
105 + }
106 +
227 107 /* Look to see if any category is different */
228 - for (i = 1; i < NUM_CATS; ++i) {
229 - if (i == LC_ALL)
230 - continue;
231 - if (strcmp(current_categories[0], current_categories[i])) {
108 + for (int i = 1; i < LC_ALL; ++i) {
109 + if (strcmp(loc->locdata[0]->l_lname,
110 + loc->locdata[i]->l_lname) != 0) {
232 111 composite = 1;
233 112 break;
234 113 }
235 114 }
236 115
237 116 if (composite) {
238 117 /*
239 118 * Note ordering of these follows the numeric order,
240 119 * if the order is changed, then setlocale() will need
241 120 * to be changed as well.
242 121 */
243 - (void) snprintf(current_locale_string,
244 - sizeof (current_locale_string),
122 + (void) snprintf(buf, sizeof (buf),
245 123 "%s/%s/%s/%s/%s/%s",
246 - current_categories[LC_CTYPE],
247 - current_categories[LC_NUMERIC],
248 - current_categories[LC_TIME],
249 - current_categories[LC_COLLATE],
250 - current_categories[LC_MONETARY],
251 - current_categories[LC_MESSAGES]);
252 - } else {
253 - (void) strlcpy(current_locale_string, current_categories[0],
254 - sizeof (current_locale_string));
124 + loc->locdata[LC_CTYPE]->l_lname,
125 + loc->locdata[LC_NUMERIC]->l_lname,
126 + loc->locdata[LC_TIME]->l_lname,
127 + loc->locdata[LC_COLLATE]->l_lname,
128 + loc->locdata[LC_MONETARY]->l_lname,
129 + loc->locdata[LC_MESSAGES]->l_lname);
130 + return (buf);
255 131 }
256 - return (current_locale_string);
132 +
133 + return (loc->locdata[0]->l_lname);
257 134 }
258 135
259 -static char *
260 -loadlocale(int category)
136 +static void
137 +install_legacy(locale_t loc, int mask)
261 138 {
262 - char *new = new_categories[category];
263 - char *old = current_categories[category];
264 - int (*func)(const char *);
265 -
266 - if ((new[0] == '.' &&
267 - (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
268 - strchr(new, '/') != NULL) {
269 - errno = EINVAL;
270 - return (NULL);
139 + /*
140 + * Update the legacy fixed variables that may be baked into
141 + * legacy programs. This is really unfortunate, but we can't
142 + * solve for them otherwise. Note that such legacy programs
143 + * are only going to see the global locale settings, and cannot
144 + * benefit from uselocale().
145 + */
146 + if (mask & LC_NUMERIC_MASK) {
147 + struct lc_numeric *lnum;
148 + lnum = loc->locdata[LC_NUMERIC]->l_data[0];
149 + _numeric[0] = *lnum->decimal_point;
150 + _numeric[1] = *lnum->thousands_sep;
271 151 }
272 152
273 - switch (category) {
274 - case LC_CTYPE:
275 - func = __wrap_setrunelocale;
276 - break;
277 - case LC_COLLATE:
278 - func = _collate_load_tables;
279 - break;
280 - case LC_TIME:
281 - func = __time_load_locale;
282 - break;
283 - case LC_NUMERIC:
284 - func = __numeric_load_locale;
285 - break;
286 - case LC_MONETARY:
287 - func = __monetary_load_locale;
288 - break;
289 - case LC_MESSAGES:
290 - func = __messages_load_locale;
291 - break;
292 - default:
293 - errno = EINVAL;
294 - return (NULL);
295 - }
153 + if (mask & LC_CTYPE_MASK) {
154 + struct lc_ctype *lct;
155 + lct = loc->locdata[LC_CTYPE]->l_data[0];
156 + for (int i = 0; i < _CACHED_RUNES; i++) {
157 + /* ctype can only encode the lower 8 bits. */
158 + __ctype[i+1] = lct->lc_ctype_mask[i] & 0xff;
159 + __ctype_mask[i] = lct->lc_ctype_mask[i];
160 + }
296 161
297 - if (strcmp(new, old) == 0)
298 - return (old);
162 + /* The bottom half is the toupper/lower array */
163 + for (int i = 0; i < _CACHED_RUNES; i++) {
164 + int u, l;
165 + __ctype[258 + i] = i;
166 + u = lct->lc_trans_upper[i];
167 + l = lct->lc_trans_lower[i];
168 + if (u && u != i)
169 + __ctype[258+i] = u;
170 + if (l && l != i)
171 + __ctype[258+i] = l;
299 172
300 - if (func(new) != _LDP_ERROR) {
301 - (void) strcpy(old, new);
302 - return (old);
303 - }
173 + /* Don't forget these annoyances either! */
174 + __trans_upper[i] = u;
175 + __trans_lower[i] = l;
176 + }
304 177
305 - return (NULL);
306 -}
307 -
308 -static const char *
309 -__get_locale_env(int category)
310 -{
311 - const char *env;
312 -
313 - /* 1. check LC_ALL. */
314 - env = getenv(categories[LC_ALL]);
315 -
316 - /* 2. check LC_* */
317 - if (env == NULL || !*env)
318 - env = getenv(categories[category]);
319 -
320 - /* 3. check LANG */
321 - if (env == NULL || !*env)
322 - env = getenv("LANG");
323 -
324 - /* 4. if none is set, fall to "C" */
325 - if (env == NULL || !*env)
326 - env = "C";
327 -
328 - return (env);
178 + /* Maximum mblen, cswidth, weird legacy */
179 + __ctype[520] = lct->lc_max_mblen;
180 + }
329 181 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX