]>
Commit | Line | Data |
---|---|---|
c84142e8 UD |
1 | /* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
28f540f4 | 3 | |
c84142e8 UD |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public License as | |
6 | published by the Free Software Foundation; either version 2 of the | |
7 | License, or (at your option) any later version. | |
28f540f4 | 8 | |
c84142e8 UD |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Library General Public License for more details. | |
28f540f4 | 13 | |
c84142e8 UD |
14 | You should have received a copy of the GNU Library General Public |
15 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
16 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 | Boston, MA 02111-1307, USA. */ | |
28f540f4 | 18 | |
7a12c6bb RM |
19 | #include <alloca.h> |
20 | #include <argz.h> | |
28f540f4 | 21 | #include <errno.h> |
a5113b14 | 22 | #include <libc-lock.h> |
933e73fa | 23 | #include <locale.h> |
7a12c6bb RM |
24 | #include <stdlib.h> |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | ||
933e73fa RM |
28 | #include "localeinfo.h" |
29 | ||
30 | /* For each category declare two external variables (with weak references): | |
31 | extern const struct locale_data *_nl_current_CATEGORY; | |
32 | This points to the current locale's in-core data for CATEGORY. | |
33 | extern const struct locale_data _nl_C_CATEGORY; | |
34 | This contains the built-in "C"/"POSIX" locale's data for CATEGORY. | |
35 | Both are weak references; if &_nl_current_CATEGORY is zero, | |
36 | then nothing is using the locale data. */ | |
37 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
c84142e8 UD |
38 | extern struct locale_data *_nl_current_##category; \ |
39 | extern struct locale_data _nl_C_##category; \ | |
0676b5fd | 40 | weak_extern (_nl_current_##category) weak_extern (_nl_C_##category) |
933e73fa RM |
41 | #include "categories.def" |
42 | #undef DEFINE_CATEGORY | |
43 | ||
44 | /* Array indexed by category of pointers to _nl_current_CATEGORY slots. | |
45 | Elements are zero for categories whose data is never used. */ | |
c84142e8 | 46 | static struct locale_data * *const _nl_current[] = |
7a12c6bb | 47 | { |
933e73fa | 48 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ |
7a12c6bb | 49 | [category] = &_nl_current_##category, |
933e73fa RM |
50 | #include "categories.def" |
51 | #undef DEFINE_CATEGORY | |
c131718c UD |
52 | /* We need this additional element to simplify the code. It must |
53 | simply be != NULL. */ | |
54 | [LC_ALL] = (struct locale_data **) ~0ul | |
7a12c6bb | 55 | }; |
933e73fa RM |
56 | |
57 | /* Array indexed by category of pointers to _nl_C_CATEGORY slots. | |
58 | Elements are zero for categories whose data is never used. */ | |
c84142e8 | 59 | struct locale_data *const _nl_C[] = |
036cc82f | 60 | { |
933e73fa | 61 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ |
036cc82f | 62 | [category] = &_nl_C_##category, |
933e73fa RM |
63 | #include "categories.def" |
64 | #undef DEFINE_CATEGORY | |
036cc82f | 65 | }; |
933e73fa RM |
66 | |
67 | ||
68 | /* Define an array of category names (also the environment variable names), | |
69 | indexed by integral category. */ | |
70 | const char *const _nl_category_names[] = | |
71 | { | |
72 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
73 | [category] = category_name, | |
74 | #include "categories.def" | |
75 | #undef DEFINE_CATEGORY | |
7a12c6bb | 76 | [LC_ALL] = "LC_ALL" |
933e73fa RM |
77 | }; |
78 | /* An array of their lengths, for convenience. */ | |
79 | const size_t _nl_category_name_sizes[] = | |
80 | { | |
81 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
82 | [category] = sizeof (category_name) - 1, | |
83 | #include "categories.def" | |
84 | #undef DEFINE_CATEGORY | |
7a12c6bb | 85 | [LC_ALL] = sizeof ("LC_ALL") - 1 |
933e73fa | 86 | }; |
28f540f4 RM |
87 | |
88 | ||
933e73fa RM |
89 | /* Declare the postload functions used below. */ |
90 | #undef NO_POSTLOAD | |
91 | #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist. */ | |
92 | #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \ | |
93 | extern void postload (void); | |
94 | #include "categories.def" | |
95 | #undef DEFINE_CATEGORY | |
96 | #undef NO_POSTLOAD | |
97 | ||
98 | /* Define an array indexed by category of postload functions to call after | |
99 | loading and installing that category's data. */ | |
a5113b14 | 100 | static void (*const _nl_category_postload[]) (void) = |
933e73fa RM |
101 | { |
102 | #define DEFINE_CATEGORY(category, category_name, items, postload, b, c, d) \ | |
103 | [category] = postload, | |
104 | #include "categories.def" | |
105 | #undef DEFINE_CATEGORY | |
106 | }; | |
107 | ||
108 | ||
933e73fa RM |
109 | /* Name of current locale for each individual category. |
110 | Each is malloc'd unless it is nl_C_name. */ | |
7a12c6bb | 111 | static const char *_nl_current_names[] = |
933e73fa RM |
112 | { |
113 | #define DEFINE_CATEGORY(category, category_name, items, a, b, c, d) \ | |
7a12c6bb | 114 | [category] = _nl_C_name, |
933e73fa RM |
115 | #include "categories.def" |
116 | #undef DEFINE_CATEGORY | |
7a12c6bb | 117 | [LC_ALL] = _nl_C_name /* For LC_ALL. */ |
933e73fa RM |
118 | }; |
119 | ||
933e73fa | 120 | |
a5113b14 | 121 | /* Lock for protecting global data. */ |
c4029823 | 122 | __libc_lock_define_initialized (, __libc_setlocale_lock) |
a5113b14 | 123 | |
933e73fa | 124 | |
7a12c6bb RM |
125 | /* Use this when we come along an error. */ |
126 | #define ERROR_RETURN \ | |
127 | do { \ | |
c4029823 | 128 | __set_errno (EINVAL); \ |
7a12c6bb RM |
129 | return NULL; \ |
130 | } while (0) | |
933e73fa | 131 | |
7a12c6bb RM |
132 | |
133 | static inline char * | |
134 | clever_copy (const char *string) | |
28f540f4 | 135 | { |
7a12c6bb RM |
136 | size_t len; |
137 | char *new; | |
138 | ||
139 | if (strcmp (string, "C") == 0 || strcmp (string, "POSIX") == 0) | |
140 | /* This return is dangerous because the returned string might be | |
141 | placed in read-only memory. But everything should be set up to | |
142 | handle this case. */ | |
143 | return (char *) _nl_C_name; | |
144 | ||
145 | len = strlen (string) + 1; | |
146 | new = (char *) malloc (len); | |
147 | return new != NULL ? memcpy (new, string, len) : NULL; | |
148 | } | |
933e73fa | 149 | |
933e73fa | 150 | |
7a12c6bb RM |
151 | /* Construct a new composite name. */ |
152 | static inline char * | |
c84142e8 | 153 | new_composite_name (int category, const char *newnames[LC_ALL]) |
7a12c6bb RM |
154 | { |
155 | size_t last_len; | |
156 | size_t cumlen = 0; | |
157 | int i; | |
158 | char *new, *p; | |
159 | int same = 1; | |
160 | ||
161 | for (i = 0; i < LC_ALL; ++i) | |
933e73fa | 162 | { |
c84142e8 UD |
163 | const char *name = (category == LC_ALL ? newnames[i] : |
164 | category == i ? newnames[0] : | |
165 | _nl_current_names[i]); | |
7a12c6bb RM |
166 | last_len = strlen (name); |
167 | cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1; | |
168 | if (i > 0 && same && strcmp (name, newnames[0]) != 0) | |
169 | same = 0; | |
933e73fa | 170 | } |
7a12c6bb RM |
171 | |
172 | if (same) | |
933e73fa | 173 | { |
7a12c6bb RM |
174 | /* All the categories use the same name. */ |
175 | if (strcmp (newnames[0], "C") == 0 || strcmp (newnames[0], "POSIX") == 0) | |
176 | return (char *) _nl_C_name; | |
177 | ||
178 | new = malloc (last_len + 1); | |
7a12c6bb | 179 | |
036cc82f | 180 | return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1); |
933e73fa | 181 | } |
7a12c6bb RM |
182 | |
183 | new = malloc (cumlen); | |
184 | if (new == NULL) | |
185 | return NULL; | |
186 | p = new; | |
187 | for (i = 0; i < LC_ALL; ++i) | |
933e73fa | 188 | { |
7a12c6bb | 189 | /* Add "CATEGORY=NAME;" to the string. */ |
c84142e8 UD |
190 | const char *name = (category == LC_ALL ? newnames[i] : |
191 | category == i ? newnames[0] : | |
192 | _nl_current_names[i]); | |
7a12c6bb RM |
193 | p = __stpcpy (p, _nl_category_names[i]); |
194 | *p++ = '='; | |
195 | p = __stpcpy (p, name); | |
196 | *p++ = ';'; | |
933e73fa | 197 | } |
7a12c6bb RM |
198 | p[-1] = '\0'; /* Clobber the last ';'. */ |
199 | return new; | |
200 | } | |
933e73fa | 201 | |
933e73fa | 202 | |
7a12c6bb RM |
203 | /* Put NAME in _nl_current_names. */ |
204 | static inline void | |
205 | setname (int category, const char *name) | |
206 | { | |
207 | if (_nl_current[category] == NULL | |
208 | && _nl_current_names[category] != _nl_C_name) | |
209 | free ((void *) _nl_current_names[category]); | |
210 | ||
211 | _nl_current_names[category] = name; | |
212 | } | |
213 | ||
214 | ||
215 | /* Put DATA in *_nl_current[CATEGORY]. */ | |
216 | static inline void | |
c84142e8 | 217 | setdata (int category, struct locale_data *data) |
7a12c6bb RM |
218 | { |
219 | if (_nl_current[category] != NULL) | |
933e73fa | 220 | { |
7a12c6bb RM |
221 | *_nl_current[category] = data; |
222 | if (_nl_category_postload[category]) | |
223 | (*_nl_category_postload[category]) (); | |
933e73fa | 224 | } |
7a12c6bb | 225 | } |
933e73fa | 226 | |
933e73fa | 227 | |
7a12c6bb RM |
228 | char * |
229 | setlocale (int category, const char *locale) | |
230 | { | |
7a12c6bb RM |
231 | char *locale_path; |
232 | size_t locale_path_len; | |
d68171ed | 233 | const char *locpath_var; |
7a12c6bb | 234 | char *composite; |
933e73fa | 235 | |
7a12c6bb RM |
236 | /* Sanity check for CATEGORY argument. */ |
237 | if (category < 0 || category > LC_ALL) | |
238 | ERROR_RETURN; | |
239 | ||
240 | /* Does user want name of current locale? */ | |
241 | if (locale == NULL) | |
242 | return (char *) _nl_current_names[category]; | |
243 | ||
244 | if (strcmp (locale, _nl_current_names[category]) == 0) | |
933e73fa | 245 | /* Changing to the same thing. */ |
7a12c6bb RM |
246 | return (char *) _nl_current_names[category]; |
247 | ||
248 | /* We perhaps really have to load some data. So we determine the | |
a5113b14 UD |
249 | path in which to look for the data now. The environment variable |
250 | `LOCPATH' must only be used when the binary has no SUID or SGID | |
7a12c6bb RM |
251 | bit set. */ |
252 | locale_path = NULL; | |
253 | locale_path_len = 0; | |
254 | ||
d68171ed UD |
255 | locpath_var = __secure_getenv ("LOCPATH"); |
256 | if (locpath_var != NULL && locpath_var[0] != '\0') | |
257 | if (__argz_create_sep (locpath_var, ':', | |
258 | &locale_path, &locale_path_len) != 0) | |
259 | return NULL; | |
933e73fa | 260 | |
e4cf5070 | 261 | if (__argz_add_sep (&locale_path, &locale_path_len, LOCALE_PATH, ':') != 0) |
7a12c6bb | 262 | return NULL; |
db2286f6 | 263 | |
933e73fa RM |
264 | if (category == LC_ALL) |
265 | { | |
7a12c6bb RM |
266 | /* The user wants to set all categories. The desired locales |
267 | for the individual categories can be selected by using a | |
268 | composite locale name. This is a semi-colon separated list | |
269 | of entries of the form `CATEGORY=VALUE'. */ | |
c84142e8 UD |
270 | const char *newnames[LC_ALL]; |
271 | struct locale_data *newdata[LC_ALL]; | |
933e73fa RM |
272 | |
273 | /* Set all name pointers to the argument name. */ | |
274 | for (category = 0; category < LC_ALL; ++category) | |
7a12c6bb | 275 | newnames[category] = (char *) locale; |
db2286f6 | 276 | |
7a12c6bb | 277 | if (strchr (locale, ';') != NULL) |
933e73fa | 278 | { |
7a12c6bb RM |
279 | /* This is a composite name. Make a copy and split it up. */ |
280 | char *np = strdupa (locale); | |
281 | char *cp; | |
282 | int cnt; | |
933e73fa | 283 | |
7a12c6bb | 284 | while ((cp = strchr (np, '=')) != NULL) |
933e73fa | 285 | { |
7a12c6bb | 286 | for (cnt = 0; cnt < LC_ALL; ++cnt) |
ce7a5ef4 | 287 | if ((size_t) (cp - np) == _nl_category_name_sizes[cnt] |
7a12c6bb | 288 | && memcmp (np, _nl_category_names[cnt], cp - np) == 0) |
933e73fa | 289 | break; |
7a12c6bb RM |
290 | |
291 | if (cnt == LC_ALL) | |
292 | /* Bogus category name. */ | |
293 | ERROR_RETURN; | |
294 | ||
295 | /* Found the category this clause sets. */ | |
296 | newnames[cnt] = ++cp; | |
297 | cp = strchr (cp, ';'); | |
298 | if (cp != NULL) | |
933e73fa | 299 | { |
7a12c6bb RM |
300 | /* Examine the next clause. */ |
301 | *cp = '\0'; | |
302 | np = cp + 1; | |
933e73fa | 303 | } |
7a12c6bb RM |
304 | else |
305 | /* This was the last clause. We are done. */ | |
306 | break; | |
933e73fa RM |
307 | } |
308 | ||
7a12c6bb RM |
309 | for (cnt = 0; cnt < LC_ALL; ++cnt) |
310 | if (newnames[cnt] == locale) | |
933e73fa | 311 | /* The composite name did not specify all categories. */ |
7a12c6bb | 312 | ERROR_RETURN; |
933e73fa | 313 | } |
19bc17a9 | 314 | |
a5113b14 | 315 | /* Protect global data. */ |
c4029823 | 316 | __libc_lock_lock (__libc_setlocale_lock); |
a5113b14 | 317 | |
933e73fa RM |
318 | /* Load the new data for each category. */ |
319 | while (category-- > 0) | |
1fb05e3d UD |
320 | { |
321 | newdata[category] = _nl_find_locale (locale_path, locale_path_len, | |
322 | category, | |
323 | &newnames[category]); | |
324 | ||
325 | if (newdata[category] == NULL) | |
326 | break; | |
327 | ||
328 | /* We must not simply free a global locale since we have no | |
329 | control over the usage. So we mark it as un-deletable. */ | |
330 | if (newdata[category]->usage_count != MAX_USAGE_COUNT) | |
c84142e8 | 331 | newdata[category]->usage_count = MAX_USAGE_COUNT; |
1fb05e3d | 332 | } |
933e73fa | 333 | |
7a12c6bb | 334 | /* Create new composite name. */ |
845dcb57 UD |
335 | if (category >= 0 |
336 | || (composite = new_composite_name (LC_ALL, newnames)) == NULL) | |
337 | /* Loading this part of the locale failed. Abort the | |
338 | composite load. */ | |
339 | composite = NULL; | |
a5113b14 | 340 | else |
933e73fa | 341 | { |
a5113b14 UD |
342 | /* Now we have loaded all the new data. Put it in place. */ |
343 | for (category = 0; category < LC_ALL; ++category) | |
344 | { | |
345 | setdata (category, newdata[category]); | |
346 | setname (category, newnames[category]); | |
347 | } | |
348 | setname (LC_ALL, composite); | |
933e73fa | 349 | } |
a5113b14 UD |
350 | |
351 | /* Critical section left. */ | |
c4029823 | 352 | __libc_lock_unlock (__libc_setlocale_lock); |
933e73fa RM |
353 | |
354 | return composite; | |
355 | } | |
356 | else | |
357 | { | |
c84142e8 UD |
358 | struct locale_data *newdata = NULL; |
359 | const char *newname = locale; | |
7a12c6bb | 360 | |
a5113b14 | 361 | /* Protect global data. */ |
c4029823 | 362 | __libc_lock_lock (__libc_setlocale_lock); |
a5113b14 | 363 | |
7a12c6bb | 364 | if (_nl_current[category] != NULL) |
933e73fa | 365 | { |
7a12c6bb | 366 | /* Only actually load the data if anything will use it. */ |
7a12c6bb | 367 | newdata = _nl_find_locale (locale_path, locale_path_len, category, |
c84142e8 | 368 | &newname); |
7a12c6bb | 369 | if (newdata == NULL) |
a5113b14 | 370 | goto abort_single; |
c84142e8 UD |
371 | |
372 | /* We must not simply free a global locale since we have no | |
373 | control over the usage. So we mark it as un-deletable. */ | |
f166d865 UD |
374 | if (newdata->usage_count != MAX_USAGE_COUNT) |
375 | newdata->usage_count = MAX_USAGE_COUNT; | |
933e73fa RM |
376 | } |
377 | ||
7a12c6bb | 378 | /* Create new composite name. */ |
933e73fa | 379 | composite = new_composite_name (category, &newname); |
7a12c6bb | 380 | if (composite == NULL) |
933e73fa | 381 | { |
845dcb57 | 382 | /* Say that we don't have any data loaded. */ |
a5113b14 UD |
383 | abort_single: |
384 | newname = NULL; | |
933e73fa | 385 | } |
a5113b14 UD |
386 | else |
387 | { | |
388 | if (_nl_current[category] != NULL) | |
389 | setdata (category, newdata); | |
28f540f4 | 390 | |
a5113b14 UD |
391 | setname (category, newname); |
392 | setname (LC_ALL, composite); | |
393 | } | |
28f540f4 | 394 | |
a5113b14 | 395 | /* Critical section left. */ |
c4029823 | 396 | __libc_lock_unlock (__libc_setlocale_lock); |
28f540f4 | 397 | |
c84142e8 | 398 | return (char *) newname; |
933e73fa | 399 | } |
28f540f4 | 400 | } |