localeimpl.c revision 732efd5515b5788339f3da4db04de7cea0f79c86
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * This file and its contents are supplied under the terms of the
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Common Development and Distribution License ("CDDL"), version 1.0.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * You may only use this file in accordance with the terms of version
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * 1.0 of the CDDL.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * A full copy of the text of the CDDL should have accompanied this
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * source. A copy of the CDDL is also available via the Internet at
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Copyright 2014 Garrett D'Amore <garrett@damore.org>
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * This file implements the 2008 newlocale and friends handling.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Big Theory of Locales:
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * (It is recommended that readers familiarize themselves with the POSIX
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * 2008 (XPG Issue 7) specifications for locales, first.)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Historically, we had a bunch of global variables that stored locale
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * data. While this worked well, it limited applications to a single locale
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * at a time. This doesn't work well in certain server applications.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Issue 7, X/Open introduced the concept of a locale_t object, along with
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * versions of functions that can take this object as a parameter, along
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * with functions to clone and manipulate these locale objects. The new
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * functions are named with a _l() suffix.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Additionally uselocale() is introduced which can change the locale of
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * of a single thread. However, setlocale() can still be used to change
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * the global locale.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * In our implementation, we use libc's TSD to store the locale data that
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * was previously global. We still have global data because some applications
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * have had those global objects compiled into them. (Such applications will
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * be unable to benefit from uselocale(), btw.) The legacy routines are
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * reimplemented as wrappers that use the appropriate locale object by
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * calling uselocale(). uselocale() when passed a NULL pointer returns the
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * thread-specific locale object if one is present, or the global locale
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * object otherwise. Note that once the TSD data is set, the only way
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * to revert to the global locale is to pass the global locale LC_GLOBAL_LOCALE
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * to uselocale().
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * We are careful to minimize performance impact of multiple calls to
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * uselocale() or setlocale() by using a cache of locale data whenever possible.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * As a consequence of this, applications that iterate over all possible
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * locales will burn through a lot of virtual memory, but we find such
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * applications rare. (locale -a might be an exception, but it is short lived.)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Category data is never released (although enclosing locale objects might be),
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * in order to guarantee thread-safety. Calling freelocale() on an object
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * while it is in use by another thread is a programmer error (use-after-free)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * and we don't bother to note it further.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Locale objects (global locales) established by setlocale() are also
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * never freed (for MT safety), but we will save previous locale objects
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * and reuse them when we can.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaitypedef struct locdata *(*loadfn_t)(const char *);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaiextern struct lc_monetary lc_monetary_posix;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaiextern struct lc_messages lc_messages_posix;
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Category names for getenv() Note that this was modified
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * for Solaris. See <iso/locale_iso.h>.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "LC_MONETARY",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai "LC_MESSAGES",
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistatic const char *get_locale_env(int);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistatic struct locdata *locdata_get(int, const const char *);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistatic struct locdata *locdata_get_cache(int, const char *);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Some utility routines.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai__locdata_alloc(const char *name, size_t memsz)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((ldata = lmalloc(sizeof (*ldata))) == NULL) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((ldata->l_data[0] = libc_malloc(memsz)) == NULL) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) strlcpy(ldata->l_lname, name, sizeof (ldata->l_lname));
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Normally we never free locale data truly, but if we failed to load it
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * for some reason, this routine is used to cleanup the partial mess.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (int i = 0; i < NLOCDATA; i++)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (ldata->l_map != NULL && ldata->l_map_len)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai (void) munmap(ldata->l_map, ldata->l_map_len);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * It turns out that for performance reasons we would really like to
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * cache the most recently referenced locale data to avoid wasteful
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * loading from files.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Returns the cached data if the locale name is the same. If not,
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * returns NULL (cache miss). The locdata is returned with a hold on
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * it, taken on behalf of the caller. The caller should drop the hold
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * when it is finished.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavaistatic struct locdata *
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavailocdata_get_cache(int category, const char *locname)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai /* Try cache first. */
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if ((loc != NULL) && (strcmp(loc->l_lname, locname) == 0)) {
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * Failing that try previously loaded locales (linear search) --
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * this could be optimized to a hash, but its unlikely that a single
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai * application will ever need to work with more than a few locales.
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai for (loc = cat_data[category]; loc != NULL; loc = loc->l_next) {
return (loc);
static struct locdata *
char *slash;
int cnt;
int len;
if (slash) {
const char *env;
return (env);
__mb_cur_max(void)
return (NULL);
for (i = 0; i < LC_ALL; i++) {
return (loc);
return (NULL);
return (NULL);
for (i = 0; i < LC_ALL; i++) {
e = errno;
errno = e;
return (NULL);
return (NULL);
return (lastloc);
static locale_t
int composite = 0;
if (composite) {
return (loc);