| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 1991-2016 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 |    <http://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 union catnamestr_t _nl_category_names attribute_hidden = | 
 | 69 |   { | 
 | 70 |     { | 
 | 71 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
 | 72 |       category_name, | 
 | 73 | #include "categories.def" | 
 | 74 | #undef DEFINE_CATEGORY | 
 | 75 |     } | 
 | 76 |   }; | 
 | 77 |  | 
 | 78 | const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = | 
 | 79 |   { | 
 | 80 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
 | 81 |     [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)), | 
 | 82 | #include "categories.def" | 
 | 83 | #undef DEFINE_CATEGORY | 
 | 84 |   }; | 
 | 85 |  | 
 | 86 | /* An array of their lengths, for convenience.  */ | 
 | 87 | const uint8_t _nl_category_name_sizes[] attribute_hidden = | 
 | 88 |   { | 
 | 89 | #define DEFINE_CATEGORY(category, category_name, items, a) \ | 
 | 90 |     [category] = sizeof (category_name) - 1, | 
 | 91 | #include "categories.def" | 
 | 92 | #undef	DEFINE_CATEGORY | 
 | 93 |     [LC_ALL] = sizeof ("LC_ALL") - 1 | 
 | 94 |   }; | 
 | 95 |  | 
 | 96 |  | 
 | 97 | #ifdef NL_CURRENT_INDIRECT | 
 | 98 | # define WEAK_POSTLOAD(postload) weak_extern (postload) | 
 | 99 | #else | 
 | 100 | # define WEAK_POSTLOAD(postload) /* Need strong refs in static linking.  */ | 
 | 101 | #endif | 
 | 102 |  | 
 | 103 | /* Declare the postload functions used below.  */ | 
 | 104 | #undef	NO_POSTLOAD | 
 | 105 | #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist.  */ | 
 | 106 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ | 
 | 107 | extern void postload (void); WEAK_POSTLOAD (postload) | 
 | 108 | #include "categories.def" | 
 | 109 | #undef	DEFINE_CATEGORY | 
 | 110 | #undef	NO_POSTLOAD | 
 | 111 |  | 
 | 112 | /* Define an array indexed by category of postload functions to call after | 
 | 113 |    loading and installing that category's data.  */ | 
 | 114 | static void (*const _nl_category_postload[]) (void) = | 
 | 115 |   { | 
 | 116 | #define DEFINE_CATEGORY(category, category_name, items, postload) \ | 
 | 117 |     [category] = postload, | 
 | 118 | #include "categories.def" | 
 | 119 | #undef	DEFINE_CATEGORY | 
 | 120 |   }; | 
 | 121 |  | 
 | 122 |  | 
 | 123 | /* Lock for protecting global data.  */ | 
 | 124 | __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden) | 
 | 125 |  | 
 | 126 | /* Defined in loadmsgcat.c.  */ | 
 | 127 | extern int _nl_msg_cat_cntr; | 
 | 128 |  | 
 | 129 |  | 
 | 130 | /* Use this when we come along an error.  */ | 
 | 131 | #define ERROR_RETURN							      \ | 
 | 132 |   do {									      \ | 
 | 133 |     __set_errno (EINVAL);						      \ | 
 | 134 |     return NULL;							      \ | 
 | 135 |   } while (0) | 
 | 136 |  | 
 | 137 |  | 
 | 138 | /* Construct a new composite name.  */ | 
 | 139 | static char * | 
 | 140 | new_composite_name (int category, const char *newnames[__LC_LAST]) | 
 | 141 | { | 
 | 142 |   size_t last_len = 0; | 
 | 143 |   size_t cumlen = 0; | 
 | 144 |   int i; | 
 | 145 |   char *new, *p; | 
 | 146 |   int same = 1; | 
 | 147 |  | 
 | 148 |   for (i = 0; i < __LC_LAST; ++i) | 
 | 149 |     if (i != LC_ALL) | 
 | 150 |       { | 
 | 151 | 	const char *name = (category == LC_ALL ? newnames[i] : | 
 | 152 | 			    category == i ? newnames[0] : | 
 | 153 | 			    _nl_global_locale.__names[i]); | 
 | 154 | 	last_len = strlen (name); | 
 | 155 | 	cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1; | 
 | 156 | 	if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0) | 
 | 157 | 	  same = 0; | 
 | 158 |       } | 
 | 159 |  | 
 | 160 |   if (same) | 
 | 161 |     { | 
 | 162 |       /* All the categories use the same name.  */ | 
 | 163 |       if (strcmp (newnames[0], _nl_C_name) == 0 | 
 | 164 | 	  || strcmp (newnames[0], _nl_POSIX_name) == 0) | 
 | 165 | 	return (char *) _nl_C_name; | 
 | 166 |  | 
 | 167 |       new = malloc (last_len + 1); | 
 | 168 |  | 
 | 169 |       return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1); | 
 | 170 |     } | 
 | 171 |  | 
 | 172 |   new = malloc (cumlen); | 
 | 173 |   if (new == NULL) | 
 | 174 |     return NULL; | 
 | 175 |   p = new; | 
 | 176 |   for (i = 0; i < __LC_LAST; ++i) | 
 | 177 |     if (i != LC_ALL) | 
 | 178 |       { | 
 | 179 | 	/* Add "CATEGORY=NAME;" to the string.  */ | 
 | 180 | 	const char *name = (category == LC_ALL ? newnames[i] : | 
 | 181 | 			    category == i ? newnames[0] : | 
 | 182 | 			    _nl_global_locale.__names[i]); | 
 | 183 | 	p = __stpcpy (p, _nl_category_names.str + _nl_category_name_idxs[i]); | 
 | 184 | 	*p++ = '='; | 
 | 185 | 	p = __stpcpy (p, name); | 
 | 186 | 	*p++ = ';'; | 
 | 187 |       } | 
 | 188 |   p[-1] = '\0';		/* Clobber the last ';'.  */ | 
 | 189 |   return new; | 
 | 190 | } | 
 | 191 |  | 
 | 192 |  | 
 | 193 | /* Put NAME in _nl_global_locale.__names.  */ | 
 | 194 | static void | 
 | 195 | setname (int category, const char *name) | 
 | 196 | { | 
 | 197 |   if (_nl_global_locale.__names[category] == name) | 
 | 198 |     return; | 
 | 199 |  | 
 | 200 |   if (_nl_global_locale.__names[category] != _nl_C_name) | 
 | 201 |     free ((char *) _nl_global_locale.__names[category]); | 
 | 202 |  | 
 | 203 |   _nl_global_locale.__names[category] = name; | 
 | 204 | } | 
 | 205 |  | 
 | 206 | /* Put DATA in *_nl_current[CATEGORY].  */ | 
 | 207 | static void | 
 | 208 | setdata (int category, struct __locale_data *data) | 
 | 209 | { | 
 | 210 |   if (CATEGORY_USED (category)) | 
 | 211 |     { | 
 | 212 |       _nl_global_locale.__locales[category] = data; | 
 | 213 |       if (_nl_category_postload[category]) | 
 | 214 | 	(*_nl_category_postload[category]) (); | 
 | 215 |     } | 
 | 216 | } | 
 | 217 |  | 
 | 218 | char * | 
 | 219 | setlocale (int category, const char *locale) | 
 | 220 | { | 
 | 221 |   char *locale_path; | 
 | 222 |   size_t locale_path_len; | 
 | 223 |   const char *locpath_var; | 
 | 224 |   char *composite; | 
 | 225 |  | 
 | 226 |   /* Sanity check for CATEGORY argument.  */ | 
 | 227 |   if (__builtin_expect (category, 0) < 0 | 
 | 228 |       || __builtin_expect (category, 0) >= __LC_LAST) | 
 | 229 |     ERROR_RETURN; | 
 | 230 |  | 
 | 231 |   /* Does user want name of current locale?  */ | 
 | 232 |   if (locale == NULL) | 
 | 233 |     return (char *) _nl_global_locale.__names[category]; | 
 | 234 |  | 
 | 235 |   /* Protect global data.  */ | 
 | 236 |   __libc_rwlock_wrlock (__libc_setlocale_lock); | 
 | 237 |  | 
 | 238 |   if (strcmp (locale, _nl_global_locale.__names[category]) == 0) | 
 | 239 |     { | 
 | 240 |       /* Changing to the same thing.  */ | 
 | 241 |       __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 242 |  | 
 | 243 |       return (char *) _nl_global_locale.__names[category]; | 
 | 244 |     } | 
 | 245 |  | 
 | 246 |   /* We perhaps really have to load some data.  So we determine the | 
 | 247 |      path in which to look for the data now.  The environment variable | 
 | 248 |      `LOCPATH' must only be used when the binary has no SUID or SGID | 
 | 249 |      bit set.  If using the default path, we tell _nl_find_locale | 
 | 250 |      by passing null and it can check the canonical locale archive.  */ | 
 | 251 |   locale_path = NULL; | 
 | 252 |   locale_path_len = 0; | 
 | 253 |  | 
 | 254 |   locpath_var = getenv ("LOCPATH"); | 
 | 255 |   if (locpath_var != NULL && locpath_var[0] != '\0') | 
 | 256 |     { | 
 | 257 |       if (__argz_create_sep (locpath_var, ':', | 
 | 258 | 			     &locale_path, &locale_path_len) != 0 | 
 | 259 | 	  || __argz_add_sep (&locale_path, &locale_path_len, | 
 | 260 | 			     _nl_default_locale_path, ':') != 0) | 
 | 261 | 	{ | 
 | 262 | 	  __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 263 | 	  return NULL; | 
 | 264 | 	} | 
 | 265 |     } | 
 | 266 |  | 
 | 267 |   if (category == LC_ALL) | 
 | 268 |     { | 
 | 269 |       /* The user wants to set all categories.  The desired locales | 
 | 270 | 	 for the individual categories can be selected by using a | 
 | 271 | 	 composite locale name.  This is a semi-colon separated list | 
 | 272 | 	 of entries of the form `CATEGORY=VALUE'.  */ | 
 | 273 |       const char *newnames[__LC_LAST]; | 
 | 274 |       struct __locale_data *newdata[__LC_LAST]; | 
 | 275 |       /* Copy of the locale argument, for in-place splitting.  */ | 
 | 276 |       char *locale_copy = NULL; | 
 | 277 |  | 
 | 278 |       /* Set all name pointers to the argument name.  */ | 
 | 279 |       for (category = 0; category < __LC_LAST; ++category) | 
 | 280 | 	if (category != LC_ALL) | 
 | 281 | 	  newnames[category] = (char *) locale; | 
 | 282 |  | 
 | 283 |       if (__glibc_unlikely (strchr (locale, ';') != NULL)) | 
 | 284 | 	{ | 
 | 285 | 	  /* This is a composite name.  Make a copy and split it up.  */ | 
 | 286 | 	  locale_copy = strdup (locale); | 
 | 287 | 	  if (__glibc_unlikely (locale_copy == NULL)) | 
 | 288 | 	    { | 
 | 289 | 	      __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 290 | 	      return NULL; | 
 | 291 | 	    } | 
 | 292 | 	  char *np = locale_copy; | 
 | 293 | 	  char *cp; | 
 | 294 | 	  int cnt; | 
 | 295 |  | 
 | 296 | 	  while ((cp = strchr (np, '=')) != NULL) | 
 | 297 | 	    { | 
 | 298 | 	      for (cnt = 0; cnt < __LC_LAST; ++cnt) | 
 | 299 | 		if (cnt != LC_ALL | 
 | 300 | 		    && (size_t) (cp - np) == _nl_category_name_sizes[cnt] | 
 | 301 | 		    && (memcmp (np, (_nl_category_names.str | 
 | 302 | 				     + _nl_category_name_idxs[cnt]), cp - np) | 
 | 303 | 			== 0)) | 
 | 304 | 		  break; | 
 | 305 |  | 
 | 306 | 	      if (cnt == __LC_LAST) | 
 | 307 | 		{ | 
 | 308 | 		error_return: | 
 | 309 | 		  __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 310 | 		  free (locale_copy); | 
 | 311 |  | 
 | 312 | 		  /* Bogus category name.  */ | 
 | 313 | 		  ERROR_RETURN; | 
 | 314 | 		} | 
 | 315 |  | 
 | 316 | 	      /* Found the category this clause sets.  */ | 
 | 317 | 	      newnames[cnt] = ++cp; | 
 | 318 | 	      cp = strchr (cp, ';'); | 
 | 319 | 	      if (cp != NULL) | 
 | 320 | 		{ | 
 | 321 | 		  /* Examine the next clause.  */ | 
 | 322 | 		  *cp = '\0'; | 
 | 323 | 		  np = cp + 1; | 
 | 324 | 		} | 
 | 325 | 	      else | 
 | 326 | 		/* This was the last clause.  We are done.  */ | 
 | 327 | 		break; | 
 | 328 | 	    } | 
 | 329 |  | 
 | 330 | 	  for (cnt = 0; cnt < __LC_LAST; ++cnt) | 
 | 331 | 	    if (cnt != LC_ALL && newnames[cnt] == locale) | 
 | 332 | 	      /* The composite name did not specify all categories.  */ | 
 | 333 | 	      goto error_return; | 
 | 334 | 	} | 
 | 335 |  | 
 | 336 |       /* Load the new data for each category.  */ | 
 | 337 |       while (category-- > 0) | 
 | 338 | 	if (category != LC_ALL) | 
 | 339 | 	  { | 
 | 340 | 	    newdata[category] = _nl_find_locale (locale_path, locale_path_len, | 
 | 341 | 						 category, | 
 | 342 | 						 &newnames[category]); | 
 | 343 |  | 
 | 344 | 	    if (newdata[category] == NULL) | 
 | 345 | 	      { | 
 | 346 | #ifdef NL_CURRENT_INDIRECT | 
 | 347 | 		if (newnames[category] == _nl_C_name) | 
 | 348 | 		  /* Null because it's the weak value of _nl_C_LC_FOO.  */ | 
 | 349 | 		  continue; | 
 | 350 | #endif | 
 | 351 | 		break; | 
 | 352 | 	      } | 
 | 353 |  | 
 | 354 | 	    /* We must not simply free a global locale since we have | 
 | 355 | 	       no control over the usage.  So we mark it as | 
 | 356 | 	       un-deletable.  And yes, the 'if' is needed, the data | 
 | 357 | 	       might be in read-only memory.  */ | 
 | 358 | 	    if (newdata[category]->usage_count != UNDELETABLE) | 
 | 359 | 	      newdata[category]->usage_count = UNDELETABLE; | 
 | 360 |  | 
 | 361 | 	    /* Make a copy of locale name.  */ | 
 | 362 | 	    if (newnames[category] != _nl_C_name) | 
 | 363 | 	      { | 
 | 364 | 		if (strcmp (newnames[category], | 
 | 365 | 			    _nl_global_locale.__names[category]) == 0) | 
 | 366 | 		  newnames[category] = _nl_global_locale.__names[category]; | 
 | 367 | 		else | 
 | 368 | 		  { | 
 | 369 | 		    newnames[category] = __strdup (newnames[category]); | 
 | 370 | 		    if (newnames[category] == NULL) | 
 | 371 | 		      break; | 
 | 372 | 		  } | 
 | 373 | 	      } | 
 | 374 | 	  } | 
 | 375 |  | 
 | 376 |       /* Create new composite name.  */ | 
 | 377 |       composite = (category >= 0 | 
 | 378 | 		   ? NULL : new_composite_name (LC_ALL, newnames)); | 
 | 379 |       if (composite != NULL) | 
 | 380 | 	{ | 
 | 381 | 	  /* Now we have loaded all the new data.  Put it in place.  */ | 
 | 382 | 	  for (category = 0; category < __LC_LAST; ++category) | 
 | 383 | 	    if (category != LC_ALL) | 
 | 384 | 	      { | 
 | 385 | 		setdata (category, newdata[category]); | 
 | 386 | 		setname (category, newnames[category]); | 
 | 387 | 	      } | 
 | 388 | 	  setname (LC_ALL, composite); | 
 | 389 |  | 
 | 390 | 	  /* We successfully loaded a new locale.  Let the message catalog | 
 | 391 | 	     functions know about this.  */ | 
 | 392 | 	  ++_nl_msg_cat_cntr; | 
 | 393 | 	} | 
 | 394 |       else | 
 | 395 | 	for (++category; category < __LC_LAST; ++category) | 
 | 396 | 	  if (category != LC_ALL && newnames[category] != _nl_C_name | 
 | 397 | 	      && newnames[category] != _nl_global_locale.__names[category]) | 
 | 398 | 	    free ((char *) newnames[category]); | 
 | 399 |  | 
 | 400 |       /* Critical section left.  */ | 
 | 401 |       __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 402 |  | 
 | 403 |       /* Free the resources.  */ | 
 | 404 |       free (locale_path); | 
 | 405 |       free (locale_copy); | 
 | 406 |  | 
 | 407 |       return composite; | 
 | 408 |     } | 
 | 409 |   else | 
 | 410 |     { | 
 | 411 |       struct __locale_data *newdata = NULL; | 
 | 412 |       const char *newname[1] = { locale }; | 
 | 413 |  | 
 | 414 |       if (CATEGORY_USED (category)) | 
 | 415 | 	{ | 
 | 416 | 	  /* Only actually load the data if anything will use it.  */ | 
 | 417 | 	  newdata = _nl_find_locale (locale_path, locale_path_len, category, | 
 | 418 | 				     &newname[0]); | 
 | 419 | 	  if (newdata == NULL) | 
 | 420 | 	    goto abort_single; | 
 | 421 |  | 
 | 422 | 	  /* We must not simply free a global locale since we have no | 
 | 423 | 	     control over the usage.  So we mark it as un-deletable. | 
 | 424 |  | 
 | 425 | 	     Note: do not remove the `if', it's necessary to cope with | 
 | 426 | 	     the builtin locale data.  */ | 
 | 427 | 	  if (newdata->usage_count != UNDELETABLE) | 
 | 428 | 	    newdata->usage_count = UNDELETABLE; | 
 | 429 | 	} | 
 | 430 |  | 
 | 431 |       /* Make a copy of locale name.  */ | 
 | 432 |       if (newname[0] != _nl_C_name) | 
 | 433 | 	{ | 
 | 434 | 	  newname[0] = __strdup (newname[0]); | 
 | 435 | 	  if (newname[0] == NULL) | 
 | 436 | 	    goto abort_single; | 
 | 437 | 	} | 
 | 438 |  | 
 | 439 |       /* Create new composite name.  */ | 
 | 440 |       composite = new_composite_name (category, newname); | 
 | 441 |       if (composite == NULL) | 
 | 442 | 	{ | 
 | 443 | 	  if (newname[0] != _nl_C_name) | 
 | 444 | 	    free ((char *) newname[0]); | 
 | 445 |  | 
 | 446 | 	  /* Say that we don't have any data loaded.  */ | 
 | 447 | 	abort_single: | 
 | 448 | 	  newname[0] = NULL; | 
 | 449 | 	} | 
 | 450 |       else | 
 | 451 | 	{ | 
 | 452 | 	  if (CATEGORY_USED (category)) | 
 | 453 | 	    setdata (category, newdata); | 
 | 454 |  | 
 | 455 | 	  setname (category, newname[0]); | 
 | 456 | 	  setname (LC_ALL, composite); | 
 | 457 |  | 
 | 458 | 	  /* We successfully loaded a new locale.  Let the message catalog | 
 | 459 | 	     functions know about this.  */ | 
 | 460 | 	  ++_nl_msg_cat_cntr; | 
 | 461 | 	} | 
 | 462 |  | 
 | 463 |       /* Critical section left.  */ | 
 | 464 |       __libc_rwlock_unlock (__libc_setlocale_lock); | 
 | 465 |  | 
 | 466 |       /* Free the resources (the locale path variable.  */ | 
 | 467 |       free (locale_path); | 
 | 468 |  | 
 | 469 |       return (char *) newname[0]; | 
 | 470 |     } | 
 | 471 | } | 
 | 472 | libc_hidden_def (setlocale) | 
 | 473 |  | 
 | 474 | static void __libc_freeres_fn_section | 
 | 475 | free_category (int category, | 
 | 476 | 	       struct __locale_data *here, struct __locale_data *c_data) | 
 | 477 | { | 
 | 478 |   struct loaded_l10nfile *runp = _nl_locale_file_list[category]; | 
 | 479 |  | 
 | 480 |   /* If this category is already "C" don't do anything.  */ | 
 | 481 |   if (here != c_data) | 
 | 482 |     { | 
 | 483 |       /* We have to be prepared that sometime later we still | 
 | 484 | 	 might need the locale information.  */ | 
 | 485 |       setdata (category, c_data); | 
 | 486 |       setname (category, _nl_C_name); | 
 | 487 |     } | 
 | 488 |  | 
 | 489 |   while (runp != NULL) | 
 | 490 |     { | 
 | 491 |       struct loaded_l10nfile *curr = runp; | 
 | 492 |       struct __locale_data *data = (struct __locale_data *) runp->data; | 
 | 493 |  | 
 | 494 |       if (data != NULL && data != c_data) | 
 | 495 | 	_nl_unload_locale (data); | 
 | 496 |       runp = runp->next; | 
 | 497 |       free ((char *) curr->filename); | 
 | 498 |       free (curr); | 
 | 499 |     } | 
 | 500 | } | 
 | 501 |  | 
 | 502 | /* This is called from iconv/gconv_db.c's free_mem, as locales must | 
 | 503 |    be freed before freeing gconv steps arrays.  */ | 
 | 504 | void __libc_freeres_fn_section | 
 | 505 | _nl_locale_subfreeres (void) | 
 | 506 | { | 
 | 507 | #ifdef NL_CURRENT_INDIRECT | 
 | 508 |   /* We don't use the loop because we want to have individual weak | 
 | 509 |      symbol references here.  */ | 
 | 510 | # define DEFINE_CATEGORY(category, category_name, items, a)		      \ | 
 | 511 |   if (CATEGORY_USED (category))						      \ | 
 | 512 |     {									      \ | 
 | 513 |       extern struct __locale_data _nl_C_##category;			      \ | 
 | 514 |       weak_extern (_nl_C_##category)					      \ | 
 | 515 |       free_category (category, *_nl_current_##category, &_nl_C_##category);   \ | 
 | 516 |     } | 
 | 517 | # include "categories.def" | 
 | 518 | # undef	DEFINE_CATEGORY | 
 | 519 | #else | 
 | 520 |   int category; | 
 | 521 |  | 
 | 522 |   for (category = 0; category < __LC_LAST; ++category) | 
 | 523 |     if (category != LC_ALL) | 
 | 524 |       free_category (category, _NL_CURRENT_DATA (category), | 
 | 525 | 		     _nl_C_locobj.__locales[category]); | 
 | 526 | #endif | 
 | 527 |  | 
 | 528 |   setname (LC_ALL, _nl_C_name); | 
 | 529 |  | 
 | 530 |   /* This frees the data structures associated with the locale archive. | 
 | 531 |      The locales from the archive are not in the file list, so we have | 
 | 532 |      not called _nl_unload_locale on them above.  */ | 
 | 533 |   _nl_archive_subfreeres (); | 
 | 534 | } |