]>
Commit | Line | Data |
---|---|---|
581c785b | 1 | /* Copyright (C) 1991-2022 Free Software Foundation, Inc. |
c84142e8 | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
c84142e8 | 4 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the 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 | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
28f540f4 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 15 | License along with the GNU C Library; if not, see |
5a82c748 | 16 | <https://www.gnu.org/licenses/>. */ |
28f540f4 | 17 | |
7a12c6bb RM |
18 | #include <alloca.h> |
19 | #include <argz.h> | |
28f540f4 | 20 | #include <errno.h> |
ec999b8e | 21 | #include <libc-lock.h> |
933e73fa | 22 | #include <locale.h> |
7a12c6bb RM |
23 | #include <stdlib.h> |
24 | #include <string.h> | |
25 | #include <unistd.h> | |
26 | ||
933e73fa RM |
27 | #include "localeinfo.h" |
28 | ||
1a0d874e RM |
29 | #ifdef NL_CURRENT_INDIRECT |
30 | ||
31 | /* For each category declare a special external symbol | |
32 | _nl_current_CATEGORY_used with a weak reference. | |
33 | This symbol will is defined in lc-CATEGORY.c and will be linked in | |
34 | if anything uses _nl_current_CATEGORY (also defined in that module). | |
35 | Also use a weak reference for the _nl_current_CATEGORY thread variable. */ | |
36 | ||
37 | # define DEFINE_CATEGORY(category, category_name, items, a) \ | |
38 | extern char _nl_current_##category##_used; \ | |
39 | weak_extern (_nl_current_##category##_used) \ | |
40 | weak_extern (_nl_current_##category) | |
41 | # include "categories.def" | |
42 | # undef DEFINE_CATEGORY | |
43 | ||
44 | /* Now define a table of flags based on those special weak symbols' values. | |
45 | _nl_current_used[CATEGORY] will be zero if _nl_current_CATEGORY is not | |
46 | linked in. */ | |
47 | static char *const _nl_current_used[] = | |
036cc82f | 48 | { |
1a0d874e RM |
49 | # define DEFINE_CATEGORY(category, category_name, items, a) \ |
50 | [category] = &_nl_current_##category##_used, | |
51 | # include "categories.def" | |
52 | # undef DEFINE_CATEGORY | |
036cc82f | 53 | }; |
933e73fa | 54 | |
1a0d874e | 55 | # define CATEGORY_USED(category) (_nl_current_used[category] != 0) |
30c14c31 RM |
56 | |
57 | #else | |
58 | ||
59 | /* The shared library always loads all the categories, | |
60 | and the current global settings are kept in _nl_global_locale. */ | |
61 | ||
30c14c31 RM |
62 | # define CATEGORY_USED(category) (1) |
63 | ||
64 | #endif | |
65 | ||
933e73fa | 66 | |
9446614c | 67 | /* Define an array of category names (also the environment variable names). */ |
de18a706 | 68 | const struct catnamestr_t _nl_category_names attribute_hidden = |
933e73fa | 69 | { |
4b10dd6c | 70 | #define DEFINE_CATEGORY(category, category_name, items, a) \ |
de18a706 | 71 | category_name, |
933e73fa | 72 | #include "categories.def" |
9446614c | 73 | #undef DEFINE_CATEGORY |
0ecb606c | 74 | }; |
9446614c UD |
75 | |
76 | const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = | |
77 | { | |
78 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | |
de18a706 | 79 | [category] = offsetof (struct catnamestr_t, CATNAMEMF (__LINE__)), |
9446614c UD |
80 | #include "categories.def" |
81 | #undef DEFINE_CATEGORY | |
82 | }; | |
83 | ||
933e73fa | 84 | /* An array of their lengths, for convenience. */ |
9446614c | 85 | const uint8_t _nl_category_name_sizes[] attribute_hidden = |
933e73fa | 86 | { |
4b10dd6c | 87 | #define DEFINE_CATEGORY(category, category_name, items, a) \ |
933e73fa RM |
88 | [category] = sizeof (category_name) - 1, |
89 | #include "categories.def" | |
90 | #undef DEFINE_CATEGORY | |
7a12c6bb | 91 | [LC_ALL] = sizeof ("LC_ALL") - 1 |
933e73fa | 92 | }; |
28f540f4 RM |
93 | |
94 | ||
0ba454fc RM |
95 | #ifdef NL_CURRENT_INDIRECT |
96 | # define WEAK_POSTLOAD(postload) weak_extern (postload) | |
97 | #else | |
98 | # define WEAK_POSTLOAD(postload) /* Need strong refs in static linking. */ | |
99 | #endif | |
100 | ||
933e73fa RM |
101 | /* Declare the postload functions used below. */ |
102 | #undef NO_POSTLOAD | |
103 | #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist. */ | |
4b10dd6c | 104 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ |
0ba454fc | 105 | extern void postload (void); WEAK_POSTLOAD (postload) |
933e73fa RM |
106 | #include "categories.def" |
107 | #undef DEFINE_CATEGORY | |
108 | #undef NO_POSTLOAD | |
109 | ||
110 | /* Define an array indexed by category of postload functions to call after | |
111 | loading and installing that category's data. */ | |
a5113b14 | 112 | static void (*const _nl_category_postload[]) (void) = |
933e73fa | 113 | { |
4b10dd6c | 114 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ |
933e73fa RM |
115 | [category] = postload, |
116 | #include "categories.def" | |
117 | #undef DEFINE_CATEGORY | |
118 | }; | |
119 | ||
120 | ||
a5113b14 | 121 | /* Lock for protecting global data. */ |
9a69db29 | 122 | __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden) |
a5113b14 | 123 | |
111bb972 UD |
124 | /* Defined in loadmsgcat.c. */ |
125 | extern int _nl_msg_cat_cntr; | |
126 | ||
933e73fa | 127 | |
7a12c6bb RM |
128 | /* Use this when we come along an error. */ |
129 | #define ERROR_RETURN \ | |
130 | do { \ | |
c4029823 | 131 | __set_errno (EINVAL); \ |
7a12c6bb RM |
132 | return NULL; \ |
133 | } while (0) | |
933e73fa | 134 | |
7a12c6bb | 135 | |
7a12c6bb | 136 | /* Construct a new composite name. */ |
dd9423a6 | 137 | static char * |
5c3b0374 | 138 | new_composite_name (int category, const char **newnames) |
7a12c6bb | 139 | { |
e918a7fe | 140 | size_t last_len = 0; |
7a12c6bb RM |
141 | size_t cumlen = 0; |
142 | int i; | |
143 | char *new, *p; | |
144 | int same = 1; | |
145 | ||
4b10dd6c UD |
146 | for (i = 0; i < __LC_LAST; ++i) |
147 | if (i != LC_ALL) | |
148 | { | |
a04549c1 JM |
149 | const char *name = (category == LC_ALL ? newnames[i] |
150 | : category == i ? newnames[0] | |
151 | : _nl_global_locale.__names[i]); | |
4b10dd6c UD |
152 | last_len = strlen (name); |
153 | cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1; | |
cc9e536d | 154 | if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0) |
4b10dd6c UD |
155 | same = 0; |
156 | } | |
7a12c6bb RM |
157 | |
158 | if (same) | |
933e73fa | 159 | { |
7a12c6bb | 160 | /* All the categories use the same name. */ |
72c74375 UD |
161 | if (strcmp (newnames[0], _nl_C_name) == 0 |
162 | || strcmp (newnames[0], _nl_POSIX_name) == 0) | |
7a12c6bb RM |
163 | return (char *) _nl_C_name; |
164 | ||
165 | new = malloc (last_len + 1); | |
7a12c6bb | 166 | |
036cc82f | 167 | return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1); |
933e73fa | 168 | } |
7a12c6bb RM |
169 | |
170 | new = malloc (cumlen); | |
171 | if (new == NULL) | |
172 | return NULL; | |
173 | p = new; | |
4b10dd6c UD |
174 | for (i = 0; i < __LC_LAST; ++i) |
175 | if (i != LC_ALL) | |
176 | { | |
177 | /* Add "CATEGORY=NAME;" to the string. */ | |
a04549c1 JM |
178 | const char *name = (category == LC_ALL ? newnames[i] |
179 | : category == i ? newnames[0] | |
180 | : _nl_global_locale.__names[i]); | |
de18a706 | 181 | p = __stpcpy (p, _nl_category_names_get (i)); |
4b10dd6c UD |
182 | *p++ = '='; |
183 | p = __stpcpy (p, name); | |
184 | *p++ = ';'; | |
185 | } | |
7a12c6bb RM |
186 | p[-1] = '\0'; /* Clobber the last ';'. */ |
187 | return new; | |
188 | } | |
933e73fa | 189 | |
933e73fa | 190 | |
1ce8aaae | 191 | /* Put NAME in _nl_global_locale.__names. */ |
2e79213a | 192 | static void |
7a12c6bb RM |
193 | setname (int category, const char *name) |
194 | { | |
1ce8aaae | 195 | if (_nl_global_locale.__names[category] == name) |
762a2918 UD |
196 | return; |
197 | ||
1ce8aaae RM |
198 | if (_nl_global_locale.__names[category] != _nl_C_name) |
199 | free ((char *) _nl_global_locale.__names[category]); | |
7a12c6bb | 200 | |
1ce8aaae | 201 | _nl_global_locale.__names[category] = name; |
7a12c6bb RM |
202 | } |
203 | ||
7a12c6bb | 204 | /* Put DATA in *_nl_current[CATEGORY]. */ |
f1d70dad | 205 | static void |
f095bb72 | 206 | setdata (int category, struct __locale_data *data) |
7a12c6bb | 207 | { |
30c14c31 | 208 | if (CATEGORY_USED (category)) |
933e73fa | 209 | { |
30c14c31 | 210 | _nl_global_locale.__locales[category] = data; |
7a12c6bb RM |
211 | if (_nl_category_postload[category]) |
212 | (*_nl_category_postload[category]) (); | |
933e73fa | 213 | } |
7a12c6bb | 214 | } |
933e73fa | 215 | |
7a12c6bb RM |
216 | char * |
217 | setlocale (int category, const char *locale) | |
218 | { | |
7a12c6bb RM |
219 | char *locale_path; |
220 | size_t locale_path_len; | |
d68171ed | 221 | const char *locpath_var; |
7a12c6bb | 222 | char *composite; |
933e73fa | 223 | |
7a12c6bb | 224 | /* Sanity check for CATEGORY argument. */ |
323fb88d UD |
225 | if (__builtin_expect (category, 0) < 0 |
226 | || __builtin_expect (category, 0) >= __LC_LAST) | |
7a12c6bb RM |
227 | ERROR_RETURN; |
228 | ||
229 | /* Does user want name of current locale? */ | |
230 | if (locale == NULL) | |
1ce8aaae | 231 | return (char *) _nl_global_locale.__names[category]; |
7a12c6bb | 232 | |
9f558b80 UD |
233 | /* Protect global data. */ |
234 | __libc_rwlock_wrlock (__libc_setlocale_lock); | |
235 | ||
1ce8aaae | 236 | if (strcmp (locale, _nl_global_locale.__names[category]) == 0) |
9f558b80 UD |
237 | { |
238 | /* Changing to the same thing. */ | |
239 | __libc_rwlock_unlock (__libc_setlocale_lock); | |
240 | ||
241 | return (char *) _nl_global_locale.__names[category]; | |
242 | } | |
7a12c6bb RM |
243 | |
244 | /* We perhaps really have to load some data. So we determine the | |
a5113b14 UD |
245 | path in which to look for the data now. The environment variable |
246 | `LOCPATH' must only be used when the binary has no SUID or SGID | |
cb09a2cd RM |
247 | bit set. If using the default path, we tell _nl_find_locale |
248 | by passing null and it can check the canonical locale archive. */ | |
7a12c6bb RM |
249 | locale_path = NULL; |
250 | locale_path_len = 0; | |
251 | ||
74955460 | 252 | locpath_var = getenv ("LOCPATH"); |
d68171ed | 253 | if (locpath_var != NULL && locpath_var[0] != '\0') |
cb09a2cd RM |
254 | { |
255 | if (__argz_create_sep (locpath_var, ':', | |
9f558b80 UD |
256 | &locale_path, &locale_path_len) != 0 |
257 | || __argz_add_sep (&locale_path, &locale_path_len, | |
258 | _nl_default_locale_path, ':') != 0) | |
259 | { | |
260 | __libc_rwlock_unlock (__libc_setlocale_lock); | |
261 | return NULL; | |
262 | } | |
cb09a2cd | 263 | } |
db2286f6 | 264 | |
933e73fa RM |
265 | if (category == LC_ALL) |
266 | { | |
7a12c6bb RM |
267 | /* The user wants to set all categories. The desired locales |
268 | for the individual categories can be selected by using a | |
269 | composite locale name. This is a semi-colon separated list | |
270 | of entries of the form `CATEGORY=VALUE'. */ | |
4b10dd6c | 271 | const char *newnames[__LC_LAST]; |
f095bb72 | 272 | struct __locale_data *newdata[__LC_LAST]; |
d1836456 FW |
273 | /* Copy of the locale argument, for in-place splitting. */ |
274 | char *locale_copy = NULL; | |
933e73fa RM |
275 | |
276 | /* Set all name pointers to the argument name. */ | |
4b10dd6c UD |
277 | for (category = 0; category < __LC_LAST; ++category) |
278 | if (category != LC_ALL) | |
279 | newnames[category] = (char *) locale; | |
db2286f6 | 280 | |
a1ffb40e | 281 | if (__glibc_unlikely (strchr (locale, ';') != NULL)) |
933e73fa | 282 | { |
7a12c6bb | 283 | /* This is a composite name. Make a copy and split it up. */ |
ae65d4f3 | 284 | locale_copy = __strdup (locale); |
d1836456 FW |
285 | if (__glibc_unlikely (locale_copy == NULL)) |
286 | { | |
287 | __libc_rwlock_unlock (__libc_setlocale_lock); | |
288 | return NULL; | |
289 | } | |
290 | char *np = locale_copy; | |
7a12c6bb RM |
291 | char *cp; |
292 | int cnt; | |
933e73fa | 293 | |
7a12c6bb | 294 | while ((cp = strchr (np, '=')) != NULL) |
933e73fa | 295 | { |
4b10dd6c UD |
296 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
297 | if (cnt != LC_ALL | |
298 | && (size_t) (cp - np) == _nl_category_name_sizes[cnt] | |
de18a706 | 299 | && (memcmp (np, (_nl_category_names_get (cnt)), cp - np) |
9446614c | 300 | == 0)) |
933e73fa | 301 | break; |
7a12c6bb | 302 | |
4b10dd6c | 303 | if (cnt == __LC_LAST) |
9f558b80 UD |
304 | { |
305 | error_return: | |
306 | __libc_rwlock_unlock (__libc_setlocale_lock); | |
d1836456 | 307 | free (locale_copy); |
9f558b80 UD |
308 | |
309 | /* Bogus category name. */ | |
310 | ERROR_RETURN; | |
311 | } | |
7a12c6bb RM |
312 | |
313 | /* Found the category this clause sets. */ | |
314 | newnames[cnt] = ++cp; | |
315 | cp = strchr (cp, ';'); | |
316 | if (cp != NULL) | |
933e73fa | 317 | { |
7a12c6bb RM |
318 | /* Examine the next clause. */ |
319 | *cp = '\0'; | |
320 | np = cp + 1; | |
933e73fa | 321 | } |
7a12c6bb RM |
322 | else |
323 | /* This was the last clause. We are done. */ | |
324 | break; | |
933e73fa RM |
325 | } |
326 | ||
4b10dd6c UD |
327 | for (cnt = 0; cnt < __LC_LAST; ++cnt) |
328 | if (cnt != LC_ALL && newnames[cnt] == locale) | |
933e73fa | 329 | /* The composite name did not specify all categories. */ |
9f558b80 | 330 | goto error_return; |
933e73fa | 331 | } |
19bc17a9 | 332 | |
933e73fa RM |
333 | /* Load the new data for each category. */ |
334 | while (category-- > 0) | |
ef5d6645 UD |
335 | if (category != LC_ALL) |
336 | { | |
ef5d6645 UD |
337 | newdata[category] = _nl_find_locale (locale_path, locale_path_len, |
338 | category, | |
339 | &newnames[category]); | |
1fb05e3d | 340 | |
ef5d6645 | 341 | if (newdata[category] == NULL) |
9a411bf5 RM |
342 | { |
343 | #ifdef NL_CURRENT_INDIRECT | |
344 | if (newnames[category] == _nl_C_name) | |
345 | /* Null because it's the weak value of _nl_C_LC_FOO. */ | |
346 | continue; | |
347 | #endif | |
348 | break; | |
349 | } | |
1fb05e3d | 350 | |
a31f867a UD |
351 | /* We must not simply free a global locale since we have |
352 | no control over the usage. So we mark it as | |
353 | un-deletable. And yes, the 'if' is needed, the data | |
354 | might be in read-only memory. */ | |
ef5d6645 UD |
355 | if (newdata[category]->usage_count != UNDELETABLE) |
356 | newdata[category]->usage_count = UNDELETABLE; | |
411adb10 UD |
357 | |
358 | /* Make a copy of locale name. */ | |
359 | if (newnames[category] != _nl_C_name) | |
360 | { | |
a31f867a UD |
361 | if (strcmp (newnames[category], |
362 | _nl_global_locale.__names[category]) == 0) | |
363 | newnames[category] = _nl_global_locale.__names[category]; | |
364 | else | |
365 | { | |
366 | newnames[category] = __strdup (newnames[category]); | |
367 | if (newnames[category] == NULL) | |
368 | break; | |
369 | } | |
411adb10 | 370 | } |
ef5d6645 | 371 | } |
933e73fa | 372 | |
7a12c6bb | 373 | /* Create new composite name. */ |
d4c5cf80 UD |
374 | composite = (category >= 0 |
375 | ? NULL : new_composite_name (LC_ALL, newnames)); | |
376 | if (composite != NULL) | |
933e73fa | 377 | { |
a5113b14 | 378 | /* Now we have loaded all the new data. Put it in place. */ |
4b10dd6c UD |
379 | for (category = 0; category < __LC_LAST; ++category) |
380 | if (category != LC_ALL) | |
381 | { | |
382 | setdata (category, newdata[category]); | |
383 | setname (category, newnames[category]); | |
384 | } | |
a5113b14 | 385 | setname (LC_ALL, composite); |
111bb972 UD |
386 | |
387 | /* We successfully loaded a new locale. Let the message catalog | |
388 | functions know about this. */ | |
389 | ++_nl_msg_cat_cntr; | |
933e73fa | 390 | } |
411adb10 UD |
391 | else |
392 | for (++category; category < __LC_LAST; ++category) | |
a31f867a UD |
393 | if (category != LC_ALL && newnames[category] != _nl_C_name |
394 | && newnames[category] != _nl_global_locale.__names[category]) | |
411adb10 | 395 | free ((char *) newnames[category]); |
a5113b14 UD |
396 | |
397 | /* Critical section left. */ | |
9a69db29 | 398 | __libc_rwlock_unlock (__libc_setlocale_lock); |
933e73fa | 399 | |
d1836456 | 400 | /* Free the resources. */ |
714a562f | 401 | free (locale_path); |
d1836456 | 402 | free (locale_copy); |
714a562f | 403 | |
933e73fa RM |
404 | return composite; |
405 | } | |
406 | else | |
407 | { | |
f095bb72 | 408 | struct __locale_data *newdata = NULL; |
650425ce | 409 | const char *newname[1] = { locale }; |
7a12c6bb | 410 | |
30c14c31 | 411 | if (CATEGORY_USED (category)) |
933e73fa | 412 | { |
7a12c6bb | 413 | /* Only actually load the data if anything will use it. */ |
7a12c6bb | 414 | newdata = _nl_find_locale (locale_path, locale_path_len, category, |
650425ce | 415 | &newname[0]); |
7a12c6bb | 416 | if (newdata == NULL) |
a5113b14 | 417 | goto abort_single; |
c84142e8 UD |
418 | |
419 | /* We must not simply free a global locale since we have no | |
a2b08ee5 UD |
420 | control over the usage. So we mark it as un-deletable. |
421 | ||
9cd83302 | 422 | Note: do not remove the `if', it's necessary to cope with |
a2b08ee5 | 423 | the builtin locale data. */ |
9756dfe1 UD |
424 | if (newdata->usage_count != UNDELETABLE) |
425 | newdata->usage_count = UNDELETABLE; | |
933e73fa RM |
426 | } |
427 | ||
411adb10 UD |
428 | /* Make a copy of locale name. */ |
429 | if (newname[0] != _nl_C_name) | |
430 | { | |
1ce8aaae | 431 | newname[0] = __strdup (newname[0]); |
411adb10 UD |
432 | if (newname[0] == NULL) |
433 | goto abort_single; | |
434 | } | |
435 | ||
7a12c6bb | 436 | /* Create new composite name. */ |
650425ce | 437 | composite = new_composite_name (category, newname); |
7a12c6bb | 438 | if (composite == NULL) |
933e73fa | 439 | { |
411adb10 UD |
440 | if (newname[0] != _nl_C_name) |
441 | free ((char *) newname[0]); | |
442 | ||
845dcb57 | 443 | /* Say that we don't have any data loaded. */ |
a5113b14 | 444 | abort_single: |
650425ce | 445 | newname[0] = NULL; |
933e73fa | 446 | } |
a5113b14 UD |
447 | else |
448 | { | |
30c14c31 | 449 | if (CATEGORY_USED (category)) |
a5113b14 | 450 | setdata (category, newdata); |
28f540f4 | 451 | |
650425ce | 452 | setname (category, newname[0]); |
a5113b14 | 453 | setname (LC_ALL, composite); |
111bb972 UD |
454 | |
455 | /* We successfully loaded a new locale. Let the message catalog | |
456 | functions know about this. */ | |
457 | ++_nl_msg_cat_cntr; | |
a5113b14 | 458 | } |
28f540f4 | 459 | |
a5113b14 | 460 | /* Critical section left. */ |
9a69db29 | 461 | __libc_rwlock_unlock (__libc_setlocale_lock); |
28f540f4 | 462 | |
714a562f UD |
463 | /* Free the resources (the locale path variable. */ |
464 | free (locale_path); | |
465 | ||
650425ce | 466 | return (char *) newname[0]; |
933e73fa | 467 | } |
28f540f4 | 468 | } |
30c14c31 | 469 | libc_hidden_def (setlocale) |
f84ad0b1 | 470 | |
7c11c4a1 | 471 | static void __libc_freeres_fn_section |
1a0d874e | 472 | free_category (int category, |
6e9331df | 473 | struct __locale_data *here, struct __locale_data *c_data) |
1a0d874e RM |
474 | { |
475 | struct loaded_l10nfile *runp = _nl_locale_file_list[category]; | |
476 | ||
477 | /* If this category is already "C" don't do anything. */ | |
478 | if (here != c_data) | |
479 | { | |
480 | /* We have to be prepared that sometime later we still | |
481 | might need the locale information. */ | |
482 | setdata (category, c_data); | |
483 | setname (category, _nl_C_name); | |
484 | } | |
485 | ||
486 | while (runp != NULL) | |
487 | { | |
488 | struct loaded_l10nfile *curr = runp; | |
6e9331df | 489 | struct __locale_data *data = (struct __locale_data *) runp->data; |
1a0d874e RM |
490 | |
491 | if (data != NULL && data != c_data) | |
bbebe83a | 492 | _nl_unload_locale (category, data); |
1a0d874e RM |
493 | runp = runp->next; |
494 | free ((char *) curr->filename); | |
495 | free (curr); | |
496 | } | |
497 | } | |
498 | ||
7c11c4a1 UD |
499 | /* This is called from iconv/gconv_db.c's free_mem, as locales must |
500 | be freed before freeing gconv steps arrays. */ | |
501 | void __libc_freeres_fn_section | |
502 | _nl_locale_subfreeres (void) | |
f84ad0b1 | 503 | { |
1a0d874e RM |
504 | #ifdef NL_CURRENT_INDIRECT |
505 | /* We don't use the loop because we want to have individual weak | |
506 | symbol references here. */ | |
507 | # define DEFINE_CATEGORY(category, category_name, items, a) \ | |
508 | if (CATEGORY_USED (category)) \ | |
509 | { \ | |
f095bb72 | 510 | extern struct __locale_data _nl_C_##category; \ |
1a0d874e RM |
511 | weak_extern (_nl_C_##category) \ |
512 | free_category (category, *_nl_current_##category, &_nl_C_##category); \ | |
513 | } | |
514 | # include "categories.def" | |
515 | # undef DEFINE_CATEGORY | |
516 | #else | |
f84ad0b1 UD |
517 | int category; |
518 | ||
4b10dd6c UD |
519 | for (category = 0; category < __LC_LAST; ++category) |
520 | if (category != LC_ALL) | |
1a0d874e RM |
521 | free_category (category, _NL_CURRENT_DATA (category), |
522 | _nl_C_locobj.__locales[category]); | |
523 | #endif | |
f84ad0b1 UD |
524 | |
525 | setname (LC_ALL, _nl_C_name); | |
a89a3dab RM |
526 | |
527 | /* This frees the data structures associated with the locale archive. | |
528 | The locales from the archive are not in the file list, so we have | |
529 | not called _nl_unload_locale on them above. */ | |
530 | _nl_archive_subfreeres (); | |
f84ad0b1 | 531 | } |