newlocale.c raw

   1  #include <stdlib.h>
   2  #include <string.h>
   3  #include <pthread.h>
   4  #include "locale_impl.h"
   5  #include "lock.h"
   6  
   7  #define malloc __libc_malloc
   8  #define calloc undef
   9  #define realloc undef
  10  #define free undef
  11  
  12  static int default_locale_init_done;
  13  static struct __locale_struct default_locale, default_ctype_locale;
  14  
  15  int __loc_is_allocated(locale_t loc)
  16  {
  17  	return loc && loc != C_LOCALE && loc != UTF8_LOCALE
  18  		&& loc != &default_locale && loc != &default_ctype_locale;
  19  }
  20  
  21  static locale_t do_newlocale(int mask, const char *name, locale_t loc)
  22  {
  23  	struct __locale_struct tmp;
  24  
  25  	for (int i=0; i<LC_ALL; i++) {
  26  		tmp.cat[i] = (!(mask & (1<<i)) && loc) ? loc->cat[i] :
  27  			__get_locale(i, (mask & (1<<i)) ? name : "");
  28  		if (tmp.cat[i] == LOC_MAP_FAILED)
  29  			return 0;
  30  	}
  31  
  32  	/* For locales with allocated storage, modify in-place. */
  33  	if (__loc_is_allocated(loc)) {
  34  		*loc = tmp;
  35  		return loc;
  36  	}
  37  
  38  	/* Otherwise, first see if we can use one of the builtin locales.
  39  	 * This makes the common usage case for newlocale, getting a C locale
  40  	 * with predictable behavior, very fast, and more importantly, fail-safe. */
  41  	if (!memcmp(&tmp, C_LOCALE, sizeof tmp)) return C_LOCALE;
  42  	if (!memcmp(&tmp, UTF8_LOCALE, sizeof tmp)) return UTF8_LOCALE;
  43  
  44  	/* And provide builtins for the initial default locale, and a
  45  	 * variant of the C locale honoring the default locale's encoding. */
  46  	if (!default_locale_init_done) {
  47  		for (int i=0; i<LC_ALL; i++)
  48  			default_locale.cat[i] = __get_locale(i, "");
  49  		default_ctype_locale.cat[LC_CTYPE] = default_locale.cat[LC_CTYPE];
  50  		default_locale_init_done = 1;
  51  	}
  52  	if (!memcmp(&tmp, &default_locale, sizeof tmp)) return &default_locale;
  53  	if (!memcmp(&tmp, &default_ctype_locale, sizeof tmp))
  54  		return &default_ctype_locale;
  55  
  56  	/* If no builtin locale matched, attempt to allocate and copy. */
  57  	if ((loc = malloc(sizeof *loc))) *loc = tmp;
  58  
  59  	return loc;
  60  }
  61  
  62  locale_t __newlocale(int mask, const char *name, locale_t loc)
  63  {
  64  	LOCK(__locale_lock);
  65  	loc = do_newlocale(mask, name, loc);
  66  	UNLOCK(__locale_lock);
  67  	return loc;
  68  }
  69  
  70  weak_alias(__newlocale, newlocale);
  71