Home | History | Annotate | Line # | Download | only in locale
setlocale.c revision 1.54
      1  1.54  ginsbach /*	$NetBSD: setlocale.c,v 1.54 2008/06/12 20:33:23 ginsbach Exp $	*/
      2  1.10    kleink 
      3   1.1       cgd /*
      4  1.53  ginsbach  * Copyright (c) 1991, 1993, 2008
      5   1.5       jtc  *	The Regents of the University of California.  All rights reserved.
      6   1.5       jtc  *
      7   1.5       jtc  * This code is derived from software contributed to Berkeley by
      8   1.5       jtc  * Paul Borman at Krystal Technologies.
      9   1.1       cgd  *
     10   1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11   1.1       cgd  * modification, are permitted provided that the following conditions
     12   1.1       cgd  * are met:
     13   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18  1.43       agc  * 3. Neither the name of the University nor the names of its contributors
     19   1.1       cgd  *    may be used to endorse or promote products derived from this software
     20   1.1       cgd  *    without specific prior written permission.
     21   1.1       cgd  *
     22   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1       cgd  * SUCH DAMAGE.
     33   1.1       cgd  */
     34   1.1       cgd 
     35  1.12  christos #include <sys/cdefs.h>
     36   1.1       cgd #if defined(LIBC_SCCS) && !defined(lint)
     37  1.10    kleink #if 0
     38   1.5       jtc static char sccsid[] = "@(#)setlocale.c	8.1 (Berkeley) 7/4/93";
     39  1.10    kleink #else
     40  1.54  ginsbach __RCSID("$NetBSD: setlocale.c,v 1.54 2008/06/12 20:33:23 ginsbach Exp $");
     41  1.10    kleink #endif
     42   1.1       cgd #endif /* LIBC_SCCS and not lint */
     43   1.1       cgd 
     44  1.11    kleink #define _CTYPE_PRIVATE
     45  1.11    kleink 
     46  1.14    kleink #include "namespace.h"
     47   1.5       jtc #include <sys/localedef.h>
     48  1.37      yamt #include <sys/types.h>
     49  1.37      yamt #include <sys/stat.h>
     50  1.37      yamt #include <assert.h>
     51  1.35    kleink #include <limits.h>
     52  1.11    kleink #include <ctype.h>
     53  1.18  tshiozak #define __SETLOCALE_SOURCE__
     54   1.1       cgd #include <locale.h>
     55  1.11    kleink #include <paths.h>
     56   1.6       jtc #include <stdio.h>
     57   1.5       jtc #include <stdlib.h>
     58   1.1       cgd #include <string.h>
     59  1.21     veego #include <unistd.h>
     60  1.32    itojun #ifdef WITH_RUNE
     61  1.24    itojun #include "rune.h"
     62  1.24    itojun #include "rune_local.h"
     63  1.32    itojun #else
     64  1.32    itojun #include "ctypeio.h"
     65  1.32    itojun #endif
     66  1.53  ginsbach #include "lcmessages.h"
     67  1.53  ginsbach #include "lcmonetary.h"
     68  1.53  ginsbach #include "lcnumeric.h"
     69  1.53  ginsbach #include "lctime.h"
     70   1.1       cgd 
     71  1.47  tshiozak #ifdef CITRUS
     72  1.44  tshiozak #include <citrus/citrus_namespace.h>
     73  1.44  tshiozak #include <citrus/citrus_region.h>
     74  1.44  tshiozak #include <citrus/citrus_lookup.h>
     75  1.46  tshiozak #include <citrus/citrus_bcs.h>
     76  1.47  tshiozak #else
     77  1.47  tshiozak #include <locale/aliasname_local.h>
     78  1.47  tshiozak #define _lookup_alias(p, a, b, s, c)	__unaliasname((p), (a), (b), (s))
     79  1.47  tshiozak #define _bcs_strcasecmp(a, b)		strcasecmp((a), (b))
     80  1.47  tshiozak #endif
     81  1.44  tshiozak 
     82  1.46  tshiozak #define _LOCALE_SYM_FORCE	"/force"
     83  1.44  tshiozak 
     84   1.5       jtc /*
     85   1.5       jtc  * Category names for getenv()
     86   1.5       jtc  */
     87  1.13   mycroft static const char *const categories[_LC_LAST] = {
     88   1.5       jtc     "LC_ALL",
     89   1.5       jtc     "LC_COLLATE",
     90   1.5       jtc     "LC_CTYPE",
     91   1.5       jtc     "LC_MONETARY",
     92   1.5       jtc     "LC_NUMERIC",
     93   1.5       jtc     "LC_TIME",
     94   1.5       jtc     "LC_MESSAGES"
     95   1.5       jtc };
     96   1.1       cgd 
     97   1.1       cgd /*
     98   1.5       jtc  * Current locales for each category
     99   1.5       jtc  */
    100   1.5       jtc static char current_categories[_LC_LAST][32] = {
    101   1.5       jtc     "C",
    102   1.5       jtc     "C",
    103   1.5       jtc     "C",
    104   1.5       jtc     "C",
    105   1.5       jtc     "C",
    106   1.5       jtc     "C",
    107   1.5       jtc     "C"
    108   1.5       jtc };
    109  1.19    kleink 
    110   1.5       jtc /*
    111   1.5       jtc  * The locales we are going to try and load
    112   1.1       cgd  */
    113   1.5       jtc static char new_categories[_LC_LAST][32];
    114   1.5       jtc 
    115   1.5       jtc static char current_locale_string[_LC_LAST * 33];
    116   1.5       jtc 
    117  1.34    itojun static char *currentlocale __P((void));
    118  1.46  tshiozak static void revert_to_default __P((int));
    119  1.46  tshiozak static int force_locale_enable __P((int));
    120  1.46  tshiozak static int load_locale_sub __P((int, const char *, int));
    121  1.34    itojun static char *loadlocale __P((int));
    122  1.37      yamt static const char *__get_locale_env __P((int));
    123  1.24    itojun 
    124  1.24    itojun char *
    125  1.24    itojun __setlocale(category, locale)
    126  1.24    itojun 	int category;
    127  1.24    itojun 	const char *locale;
    128  1.24    itojun {
    129  1.27  jdolecek 	int i, loadlocale_success;
    130  1.16  christos 	size_t len;
    131  1.37      yamt 	const char *env, *r;
    132   1.5       jtc 
    133  1.20  tshiozak 	if (issetugid() ||
    134  1.54  ginsbach 	    ((!_PathLocale && !(_PathLocale = getenv("PATH_LOCALE"))) ||
    135  1.54  ginsbach 	     !*_PathLocale))
    136  1.49      yamt 		_PathLocale = _PATH_LOCALE;
    137   1.5       jtc 
    138   1.5       jtc 	if (category < 0 || category >= _LC_LAST)
    139   1.1       cgd 		return (NULL);
    140   1.5       jtc 
    141   1.5       jtc 	if (!locale)
    142   1.5       jtc 		return (category ?
    143   1.5       jtc 		    current_categories[category] : currentlocale());
    144   1.5       jtc 
    145   1.5       jtc 	/*
    146   1.5       jtc 	 * Default to the current locale for everything.
    147   1.5       jtc 	 */
    148   1.5       jtc 	for (i = 1; i < _LC_LAST; ++i)
    149  1.23    itojun 		(void)strlcpy(new_categories[i], current_categories[i],
    150  1.23    itojun 		    sizeof(new_categories[i]));
    151   1.5       jtc 
    152   1.5       jtc 	/*
    153   1.5       jtc 	 * Now go fill up new_categories from the locale argument
    154   1.5       jtc 	 */
    155   1.5       jtc 	if (!*locale) {
    156  1.37      yamt 		if (category == LC_ALL) {
    157   1.5       jtc 			for (i = 1; i < _LC_LAST; ++i) {
    158  1.37      yamt 				env = __get_locale_env(i);
    159  1.23    itojun 				(void)strlcpy(new_categories[i], env,
    160  1.23    itojun 				    sizeof(new_categories[i]));
    161   1.5       jtc 			}
    162   1.5       jtc 		}
    163  1.37      yamt 		else {
    164  1.37      yamt 			env = __get_locale_env(category);
    165  1.37      yamt 			(void)strlcpy(new_categories[category], env,
    166  1.37      yamt 				sizeof(new_categories[category]));
    167  1.37      yamt 		}
    168   1.8       mrg 	} else if (category) {
    169  1.23    itojun 		(void)strlcpy(new_categories[category], locale,
    170  1.23    itojun 		    sizeof(new_categories[category]));
    171   1.5       jtc 	} else {
    172   1.5       jtc 		if ((r = strchr(locale, '/')) == 0) {
    173   1.5       jtc 			for (i = 1; i < _LC_LAST; ++i) {
    174  1.23    itojun 				(void)strlcpy(new_categories[i], locale,
    175  1.23    itojun 				    sizeof(new_categories[i]));
    176   1.5       jtc 			}
    177   1.5       jtc 		} else {
    178  1.42     enami 			for (i = 1;;) {
    179  1.42     enami 				_DIAGASSERT(*r == '/' || *r == 0);
    180  1.42     enami 				_DIAGASSERT(*locale != 0);
    181  1.42     enami 				if (*locale == '/')
    182  1.42     enami 					return (NULL);	/* invalid format. */
    183  1.40  tshiozak 				len = r - locale;
    184  1.39    itojun 				if (len + 1 > sizeof(new_categories[i]))
    185  1.39    itojun 					return (NULL);	/* too long */
    186  1.39    itojun 				(void)memcpy(new_categories[i], locale, len);
    187  1.39    itojun 				new_categories[i][len] = '\0';
    188  1.42     enami 				if (*r == 0)
    189  1.42     enami 					break;
    190  1.42     enami 				_DIAGASSERT(*r == '/');
    191  1.42     enami 				if (*(locale = ++r) == 0)
    192  1.42     enami 					/* slash followed by NUL */
    193  1.42     enami 					return (NULL);
    194  1.42     enami 				/* skip until NUL or '/' */
    195  1.42     enami 				while (*r && *r != '/')
    196  1.42     enami 					r++;
    197  1.42     enami 				if (++i == _LC_LAST)
    198  1.42     enami 					return (NULL);	/* too many slashes. */
    199  1.38  tshiozak 			}
    200  1.42     enami 			if (i + 1 != _LC_LAST)
    201  1.42     enami 				return (NULL);	/* too few slashes. */
    202   1.5       jtc 		}
    203   1.5       jtc 	}
    204   1.5       jtc 
    205   1.5       jtc 	if (category)
    206   1.5       jtc 		return (loadlocale(category));
    207   1.5       jtc 
    208  1.27  jdolecek 	loadlocale_success = 0;
    209  1.22    itojun 	for (i = 1; i < _LC_LAST; ++i) {
    210  1.27  jdolecek 		if (loadlocale(i) != NULL)
    211  1.27  jdolecek 			loadlocale_success = 1;
    212  1.22    itojun 	}
    213  1.27  jdolecek 
    214  1.27  jdolecek 	/*
    215  1.27  jdolecek 	 * If all categories failed, return NULL; we don't need to back
    216  1.27  jdolecek 	 * changes off, since none happened.
    217  1.27  jdolecek 	 */
    218  1.27  jdolecek 	if (!loadlocale_success)
    219  1.27  jdolecek 		return NULL;
    220  1.27  jdolecek 
    221   1.9    kleink 	return (currentlocale());
    222   1.5       jtc }
    223   1.5       jtc 
    224   1.5       jtc static char *
    225   1.5       jtc currentlocale()
    226   1.5       jtc {
    227   1.5       jtc 	int i;
    228   1.5       jtc 
    229  1.23    itojun 	(void)strlcpy(current_locale_string, current_categories[1],
    230  1.23    itojun 	    sizeof(current_locale_string));
    231   1.5       jtc 
    232   1.5       jtc 	for (i = 2; i < _LC_LAST; ++i)
    233   1.5       jtc 		if (strcmp(current_categories[1], current_categories[i])) {
    234   1.5       jtc 			(void)snprintf(current_locale_string,
    235  1.36      yamt 			    sizeof(current_locale_string), "%s/%s/%s/%s/%s/%s",
    236   1.5       jtc 			    current_categories[1], current_categories[2],
    237   1.5       jtc 			    current_categories[3], current_categories[4],
    238  1.36      yamt 			    current_categories[5], current_categories[6]);
    239   1.5       jtc 			break;
    240   1.5       jtc 		}
    241   1.5       jtc 	return (current_locale_string);
    242   1.5       jtc }
    243   1.5       jtc 
    244  1.46  tshiozak static void
    245  1.46  tshiozak revert_to_default(category)
    246  1.46  tshiozak 	int category;
    247  1.46  tshiozak {
    248  1.46  tshiozak 	switch (category) {
    249  1.46  tshiozak 	case LC_CTYPE:
    250  1.46  tshiozak #ifdef WITH_RUNE
    251  1.46  tshiozak 		(void)_xpg4_setrunelocale("C");
    252  1.46  tshiozak #else
    253  1.46  tshiozak 		if (_ctype_ != _C_ctype_) {
    254  1.46  tshiozak 			/* LINTED const castaway */
    255  1.46  tshiozak 			free((void *)_ctype_);
    256  1.46  tshiozak 			_ctype_ = _C_ctype_;
    257  1.46  tshiozak 		}
    258  1.46  tshiozak 		if (_toupper_tab_ != _C_toupper_) {
    259  1.46  tshiozak 			/* LINTED const castaway */
    260  1.46  tshiozak 			free((void *)_toupper_tab_);
    261  1.46  tshiozak 			_toupper_tab_ = _C_toupper_;
    262  1.46  tshiozak 		}
    263  1.46  tshiozak 		if (_tolower_tab_ != _C_tolower_) {
    264  1.46  tshiozak 			/* LINTED const castaway */
    265  1.46  tshiozak 			free((void *)_tolower_tab_);
    266  1.46  tshiozak 			_tolower_tab_ = _C_tolower_;
    267  1.46  tshiozak 		}
    268  1.46  tshiozak #endif
    269  1.46  tshiozak 		break;
    270  1.51      manu 	case LC_TIME:
    271  1.51      manu 		if (_CurrentTimeLocale != &_DefaultTimeLocale) {
    272  1.53  ginsbach 			free(__UNCONST(_CurrentTimeLocale));
    273  1.51      manu 			_CurrentTimeLocale = &_DefaultTimeLocale;
    274  1.51      manu 		}
    275  1.51      manu 		break;
    276  1.46  tshiozak 	case LC_MESSAGES:
    277  1.53  ginsbach 		if (_CurrentMessagesLocale != &_DefaultMessagesLocale) {
    278  1.53  ginsbach 			free(__UNCONST(_CurrentMessagesLocale));
    279  1.53  ginsbach 			_CurrentMessagesLocale = &_DefaultMessagesLocale;
    280  1.53  ginsbach 		}
    281  1.53  ginsbach 		break;
    282  1.46  tshiozak 	case LC_COLLATE:
    283  1.53  ginsbach 		break;
    284  1.46  tshiozak 	case LC_MONETARY:
    285  1.53  ginsbach 		if (_CurrentMonetaryLocale != &_DefaultMonetaryLocale) {
    286  1.53  ginsbach 			free(__UNCONST(_CurrentMonetaryLocale));
    287  1.53  ginsbach 			_CurrentMonetaryLocale = &_DefaultMonetaryLocale;
    288  1.53  ginsbach 		}
    289  1.53  ginsbach 		break;
    290  1.46  tshiozak 	case LC_NUMERIC:
    291  1.53  ginsbach 		if (_CurrentNumericLocale != &_DefaultNumericLocale) {
    292  1.53  ginsbach 			free(__UNCONST(_CurrentNumericLocale));
    293  1.53  ginsbach 			_CurrentNumericLocale = &_DefaultNumericLocale;
    294  1.53  ginsbach 		}
    295  1.46  tshiozak 		break;
    296  1.46  tshiozak 	}
    297  1.46  tshiozak }
    298  1.46  tshiozak 
    299  1.44  tshiozak static int
    300  1.46  tshiozak force_locale_enable(category)
    301  1.46  tshiozak 	int category;
    302  1.46  tshiozak {
    303  1.46  tshiozak 	revert_to_default(category);
    304  1.46  tshiozak 
    305  1.46  tshiozak 	return 0;
    306  1.46  tshiozak }
    307  1.46  tshiozak 
    308  1.46  tshiozak static int
    309  1.46  tshiozak load_locale_sub(category, locname, isspecial)
    310  1.44  tshiozak 	int category;
    311  1.44  tshiozak 	const char *locname;
    312  1.46  tshiozak 	int isspecial;
    313  1.44  tshiozak {
    314  1.44  tshiozak 	char name[PATH_MAX];
    315  1.54  ginsbach 	int len;
    316  1.44  tshiozak 
    317  1.46  tshiozak 	/* check for the default locales */
    318  1.46  tshiozak 	if (!strcmp(new_categories[category], "C") ||
    319  1.46  tshiozak 	    !strcmp(new_categories[category], "POSIX")) {
    320  1.46  tshiozak 		revert_to_default(category);
    321  1.46  tshiozak 		return 0;
    322  1.46  tshiozak 	}
    323  1.46  tshiozak 
    324  1.46  tshiozak 	/* check whether special symbol */
    325  1.46  tshiozak 	if (isspecial && _bcs_strcasecmp(locname, _LOCALE_SYM_FORCE) == 0)
    326  1.46  tshiozak 		return force_locale_enable(category);
    327  1.46  tshiozak 
    328  1.44  tshiozak 	/* sanity check */
    329  1.44  tshiozak 	if (strchr(locname, '/') != NULL)
    330  1.44  tshiozak 		return -1;
    331  1.44  tshiozak 
    332  1.54  ginsbach 	len = snprintf(name, sizeof(name), "%s/%s/%s",
    333  1.44  tshiozak 		       _PathLocale, locname, categories[category]);
    334  1.54  ginsbach 	if (len < 0 || len >= sizeof(name))
    335  1.54  ginsbach 		return -1;
    336  1.44  tshiozak 
    337  1.44  tshiozak 	switch (category) {
    338  1.44  tshiozak 	case LC_CTYPE:
    339  1.44  tshiozak #ifdef WITH_RUNE
    340  1.44  tshiozak 		if (_xpg4_setrunelocale(__UNCONST(locname)))
    341  1.44  tshiozak 			return -1;
    342  1.44  tshiozak #else
    343  1.44  tshiozak 		if (!__loadctype(name))
    344  1.44  tshiozak 			return -1;
    345  1.44  tshiozak #endif
    346  1.44  tshiozak 		break;
    347  1.44  tshiozak 
    348  1.44  tshiozak 	case LC_MESSAGES:
    349  1.54  ginsbach 		len += snprintf(name + len, sizeof(name) - len, "/%s",
    350  1.54  ginsbach 				categories[category]);
    351  1.54  ginsbach 		if (len >= sizeof(name))
    352  1.54  ginsbach 			return -1;
    353  1.54  ginsbach 		if (!__loadmessages(name))
    354  1.54  ginsbach #ifdef notyet
    355  1.54  ginsbach 			return -1;
    356  1.54  ginsbach #else
    357  1.44  tshiozak 		/*
    358  1.44  tshiozak 		 * XXX we don't have LC_MESSAGES support yet,
    359  1.44  tshiozak 		 * but catopen may use the value of LC_MESSAGES category.
    360  1.44  tshiozak 		 * so return successfully if locale directory is present.
    361  1.44  tshiozak 		 */
    362  1.44  tshiozak 		/* local */
    363  1.44  tshiozak 		{
    364  1.44  tshiozak 			struct stat st;
    365  1.54  ginsbach 
    366  1.54  ginsbach 			(void)snprintf(name, sizeof(name), "%s/%s",
    367  1.54  ginsbach 				_PathLocale, locname);
    368  1.44  tshiozak 			if (stat(name, &st) < 0)
    369  1.44  tshiozak 				return -1;
    370  1.44  tshiozak 			if (!S_ISDIR(st.st_mode))
    371  1.44  tshiozak 				return -1;
    372  1.44  tshiozak 		}
    373  1.53  ginsbach #endif
    374  1.44  tshiozak 		break;
    375  1.44  tshiozak 
    376  1.51      manu 	case LC_TIME:
    377  1.51      manu 		if (!__loadtime(name))
    378  1.51      manu 			return -1;
    379  1.51      manu 		break;
    380  1.44  tshiozak 	case LC_COLLATE:
    381  1.53  ginsbach 		return -1;
    382  1.44  tshiozak 	case LC_MONETARY:
    383  1.53  ginsbach 		if (!__loadmonetary(name))
    384  1.53  ginsbach 			return -1;
    385  1.53  ginsbach 		break;
    386  1.44  tshiozak 	case LC_NUMERIC:
    387  1.53  ginsbach 		if (!__loadnumeric(name))
    388  1.53  ginsbach 			return -1;
    389  1.53  ginsbach 		break;
    390  1.44  tshiozak 	}
    391  1.44  tshiozak 
    392  1.44  tshiozak 	return 0;
    393  1.44  tshiozak }
    394  1.44  tshiozak 
    395  1.15    kleink static char *
    396   1.5       jtc loadlocale(category)
    397   1.5       jtc 	int category;
    398   1.5       jtc {
    399  1.44  tshiozak 	char aliaspath[PATH_MAX], loccat[PATH_MAX], buf[PATH_MAX];
    400  1.44  tshiozak 	const char *alias;
    401   1.5       jtc 
    402  1.37      yamt 	_DIAGASSERT(0 < category && category < _LC_LAST);
    403  1.37      yamt 
    404  1.11    kleink 	if (strcmp(new_categories[category], current_categories[category]) == 0)
    405   1.5       jtc 		return (current_categories[category]);
    406   1.5       jtc 
    407  1.44  tshiozak 	/* (1) non-aliased file */
    408  1.46  tshiozak 	if (!load_locale_sub(category, new_categories[category], 0))
    409  1.44  tshiozak 		goto success;
    410  1.44  tshiozak 
    411  1.44  tshiozak 	/* (2) lookup locname/catname type alias */
    412  1.44  tshiozak 	(void)snprintf(aliaspath, sizeof(aliaspath),
    413  1.44  tshiozak 		       "%s/" _LOCALE_ALIAS_NAME, _PathLocale);
    414  1.44  tshiozak 	(void)snprintf(loccat, sizeof(loccat), "%s/%s",
    415  1.44  tshiozak 		       new_categories[category], categories[category]);
    416  1.44  tshiozak 	alias = _lookup_alias(aliaspath, loccat, buf, sizeof(buf),
    417  1.44  tshiozak 			      _LOOKUP_CASE_SENSITIVE);
    418  1.46  tshiozak 	if (!load_locale_sub(category, alias, 1))
    419  1.44  tshiozak 		goto success;
    420  1.44  tshiozak 
    421  1.44  tshiozak 	/* (3) lookup locname type alias */
    422  1.44  tshiozak 	alias = _lookup_alias(aliaspath, new_categories[category],
    423  1.44  tshiozak 			      buf, sizeof(buf), _LOOKUP_CASE_SENSITIVE);
    424  1.46  tshiozak 	if (!load_locale_sub(category, alias, 1))
    425  1.44  tshiozak 		goto success;
    426  1.11    kleink 
    427  1.44  tshiozak 	return NULL;
    428  1.11    kleink 
    429  1.44  tshiozak success:
    430  1.37      yamt 	(void)strlcpy(current_categories[category],
    431  1.37      yamt 		new_categories[category],
    432  1.37      yamt 		sizeof(current_categories[category]));
    433  1.37      yamt 	return current_categories[category];
    434  1.37      yamt }
    435  1.37      yamt 
    436  1.37      yamt static const char *
    437  1.37      yamt __get_locale_env(category)
    438  1.37      yamt 	int category;
    439  1.37      yamt {
    440  1.37      yamt 	const char *env;
    441  1.37      yamt 
    442  1.37      yamt 	_DIAGASSERT(category != LC_ALL);
    443  1.37      yamt 
    444  1.37      yamt 	/* 1. check LC_ALL. */
    445  1.37      yamt 	env = getenv(categories[0]);
    446  1.37      yamt 
    447  1.37      yamt 	/* 2. check LC_* */
    448  1.37      yamt 	if (!env || !*env)
    449  1.37      yamt 		env = getenv(categories[category]);
    450  1.37      yamt 
    451  1.37      yamt 	/* 3. check LANG */
    452  1.37      yamt 	if (!env || !*env)
    453  1.37      yamt 		env = getenv("LANG");
    454  1.37      yamt 
    455  1.37      yamt 	/* 4. if none is set, fall to "C" */
    456  1.37      yamt 	if (!env || !*env || strchr(env, '/'))
    457  1.37      yamt 		env = "C";
    458  1.37      yamt 
    459  1.37      yamt 	return env;
    460   1.1       cgd }
    461