| 1 | /* Copyright (C) 1991-2020 Free Software Foundation, Inc. | 
|---|
| 2 | This file is part of the GNU C Library. | 
|---|
| 3 |  | 
|---|
| 4 | The GNU C Library is free software; you can redistribute it and/or | 
|---|
| 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. | 
|---|
| 8 |  | 
|---|
| 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 | Lesser General Public License for more details. | 
|---|
| 13 |  | 
|---|
| 14 | You should have received a copy of the GNU Lesser General Public | 
|---|
| 15 | License along with the GNU C Library; if not, see | 
|---|
| 16 | <https://www.gnu.org/licenses/>.  */ | 
|---|
| 17 |  | 
|---|
| 18 | #include <alloca.h> | 
|---|
| 19 | #include <argz.h> | 
|---|
| 20 | #include <errno.h> | 
|---|
| 21 | #include <libc-lock.h> | 
|---|
| 22 | #include <locale.h> | 
|---|
| 23 | #include <stdlib.h> | 
|---|
| 24 | #include <string.h> | 
|---|
| 25 | #include <unistd.h> | 
|---|
| 26 |  | 
|---|
| 27 | #include "localeinfo.h" | 
|---|
| 28 |  | 
|---|
| 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[] = | 
|---|
| 48 | { | 
|---|
| 49 | # define DEFINE_CATEGORY(category, category_name, items, a) \ | 
|---|
| 50 | [category] = &_nl_current_##category##_used, | 
|---|
| 51 | # include "categories.def" | 
|---|
| 52 | # undef	DEFINE_CATEGORY | 
|---|
| 53 | }; | 
|---|
| 54 |  | 
|---|
| 55 | # define CATEGORY_USED(category)	(_nl_current_used[category] != 0) | 
|---|
| 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 |  | 
|---|
| 62 | # define CATEGORY_USED(category)	(1) | 
|---|
| 63 |  | 
|---|
| 64 | #endif | 
|---|
| 65 |  | 
|---|
| 66 |  | 
|---|
| 67 | /* Define an array of category names (also the environment variable names).  */ | 
|---|
| 68 | const struct catnamestr_t _nl_category_names attribute_hidden = | 
|---|
| 69 | { | 
|---|
| 70 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
|---|
| 71 | category_name, | 
|---|
| 72 | #include "categories.def" | 
|---|
| 73 | #undef DEFINE_CATEGORY | 
|---|
| 74 | }; | 
|---|
| 75 |  | 
|---|
| 76 | const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = | 
|---|
| 77 | { | 
|---|
| 78 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
|---|
| 79 | [category] = offsetof (struct catnamestr_t, CATNAMEMF (__LINE__)), | 
|---|
| 80 | #include "categories.def" | 
|---|
| 81 | #undef DEFINE_CATEGORY | 
|---|
| 82 | }; | 
|---|
| 83 |  | 
|---|
| 84 | /* An array of their lengths, for convenience.  */ | 
|---|
| 85 | const uint8_t _nl_category_name_sizes[] attribute_hidden = | 
|---|
| 86 | { | 
|---|
| 87 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
|---|
| 88 | [category] = sizeof (category_name) - 1, | 
|---|
| 89 | #include "categories.def" | 
|---|
| 90 | #undef	DEFINE_CATEGORY | 
|---|
| 91 | [LC_ALL] = sizeof ( "LC_ALL") - 1 | 
|---|
| 92 | }; | 
|---|
| 93 |  | 
|---|
| 94 |  | 
|---|
| 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 |  | 
|---|
| 101 | /* Declare the postload functions used below.  */ | 
|---|
| 102 | #undef	NO_POSTLOAD | 
|---|
| 103 | #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist.  */ | 
|---|
| 104 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ | 
|---|
| 105 | extern void postload (void); WEAK_POSTLOAD (postload) | 
|---|
| 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.  */ | 
|---|
| 112 | static void (*const _nl_category_postload[]) (void) = | 
|---|
| 113 | { | 
|---|
| 114 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ | 
|---|
| 115 | [category] = postload, | 
|---|
| 116 | #include "categories.def" | 
|---|
| 117 | #undef	DEFINE_CATEGORY | 
|---|
| 118 | }; | 
|---|
| 119 |  | 
|---|
| 120 |  | 
|---|
| 121 | /* Lock for protecting global data.  */ | 
|---|
| 122 | __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden) | 
|---|
| 123 |  | 
|---|
| 124 | /* Defined in loadmsgcat.c.  */ | 
|---|
| 125 | extern int _nl_msg_cat_cntr; | 
|---|
| 126 |  | 
|---|
| 127 |  | 
|---|
| 128 | /* Use this when we come along an error.  */ | 
|---|
| 129 | #define ERROR_RETURN							      \ | 
|---|
| 130 | do {									      \ | 
|---|
| 131 | __set_errno (EINVAL);						      \ | 
|---|
| 132 | return NULL;							      \ | 
|---|
| 133 | } while (0) | 
|---|
| 134 |  | 
|---|
| 135 |  | 
|---|
| 136 | /* Construct a new composite name.  */ | 
|---|
| 137 | static char * | 
|---|
| 138 | new_composite_name (int category, const char *newnames[__LC_LAST]) | 
|---|
| 139 | { | 
|---|
| 140 | size_t last_len = 0; | 
|---|
| 141 | size_t cumlen = 0; | 
|---|
| 142 | int i; | 
|---|
| 143 | char *new, *p; | 
|---|
| 144 | int same = 1; | 
|---|
| 145 |  | 
|---|
| 146 | for (i = 0; i < __LC_LAST; ++i) | 
|---|
| 147 | if (i != LC_ALL) | 
|---|
| 148 | { | 
|---|
| 149 | const char *name = (category == LC_ALL ? newnames[i] | 
|---|
| 150 | : category == i ? newnames[0] | 
|---|
| 151 | : _nl_global_locale.__names[i]); | 
|---|
| 152 | last_len = strlen (name); | 
|---|
| 153 | cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1; | 
|---|
| 154 | if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0) | 
|---|
| 155 | same = 0; | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | if (same) | 
|---|
| 159 | { | 
|---|
| 160 | /* All the categories use the same name.  */ | 
|---|
| 161 | if (strcmp (newnames[0], _nl_C_name) == 0 | 
|---|
| 162 | || strcmp (newnames[0], _nl_POSIX_name) == 0) | 
|---|
| 163 | return (char *) _nl_C_name; | 
|---|
| 164 |  | 
|---|
| 165 | new = malloc (last_len + 1); | 
|---|
| 166 |  | 
|---|
| 167 | return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1); | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | new = malloc (cumlen); | 
|---|
| 171 | if (new == NULL) | 
|---|
| 172 | return NULL; | 
|---|
| 173 | p = new; | 
|---|
| 174 | for (i = 0; i < __LC_LAST; ++i) | 
|---|
| 175 | if (i != LC_ALL) | 
|---|
| 176 | { | 
|---|
| 177 | /* Add "CATEGORY=NAME;" to the string.  */ | 
|---|
| 178 | const char *name = (category == LC_ALL ? newnames[i] | 
|---|
| 179 | : category == i ? newnames[0] | 
|---|
| 180 | : _nl_global_locale.__names[i]); | 
|---|
| 181 | p = __stpcpy (p, _nl_category_names_get (i)); | 
|---|
| 182 | *p++ = '='; | 
|---|
| 183 | p = __stpcpy (p, name); | 
|---|
| 184 | *p++ = ';'; | 
|---|
| 185 | } | 
|---|
| 186 | p[-1] = '\0';		/* Clobber the last ';'.  */ | 
|---|
| 187 | return new; | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 |  | 
|---|
| 191 | /* Put NAME in _nl_global_locale.__names.  */ | 
|---|
| 192 | static void | 
|---|
| 193 | setname (int category, const char *name) | 
|---|
| 194 | { | 
|---|
| 195 | if (_nl_global_locale.__names[category] == name) | 
|---|
| 196 | return; | 
|---|
| 197 |  | 
|---|
| 198 | if (_nl_global_locale.__names[category] != _nl_C_name) | 
|---|
| 199 | free ((char *) _nl_global_locale.__names[category]); | 
|---|
| 200 |  | 
|---|
| 201 | _nl_global_locale.__names[category] = name; | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | /* Put DATA in *_nl_current[CATEGORY].  */ | 
|---|
| 205 | static void | 
|---|
| 206 | setdata (int category, struct __locale_data *data) | 
|---|
| 207 | { | 
|---|
| 208 | if (CATEGORY_USED (category)) | 
|---|
| 209 | { | 
|---|
| 210 | _nl_global_locale.__locales[category] = data; | 
|---|
| 211 | if (_nl_category_postload[category]) | 
|---|
| 212 | (*_nl_category_postload[category]) (); | 
|---|
| 213 | } | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 | char * | 
|---|
| 217 | setlocale (int category, const char *locale) | 
|---|
| 218 | { | 
|---|
| 219 | char *locale_path; | 
|---|
| 220 | size_t locale_path_len; | 
|---|
| 221 | const char *locpath_var; | 
|---|
| 222 | char *composite; | 
|---|
| 223 |  | 
|---|
| 224 | /* Sanity check for CATEGORY argument.  */ | 
|---|
| 225 | if (__builtin_expect (category, 0) < 0 | 
|---|
| 226 | || __builtin_expect (category, 0) >= __LC_LAST) | 
|---|
| 227 | ERROR_RETURN; | 
|---|
| 228 |  | 
|---|
| 229 | /* Does user want name of current locale?  */ | 
|---|
| 230 | if (locale == NULL) | 
|---|
| 231 | return (char *) _nl_global_locale.__names[category]; | 
|---|
| 232 |  | 
|---|
| 233 | /* Protect global data.  */ | 
|---|
| 234 | __libc_rwlock_wrlock (__libc_setlocale_lock); | 
|---|
| 235 |  | 
|---|
| 236 | if (strcmp (locale, _nl_global_locale.__names[category]) == 0) | 
|---|
| 237 | { | 
|---|
| 238 | /* Changing to the same thing.  */ | 
|---|
| 239 | __libc_rwlock_unlock (__libc_setlocale_lock); | 
|---|
| 240 |  | 
|---|
| 241 | return (char *) _nl_global_locale.__names[category]; | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 | /* We perhaps really have to load some data.  So we determine the | 
|---|
| 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 | 
|---|
| 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.  */ | 
|---|
| 249 | locale_path = NULL; | 
|---|
| 250 | locale_path_len = 0; | 
|---|
| 251 |  | 
|---|
| 252 | locpath_var = getenv ( "LOCPATH"); | 
|---|
| 253 | if (locpath_var != NULL && locpath_var[0] != '\0') | 
|---|
| 254 | { | 
|---|
| 255 | if (__argz_create_sep (locpath_var, ':', | 
|---|
| 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 | } | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | if (category == LC_ALL) | 
|---|
| 266 | { | 
|---|
| 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'.  */ | 
|---|
| 271 | const char *newnames[__LC_LAST]; | 
|---|
| 272 | struct __locale_data *newdata[__LC_LAST]; | 
|---|
| 273 | /* Copy of the locale argument, for in-place splitting.  */ | 
|---|
| 274 | char *locale_copy = NULL; | 
|---|
| 275 |  | 
|---|
| 276 | /* Set all name pointers to the argument name.  */ | 
|---|
| 277 | for (category = 0; category < __LC_LAST; ++category) | 
|---|
| 278 | if (category != LC_ALL) | 
|---|
| 279 | newnames[category] = (char *) locale; | 
|---|
| 280 |  | 
|---|
| 281 | if (__glibc_unlikely (strchr (locale, ';') != NULL)) | 
|---|
| 282 | { | 
|---|
| 283 | /* This is a composite name.  Make a copy and split it up.  */ | 
|---|
| 284 | locale_copy = __strdup (locale); | 
|---|
| 285 | if (__glibc_unlikely (locale_copy == NULL)) | 
|---|
| 286 | { | 
|---|
| 287 | __libc_rwlock_unlock (__libc_setlocale_lock); | 
|---|
| 288 | return NULL; | 
|---|
| 289 | } | 
|---|
| 290 | char *np = locale_copy; | 
|---|
| 291 | char *cp; | 
|---|
| 292 | int cnt; | 
|---|
| 293 |  | 
|---|
| 294 | while ((cp = strchr (np, '=')) != NULL) | 
|---|
| 295 | { | 
|---|
| 296 | for (cnt = 0; cnt < __LC_LAST; ++cnt) | 
|---|
| 297 | if (cnt != LC_ALL | 
|---|
| 298 | && (size_t) (cp - np) == _nl_category_name_sizes[cnt] | 
|---|
| 299 | && (memcmp (np, (_nl_category_names_get (cnt)), cp - np) | 
|---|
| 300 | == 0)) | 
|---|
| 301 | break; | 
|---|
| 302 |  | 
|---|
| 303 | if (cnt == __LC_LAST) | 
|---|
| 304 | { | 
|---|
| 305 | error_return: | 
|---|
| 306 | __libc_rwlock_unlock (__libc_setlocale_lock); | 
|---|
| 307 | free (locale_copy); | 
|---|
| 308 |  | 
|---|
| 309 | /* Bogus category name.  */ | 
|---|
| 310 | ERROR_RETURN; | 
|---|
| 311 | } | 
|---|
| 312 |  | 
|---|
| 313 | /* Found the category this clause sets.  */ | 
|---|
| 314 | newnames[cnt] = ++cp; | 
|---|
| 315 | cp = strchr (cp, ';'); | 
|---|
| 316 | if (cp != NULL) | 
|---|
| 317 | { | 
|---|
| 318 | /* Examine the next clause.  */ | 
|---|
| 319 | *cp = '\0'; | 
|---|
| 320 | np = cp + 1; | 
|---|
| 321 | } | 
|---|
| 322 | else | 
|---|
| 323 | /* This was the last clause.  We are done.  */ | 
|---|
| 324 | break; | 
|---|
| 325 | } | 
|---|
| 326 |  | 
|---|
| 327 | for (cnt = 0; cnt < __LC_LAST; ++cnt) | 
|---|
| 328 | if (cnt != LC_ALL && newnames[cnt] == locale) | 
|---|
| 329 | /* The composite name did not specify all categories.  */ | 
|---|
| 330 | goto error_return; | 
|---|
| 331 | } | 
|---|
| 332 |  | 
|---|
| 333 | /* Load the new data for each category.  */ | 
|---|
| 334 | while (category-- > 0) | 
|---|
| 335 | if (category != LC_ALL) | 
|---|
| 336 | { | 
|---|
| 337 | newdata[category] = _nl_find_locale (locale_path, locale_path_len, | 
|---|
| 338 | category, | 
|---|
| 339 | &newnames[category]); | 
|---|
| 340 |  | 
|---|
| 341 | if (newdata[category] == NULL) | 
|---|
| 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 | } | 
|---|
| 350 |  | 
|---|
| 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.  */ | 
|---|
| 355 | if (newdata[category]->usage_count != UNDELETABLE) | 
|---|
| 356 | newdata[category]->usage_count = UNDELETABLE; | 
|---|
| 357 |  | 
|---|
| 358 | /* Make a copy of locale name.  */ | 
|---|
| 359 | if (newnames[category] != _nl_C_name) | 
|---|
| 360 | { | 
|---|
| 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 | } | 
|---|
| 370 | } | 
|---|
| 371 | } | 
|---|
| 372 |  | 
|---|
| 373 | /* Create new composite name.  */ | 
|---|
| 374 | composite = (category >= 0 | 
|---|
| 375 | ? NULL : new_composite_name (LC_ALL, newnames)); | 
|---|
| 376 | if (composite != NULL) | 
|---|
| 377 | { | 
|---|
| 378 | /* Now we have loaded all the new data.  Put it in place.  */ | 
|---|
| 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 | } | 
|---|
| 385 | setname (LC_ALL, composite); | 
|---|
| 386 |  | 
|---|
| 387 | /* We successfully loaded a new locale.  Let the message catalog | 
|---|
| 388 | functions know about this.  */ | 
|---|
| 389 | ++_nl_msg_cat_cntr; | 
|---|
| 390 | } | 
|---|
| 391 | else | 
|---|
| 392 | for (++category; category < __LC_LAST; ++category) | 
|---|
| 393 | if (category != LC_ALL && newnames[category] != _nl_C_name | 
|---|
| 394 | && newnames[category] != _nl_global_locale.__names[category]) | 
|---|
| 395 | free ((char *) newnames[category]); | 
|---|
| 396 |  | 
|---|
| 397 | /* Critical section left.  */ | 
|---|
| 398 | __libc_rwlock_unlock (__libc_setlocale_lock); | 
|---|
| 399 |  | 
|---|
| 400 | /* Free the resources.  */ | 
|---|
| 401 | free (locale_path); | 
|---|
| 402 | free (locale_copy); | 
|---|
| 403 |  | 
|---|
| 404 | return composite; | 
|---|
| 405 | } | 
|---|
| 406 | else | 
|---|
| 407 | { | 
|---|
| 408 | struct __locale_data *newdata = NULL; | 
|---|
| 409 | const char *newname[1] = { locale }; | 
|---|
| 410 |  | 
|---|
| 411 | if (CATEGORY_USED (category)) | 
|---|
| 412 | { | 
|---|
| 413 | /* Only actually load the data if anything will use it.  */ | 
|---|
| 414 | newdata = _nl_find_locale (locale_path, locale_path_len, category, | 
|---|
| 415 | &newname[0]); | 
|---|
| 416 | if (newdata == NULL) | 
|---|
| 417 | goto abort_single; | 
|---|
| 418 |  | 
|---|
| 419 | /* We must not simply free a global locale since we have no | 
|---|
| 420 | control over the usage.  So we mark it as un-deletable. | 
|---|
| 421 |  | 
|---|
| 422 | Note: do not remove the `if', it's necessary to cope with | 
|---|
| 423 | the builtin locale data.  */ | 
|---|
| 424 | if (newdata->usage_count != UNDELETABLE) | 
|---|
| 425 | newdata->usage_count = UNDELETABLE; | 
|---|
| 426 | } | 
|---|
| 427 |  | 
|---|
| 428 | /* Make a copy of locale name.  */ | 
|---|
| 429 | if (newname[0] != _nl_C_name) | 
|---|
| 430 | { | 
|---|
| 431 | newname[0] = __strdup (newname[0]); | 
|---|
| 432 | if (newname[0] == NULL) | 
|---|
| 433 | goto abort_single; | 
|---|
| 434 | } | 
|---|
| 435 |  | 
|---|
| 436 | /* Create new composite name.  */ | 
|---|
| 437 | composite = new_composite_name (category, newname); | 
|---|
| 438 | if (composite == NULL) | 
|---|
| 439 | { | 
|---|
| 440 | if (newname[0] != _nl_C_name) | 
|---|
| 441 | free ((char *) newname[0]); | 
|---|
| 442 |  | 
|---|
| 443 | /* Say that we don't have any data loaded.  */ | 
|---|
| 444 | abort_single: | 
|---|
| 445 | newname[0] = NULL; | 
|---|
| 446 | } | 
|---|
| 447 | else | 
|---|
| 448 | { | 
|---|
| 449 | if (CATEGORY_USED (category)) | 
|---|
| 450 | setdata (category, newdata); | 
|---|
| 451 |  | 
|---|
| 452 | setname (category, newname[0]); | 
|---|
| 453 | setname (LC_ALL, composite); | 
|---|
| 454 |  | 
|---|
| 455 | /* We successfully loaded a new locale.  Let the message catalog | 
|---|
| 456 | functions know about this.  */ | 
|---|
| 457 | ++_nl_msg_cat_cntr; | 
|---|
| 458 | } | 
|---|
| 459 |  | 
|---|
| 460 | /* Critical section left.  */ | 
|---|
| 461 | __libc_rwlock_unlock (__libc_setlocale_lock); | 
|---|
| 462 |  | 
|---|
| 463 | /* Free the resources (the locale path variable.  */ | 
|---|
| 464 | free (locale_path); | 
|---|
| 465 |  | 
|---|
| 466 | return (char *) newname[0]; | 
|---|
| 467 | } | 
|---|
| 468 | } | 
|---|
| 469 | libc_hidden_def (setlocale) | 
|---|
| 470 |  | 
|---|
| 471 | static void __libc_freeres_fn_section | 
|---|
| 472 | free_category (int category, | 
|---|
| 473 | struct __locale_data *here, struct __locale_data *c_data) | 
|---|
| 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; | 
|---|
| 489 | struct __locale_data *data = (struct __locale_data *) runp->data; | 
|---|
| 490 |  | 
|---|
| 491 | if (data != NULL && data != c_data) | 
|---|
| 492 | _nl_unload_locale (data); | 
|---|
| 493 | runp = runp->next; | 
|---|
| 494 | free ((char *) curr->filename); | 
|---|
| 495 | free (curr); | 
|---|
| 496 | } | 
|---|
| 497 | } | 
|---|
| 498 |  | 
|---|
| 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) | 
|---|
| 503 | { | 
|---|
| 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 | {									      \ | 
|---|
| 510 | extern struct __locale_data _nl_C_##category;			      \ | 
|---|
| 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 | 
|---|
| 517 | int category; | 
|---|
| 518 |  | 
|---|
| 519 | for (category = 0; category < __LC_LAST; ++category) | 
|---|
| 520 | if (category != LC_ALL) | 
|---|
| 521 | free_category (category, _NL_CURRENT_DATA (category), | 
|---|
| 522 | _nl_C_locobj.__locales[category]); | 
|---|
| 523 | #endif | 
|---|
| 524 |  | 
|---|
| 525 | setname (LC_ALL, _nl_C_name); | 
|---|
| 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 (); | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|