1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <alloca.h>
21: #include <argz.h>
22: #include <errno.h>
23: #include <bits/libc-lock.h>
24: #include <locale.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
28:
29: #include "localeinfo.h"
30:
31: #ifdef NL_CURRENT_INDIRECT
32:
33:
34:
35:
36:
37:
38:
39: # define DEFINE_CATEGORY(category, category_name, items, a) \
40: extern char _nl_current_##category##_used; \
41: weak_extern (_nl_current_##category##_used) \
42: weak_extern (_nl_current_##category)
43: # include "categories.def"
44: # undef DEFINE_CATEGORY
45:
46:
47:
48:
49: static char *const _nl_current_used[] =
50: {
51: # define DEFINE_CATEGORY(category, category_name, items, a) \
52: [category] = &_nl_current_##category##_used,
53: # include "categories.def"
54: # undef DEFINE_CATEGORY
55: };
56:
57: # define CATEGORY_USED(category) (_nl_current_used[category] != 0)
58:
59: #else
60:
61:
62:
63:
64: # define CATEGORY_USED(category) (1)
65:
66: #endif
67:
68:
69:
70: const union catnamestr_t _nl_category_names attribute_hidden =
71: {
72: {
73: #define DEFINE_CATEGORY(category, category_name, items, a) \
74: category_name,
75: #include "categories.def"
76: #undef DEFINE_CATEGORY
77: }
78: };
79:
80: const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
81: {
82: #define DEFINE_CATEGORY(category, category_name, items, a) \
83: [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
84: #include "categories.def"
85: #undef DEFINE_CATEGORY
86: };
87:
88:
89: const uint8_t _nl_category_name_sizes[] attribute_hidden =
90: {
91: #define DEFINE_CATEGORY(category, category_name, items, a) \
92: [category] = sizeof (category_name) - 1,
93: #include "categories.def"
94: #undef DEFINE_CATEGORY
95: [LC_ALL] = sizeof ("LC_ALL") - 1
96: };
97:
98:
99: #ifdef NL_CURRENT_INDIRECT
100: # define WEAK_POSTLOAD(postload) weak_extern (postload)
101: #else
102: # define WEAK_POSTLOAD(postload)
103: #endif
104:
105:
106: #undef NO_POSTLOAD
107: #define NO_POSTLOAD _nl_postload_ctype
108: #define DEFINE_CATEGORY(category, category_name, items, postload) \
109: extern void postload (void); WEAK_POSTLOAD (postload)
110: #include "categories.def"
111: #undef DEFINE_CATEGORY
112: #undef NO_POSTLOAD
113:
114:
115:
116: static void (*const _nl_category_postload[]) (void) =
117: {
118: #define DEFINE_CATEGORY(category, category_name, items, postload) \
119: [category] = postload,
120: #include "categories.def"
121: #undef DEFINE_CATEGORY
122: };
123:
124:
125:
126: __libc_lock_define_initialized (, __libc_setlocale_lock attribute_hidden)
127:
128:
129: extern int _nl_msg_cat_cntr;
130:
131:
132:
133: #define ERROR_RETURN \
134: do { \
135: __set_errno (EINVAL); \
136: return NULL; \
137: } while (0)
138:
139:
140:
141: static char *
142: new_composite_name (int category, const char *newnames[__LC_LAST])
143: {
144: size_t last_len = 0;
145: size_t cumlen = 0;
146: int i;
147: char *new, *p;
148: int same = 1;
149:
150: for (i = 0; i < __LC_LAST; ++i)
151: if (i != LC_ALL)
152: {
153: const char *name = (category == LC_ALL ? newnames[i] :
154: category == i ? newnames[0] :
155: _nl_global_locale.__names[i]);
156: last_len = strlen (name);
157: cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
158: if (i > 0 && same && strcmp (name, newnames[0]) != 0)
159: same = 0;
160: }
161:
162: if (same)
163: {
164:
165: if (strcmp (newnames[0], _nl_C_name) == 0
166: || strcmp (newnames[0], _nl_POSIX_name) == 0)
167: return (char *) _nl_C_name;
168:
169: new = malloc (last_len + 1);
170:
171: return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1);
172: }
173:
174: new = malloc (cumlen);
175: if (new == NULL)
176: return NULL;
177: p = new;
178: for (i = 0; i < __LC_LAST; ++i)
179: if (i != LC_ALL)
180: {
181:
182: const char *name = (category == LC_ALL ? newnames[i] :
183: category == i ? newnames[0] :
184: _nl_global_locale.__names[i]);
185: p = __stpcpy (p, _nl_category_names.str + _nl_category_name_idxs[i]);
186: *p++ = '=';
187: p = __stpcpy (p, name);
188: *p++ = ';';
189: }
190: p[-1] = '\0';
191: return new;
192: }
193:
194:
195:
196: static inline void
197: setname (int category, const char *name)
198: {
199: if (_nl_global_locale.__names[category] == name)
200: return;
201:
202: if (_nl_global_locale.__names[category] != _nl_C_name)
203: free ((char *) _nl_global_locale.__names[category]);
204:
205: _nl_global_locale.__names[category] = name;
206: }
207:
208:
209: static inline void
210: setdata (int category, struct locale_data *data)
211: {
212: if (CATEGORY_USED (category))
213: {
214: _nl_global_locale.__locales[category] = data;
215: if (_nl_category_postload[category])
216: (*_nl_category_postload[category]) ();
217: }
218: }
219:
220: char *
221: setlocale (int category, const char *locale)
222: {
223: char *locale_path;
224: size_t locale_path_len;
225: const char *locpath_var;
226: char *composite;
227:
228:
229: if (__builtin_expect (category, 0) < 0
230: || __builtin_expect (category, 0) >= __LC_LAST)
231: ERROR_RETURN;
232:
233:
234: if (locale == NULL)
235: return (char *) _nl_global_locale.__names[category];
236:
237: if (strcmp (locale, _nl_global_locale.__names[category]) == 0)
238:
239: return (char *) _nl_global_locale.__names[category];
240:
241:
242:
243:
244:
245:
246: locale_path = NULL;
247: locale_path_len = 0;
248:
249: locpath_var = getenv ("LOCPATH");
250: if (locpath_var != NULL && locpath_var[0] != '\0')
251: {
252: if (__argz_create_sep (locpath_var, ':',
253: &locale_path, &locale_path_len) != 0)
254: return NULL;
255:
256: if (__argz_add_sep (&locale_path, &locale_path_len,
257: _nl_default_locale_path, ':') != 0)
258: return NULL;
259: }
260:
261: if (category == LC_ALL)
262: {
263:
264:
265:
266:
267: const char *newnames[__LC_LAST];
268: struct locale_data *newdata[__LC_LAST];
269:
270:
271: for (category = 0; category < __LC_LAST; ++category)
272: if (category != LC_ALL)
273: newnames[category] = (char *) locale;
274:
275: if (__builtin_expect (strchr (locale, ';') != NULL, 0))
276: {
277:
278: char *np = strdupa (locale);
279: char *cp;
280: int cnt;
281:
282: while ((cp = strchr (np, '=')) != NULL)
283: {
284: for (cnt = 0; cnt < __LC_LAST; ++cnt)
285: if (cnt != LC_ALL
286: && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
287: && (memcmp (np, (_nl_category_names.str
288: + _nl_category_name_idxs[cnt]), cp - np)
289: == 0))
290: break;
291:
292: if (cnt == __LC_LAST)
293:
294: ERROR_RETURN;
295:
296:
297: newnames[cnt] = ++cp;
298: cp = strchr (cp, ';');
299: if (cp != NULL)
300: {
301:
302: *cp = '\0';
303: np = cp + 1;
304: }
305: else
306:
307: break;
308: }
309:
310: for (cnt = 0; cnt < __LC_LAST; ++cnt)
311: if (cnt != LC_ALL && newnames[cnt] == locale)
312:
313: ERROR_RETURN;
314: }
315:
316:
317: __libc_lock_lock (__libc_setlocale_lock);
318:
319:
320: while (category-- > 0)
321: if (category != LC_ALL)
322: {
323: newdata[category] = _nl_find_locale (locale_path, locale_path_len,
324: category,
325: &newnames[category]);
326:
327: if (newdata[category] == NULL)
328: {
329: #ifdef NL_CURRENT_INDIRECT
330: if (newnames[category] == _nl_C_name)
331:
332: continue;
333: #endif
334: break;
335: }
336:
337:
338:
339:
340:
341: if (newdata[category]->usage_count != UNDELETABLE)
342: newdata[category]->usage_count = UNDELETABLE;
343:
344:
345: if (newnames[category] != _nl_C_name)
346: {
347: if (strcmp (newnames[category],
348: _nl_global_locale.__names[category]) == 0)
349: newnames[category] = _nl_global_locale.__names[category];
350: else
351: {
352: newnames[category] = __strdup (newnames[category]);
353: if (newnames[category] == NULL)
354: break;
355: }
356: }
357: }
358:
359:
360: composite = (category >= 0
361: ? NULL : new_composite_name (LC_ALL, newnames));
362: if (composite != NULL)
363: {
364:
365: for (category = 0; category < __LC_LAST; ++category)
366: if (category != LC_ALL)
367: {
368: setdata (category, newdata[category]);
369: setname (category, newnames[category]);
370: }
371: setname (LC_ALL, composite);
372:
373:
374:
375: ++_nl_msg_cat_cntr;
376: }
377: else
378: for (++category; category < __LC_LAST; ++category)
379: if (category != LC_ALL && newnames[category] != _nl_C_name
380: && newnames[category] != _nl_global_locale.__names[category])
381: free ((char *) newnames[category]);
382:
383:
384: __libc_lock_unlock (__libc_setlocale_lock);
385:
386:
387: free (locale_path);
388:
389: return composite;
390: }
391: else
392: {
393: struct locale_data *newdata = NULL;
394: const char *newname[1] = { locale };
395:
396:
397: __libc_lock_lock (__libc_setlocale_lock);
398:
399: if (CATEGORY_USED (category))
400: {
401:
402: newdata = _nl_find_locale (locale_path, locale_path_len, category,
403: &newname[0]);
404: if (newdata == NULL)
405: goto abort_single;
406:
407:
408:
409:
410:
411:
412: if (newdata->usage_count != UNDELETABLE)
413: newdata->usage_count = UNDELETABLE;
414: }
415:
416:
417: if (newname[0] != _nl_C_name)
418: {
419: newname[0] = __strdup (newname[0]);
420: if (newname[0] == NULL)
421: goto abort_single;
422: }
423:
424:
425: composite = new_composite_name (category, newname);
426: if (composite == NULL)
427: {
428: if (newname[0] != _nl_C_name)
429: free ((char *) newname[0]);
430:
431:
432: abort_single:
433: newname[0] = NULL;
434: }
435: else
436: {
437: if (CATEGORY_USED (category))
438: setdata (category, newdata);
439:
440: setname (category, newname[0]);
441: setname (LC_ALL, composite);
442:
443:
444:
445: ++_nl_msg_cat_cntr;
446: }
447:
448:
449: __libc_lock_unlock (__libc_setlocale_lock);
450:
451:
452: free (locale_path);
453:
454: return (char *) newname[0];
455: }
456: }
457: libc_hidden_def (setlocale)
458:
459: static void __libc_freeres_fn_section
460: free_category (int category,
461: struct locale_data *here, struct locale_data *c_data)
462: {
463: struct loaded_l10nfile *runp = _nl_locale_file_list[category];
464:
465:
466: if (here != c_data)
467: {
468:
469:
470: setdata (category, c_data);
471: setname (category, _nl_C_name);
472: }
473:
474: while (runp != NULL)
475: {
476: struct loaded_l10nfile *curr = runp;
477: struct locale_data *data = (struct locale_data *) runp->data;
478:
479: if (data != NULL && data != c_data)
480: _nl_unload_locale (data);
481: runp = runp->next;
482: free ((char *) curr->filename);
483: free (curr);
484: }
485: }
486:
487:
488:
489: void __libc_freeres_fn_section
490: _nl_locale_subfreeres (void)
491: {
492: #ifdef NL_CURRENT_INDIRECT
493:
494:
495: # define DEFINE_CATEGORY(category, category_name, items, a) \
496: if (CATEGORY_USED (category)) \
497: { \
498: extern struct locale_data _nl_C_##category; \
499: weak_extern (_nl_C_##category) \
500: free_category (category, *_nl_current_##category, &_nl_C_##category); \
501: }
502: # include "categories.def"
503: # undef DEFINE_CATEGORY
504: #else
505: int category;
506:
507: for (category = 0; category < __LC_LAST; ++category)
508: if (category != LC_ALL)
509: free_category (category, _NL_CURRENT_DATA (category),
510: _nl_C_locobj.__locales[category]);
511: #endif
512:
513: setname (LC_ALL, _nl_C_name);
514:
515:
516:
517:
518: _nl_archive_subfreeres ();
519: }