--- setlocale.c.orig 2009-11-09 15:05:25.000000000 -0800 +++ setlocale.c 2009-11-09 15:05:26.000000000 -0800 @@ -37,6 +37,8 @@ static char sccsid[] = "@(#)setlocale.c #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/lib/libc/locale/setlocale.c,v 1.51 2007/01/09 00:28:00 imp Exp $"); +#include "xlocale_private.h" + #include <sys/types.h> #include <sys/stat.h> #include <errno.h> @@ -52,7 +54,7 @@ __FBSDID("$FreeBSD: src/lib/libc/locale/ #include "lmessages.h" /* for __messages_load_locale() */ #include "setlocale.h" #include "ldpart.h" -#include "../stdtime/timelocal.h" /* for __time_load_locale() */ +#include "timelocal.h" /* for __time_load_locale() */ /* * Category names for getenv() @@ -95,15 +97,18 @@ static char current_locale_string[_LC_LA static char *currentlocale(void); static char *loadlocale(int); -static const char *__get_locale_env(int); +__private_extern__ const char *__get_locale_env(int); + +#define UNLOCK_AND_RETURN(x) {XL_UNLOCK(&__global_locale); return (x);} char * setlocale(category, locale) int category; const char *locale; { - int i, j, len, saverr; + int i, j, len, saverr, save__numeric_fp_cvt; const char *env, *r; + locale_t save__lc_numeric_loc; if (category < LC_ALL || category >= _LC_LAST) { errno = EINVAL; @@ -114,6 +119,7 @@ setlocale(category, locale) return (category != LC_ALL ? current_categories[category] : currentlocale()); + XL_LOCK(&__global_locale); /* * Default to the current locale for everything. */ @@ -129,7 +135,7 @@ setlocale(category, locale) env = __get_locale_env(i); if (strlen(env) > ENCODING_LEN) { errno = EINVAL; - return (NULL); + UNLOCK_AND_RETURN (NULL); } (void)strcpy(new_categories[i], env); } @@ -137,21 +143,21 @@ setlocale(category, locale) env = __get_locale_env(category); if (strlen(env) > ENCODING_LEN) { errno = EINVAL; - return (NULL); + UNLOCK_AND_RETURN (NULL); } (void)strcpy(new_categories[category], env); } } else if (category != LC_ALL) { if (strlen(locale) > ENCODING_LEN) { errno = EINVAL; - return (NULL); + UNLOCK_AND_RETURN (NULL); } (void)strcpy(new_categories[category], locale); } else { if ((r = strchr(locale, '/')) == NULL) { if (strlen(locale) > ENCODING_LEN) { errno = EINVAL; - return (NULL); + UNLOCK_AND_RETURN (NULL); } for (i = 1; i < _LC_LAST; ++i) (void)strcpy(new_categories[i], locale); @@ -160,14 +166,14 @@ setlocale(category, locale) ; if (!r[1]) { errno = EINVAL; - return (NULL); /* Hmm, just slashes... */ + UNLOCK_AND_RETURN (NULL); /* Hmm, just slashes... */ } do { if (i == _LC_LAST) break; /* Too many slashes... */ if ((len = r - locale) > ENCODING_LEN) { errno = EINVAL; - return (NULL); + UNLOCK_AND_RETURN (NULL); } (void)strlcpy(new_categories[i], locale, len + 1); @@ -187,8 +193,11 @@ setlocale(category, locale) } if (category != LC_ALL) - return (loadlocale(category)); + UNLOCK_AND_RETURN (loadlocale(category)); + save__numeric_fp_cvt = __global_locale.__numeric_fp_cvt; + save__lc_numeric_loc = __global_locale.__lc_numeric_loc; + XL_RETAIN(save__lc_numeric_loc); for (i = 1; i < _LC_LAST; ++i) { (void)strcpy(saved_categories[i], current_categories[i]); if (loadlocale(i) == NULL) { @@ -201,11 +210,15 @@ setlocale(category, locale) (void)loadlocale(j); } } + __global_locale.__numeric_fp_cvt = save__numeric_fp_cvt; + __global_locale.__lc_numeric_loc = save__lc_numeric_loc; + XL_RELEASE(save__lc_numeric_loc); errno = saverr; - return (NULL); + UNLOCK_AND_RETURN (NULL); } } - return (currentlocale()); + XL_RELEASE(save__lc_numeric_loc); + UNLOCK_AND_RETURN (currentlocale()); } static char * @@ -233,7 +246,7 @@ loadlocale(category) { char *new = new_categories[category]; char *old = current_categories[category]; - int (*func)(const char *); + int (*func)(const char *, locale_t); int saved_errno; if ((new[0] == '.' && @@ -276,15 +289,26 @@ loadlocale(category) if (strcmp(new, old) == 0) return (old); - if (func(new) != _LDP_ERROR) { + if (func(new, &__global_locale) != _LDP_ERROR) { (void)strcpy(old, new); + switch (category) { + case LC_CTYPE: + if (__global_locale.__numeric_fp_cvt == LC_NUMERIC_FP_SAME_LOCALE) + __global_locale.__numeric_fp_cvt = LC_NUMERIC_FP_UNINITIALIZED; + break; + case LC_NUMERIC: + __global_locale.__numeric_fp_cvt = LC_NUMERIC_FP_UNINITIALIZED; + XL_RELEASE(__global_locale.__lc_numeric_loc); + __global_locale.__lc_numeric_loc = NULL; + break; + } return (old); } return (NULL); } -static const char * +__private_extern__ const char * __get_locale_env(category) int category; { @@ -311,7 +335,7 @@ __get_locale_env(category) /* * Detect locale storage location and store its value to _PathLocale variable */ -int +__private_extern__ int __detect_path_locale(void) { if (_PathLocale == NULL) {