Module Name:    src
Committed By:   joerg
Date:           Fri Sep 13 13:13:32 UTC 2013

Modified Files:
        src/lib/libc/citrus: citrus_lc_ctype.c
        src/lib/libc/compat/locale: compat_setlocale1.c
        src/lib/libc/locale: global_locale.c localeconv.c nb_lc_messages_misc.h
            nb_lc_monetary_misc.h nb_lc_numeric_misc.h nb_lc_template.h
            nb_lc_template_decl.h nb_lc_time_misc.h newlocale.c setlocale.c
            setlocale_local.h

Log Message:
Redo the locale cache to be constant. It now contains the localeconv()
data and which LC_MONETARY and LC_NUMERIC values it is derived from.
In newlocale(3) and setlocale(3), check for the existing entries and on
miss, create a new entry. This is currently not using a lock for the
list as the worst case is a small memory leak.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/lib/libc/citrus/citrus_lc_ctype.c
cvs rdiff -u -r1.1 -r1.2 src/lib/libc/compat/locale/compat_setlocale1.c
cvs rdiff -u -r1.20 -r1.21 src/lib/libc/locale/global_locale.c
cvs rdiff -u -r1.21 -r1.22 src/lib/libc/locale/localeconv.c
cvs rdiff -u -r1.6 -r1.7 src/lib/libc/locale/nb_lc_messages_misc.h \
    src/lib/libc/locale/nb_lc_monetary_misc.h \
    src/lib/libc/locale/nb_lc_numeric_misc.h
cvs rdiff -u -r1.7 -r1.8 src/lib/libc/locale/nb_lc_template.h \
    src/lib/libc/locale/nb_lc_time_misc.h
cvs rdiff -u -r1.3 -r1.4 src/lib/libc/locale/nb_lc_template_decl.h
cvs rdiff -u -r1.2 -r1.3 src/lib/libc/locale/newlocale.c
cvs rdiff -u -r1.63 -r1.64 src/lib/libc/locale/setlocale.c
cvs rdiff -u -r1.14 -r1.15 src/lib/libc/locale/setlocale_local.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/citrus/citrus_lc_ctype.c
diff -u src/lib/libc/citrus/citrus_lc_ctype.c:1.14 src/lib/libc/citrus/citrus_lc_ctype.c:1.15
--- src/lib/libc/citrus/citrus_lc_ctype.c:1.14	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/citrus/citrus_lc_ctype.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: citrus_lc_ctype.c,v 1.14 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: citrus_lc_ctype.c,v 1.15 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: citrus_lc_ctype.c,v 1.14 2013/08/20 19:58:30 joerg Exp $");
+__RCSID("$NetBSD: citrus_lc_ctype.c,v 1.15 2013/09/13 13:13:32 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include "reentrant.h"
@@ -96,14 +96,6 @@ _citrus_LC_CTYPE_create_impl(const char 
 }
 
 static __inline void
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict cache,
-    _RuneLocale * __restrict data)
-{
-	_DIAGASSERT(cache != NULL);
-	_DIAGASSERT(data != NULL);
-}
-
-static __inline void
 _PREFIX(update_global)(_RuneLocale *data)
 {
 	_DIAGASSERT(data != NULL);

Index: src/lib/libc/compat/locale/compat_setlocale1.c
diff -u src/lib/libc/compat/locale/compat_setlocale1.c:1.1 src/lib/libc/compat/locale/compat_setlocale1.c:1.2
--- src/lib/libc/compat/locale/compat_setlocale1.c:1.1	Mon Jun  7 13:52:30 2010
+++ src/lib/libc/compat/locale/compat_setlocale1.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: compat_setlocale1.c,v 1.1 2010/06/07 13:52:30 tnozaki Exp $ */
+/* $NetBSD: compat_setlocale1.c,v 1.2 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)1999 Citrus Project,
@@ -30,7 +30,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: compat_setlocale1.c,v 1.1 2010/06/07 13:52:30 tnozaki Exp $");
+__RCSID("$NetBSD: compat_setlocale1.c,v 1.2 2013/09/13 13:13:32 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
@@ -38,6 +38,8 @@ __RCSID("$NetBSD: compat_setlocale1.c,v 
 
 #include "setlocale_local.h"
 
+#undef setlocale
+
 __warn_references(setlocale,
     "warning: reference to compatibility setlocale();"
     "include <locale.h> for correct reference")
@@ -47,7 +49,10 @@ __warn_references(setlocale,
  * This function will ensure binary compatibility for old executables.
  */
 char *
-setlocale(int category, const char *locale)
+compat_setlocale(int category, const char *locale) __RENAME(setlocale);
+
+char *
+compat_setlocale(int category, const char *locale)
 {
 
 	/* locale may be NULL */

Index: src/lib/libc/locale/global_locale.c
diff -u src/lib/libc/locale/global_locale.c:1.20 src/lib/libc/locale/global_locale.c:1.21
--- src/lib/libc/locale/global_locale.c:1.20	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/global_locale.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: global_locale.c,v 1.20 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: global_locale.c,v 1.21 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: global_locale.c,v 1.20 2013/08/20 19:58:30 joerg Exp $");
+__RCSID("$NetBSD: global_locale.c,v 1.21 2013/09/13 13:13:32 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
@@ -110,7 +110,10 @@ static const _TimeLocale _DefaultTimeLoc
 	"%I:%M:%S %p"
 };
 
-static const struct lconv _C_ldata = {
+static const char _lc_C_locale_name[] = _C_LOCALE;
+
+__dso_hidden const struct _locale_cache_t _C_cache = {
+    .ldata = {
 	.decimal_point		= __UNCONST("."),
 	.thousands_sep		= __UNCONST(""),
 	.grouping		= __UNCONST(""),
@@ -135,23 +138,22 @@ static const struct lconv _C_ldata = {
 	.int_n_sep_by_space	= NBCHAR_MAX,
 	.int_p_sign_posn	= NBCHAR_MAX,
 	.int_n_sign_posn	= NBCHAR_MAX,
-};
-
-static struct _locale_cache_t _global_cache = {
-    .ldata = __UNCONST(&_C_ldata),
+    },
+    .monetary_name = _lc_C_locale_name,
+    .numeric_name = _lc_C_locale_name,
 };
 
 __dso_protected struct _locale _lc_global_locale = {
-    .cache = &_global_cache,
+    .cache = &_C_cache,
     .query = { _C_LOCALE },
     .part_name = {
-	[(size_t)LC_ALL     ] = _C_LOCALE,
-	[(size_t)LC_COLLATE ] = _C_LOCALE,
-	[(size_t)LC_CTYPE   ] = _C_LOCALE,
-	[(size_t)LC_MONETARY] = _C_LOCALE,
-	[(size_t)LC_NUMERIC ] = _C_LOCALE,
-	[(size_t)LC_TIME    ] = _C_LOCALE,
-	[(size_t)LC_MESSAGES] = _C_LOCALE,
+	[(size_t)LC_ALL     ] = _lc_C_locale_name,
+	[(size_t)LC_COLLATE ] = _lc_C_locale_name,
+	[(size_t)LC_CTYPE   ] = _lc_C_locale_name,
+	[(size_t)LC_MONETARY] = _lc_C_locale_name,
+	[(size_t)LC_NUMERIC ] = _lc_C_locale_name,
+	[(size_t)LC_TIME    ] = _lc_C_locale_name,
+	[(size_t)LC_MESSAGES] = _lc_C_locale_name,
     },
     .part_impl = {
 	[(size_t)LC_ALL     ] = (_locale_part_t)NULL,
@@ -169,21 +171,17 @@ __dso_protected struct _locale _lc_globa
     },
 };
 
-static const struct _locale_cache_t _C_cache = {
-    .ldata = __UNCONST(&_C_ldata),
-};
-
 __dso_protected const struct _locale _lc_C_locale = {
-    .cache = __UNCONST(&_C_cache),
+    .cache = &_C_cache,
     .query = { _C_LOCALE },
     .part_name = {
-	[(size_t)LC_ALL     ] = _C_LOCALE,
-	[(size_t)LC_COLLATE ] = _C_LOCALE,
-	[(size_t)LC_CTYPE   ] = _C_LOCALE,
-	[(size_t)LC_MONETARY] = _C_LOCALE,
-	[(size_t)LC_NUMERIC ] = _C_LOCALE,
-	[(size_t)LC_TIME    ] = _C_LOCALE,
-	[(size_t)LC_MESSAGES] = _C_LOCALE,
+	[(size_t)LC_ALL     ] = _lc_C_locale_name,
+	[(size_t)LC_COLLATE ] = _lc_C_locale_name,
+	[(size_t)LC_CTYPE   ] = _lc_C_locale_name,
+	[(size_t)LC_MONETARY] = _lc_C_locale_name,
+	[(size_t)LC_NUMERIC ] = _lc_C_locale_name,
+	[(size_t)LC_TIME    ] = _lc_C_locale_name,
+	[(size_t)LC_MESSAGES] = _lc_C_locale_name,
     },
     .part_impl = {
 	[(size_t)LC_ALL     ] = (_locale_part_t)NULL,

Index: src/lib/libc/locale/localeconv.c
diff -u src/lib/libc/locale/localeconv.c:1.21 src/lib/libc/locale/localeconv.c:1.22
--- src/lib/libc/locale/localeconv.c:1.21	Fri May 17 12:55:57 2013
+++ src/lib/libc/locale/localeconv.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: localeconv.c,v 1.21 2013/05/17 12:55:57 joerg Exp $ */
+/* $NetBSD: localeconv.c,v 1.22 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: localeconv.c,v 1.21 2013/05/17 12:55:57 joerg Exp $");
+__RCSID("$NetBSD: localeconv.c,v 1.22 2013/09/13 13:13:32 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
@@ -41,11 +41,11 @@ __RCSID("$NetBSD: localeconv.c,v 1.21 20
 struct lconv *
 localeconv(void)
 {
-	return _current_cache()->ldata;
+	return localeconv_l(_current_locale());
 }
 
 struct lconv *
 localeconv_l(locale_t loc)
 {
-	return loc->cache->ldata;
+	return __UNCONST(&loc->cache->ldata);
 }

Index: src/lib/libc/locale/nb_lc_messages_misc.h
diff -u src/lib/libc/locale/nb_lc_messages_misc.h:1.6 src/lib/libc/locale/nb_lc_messages_misc.h:1.7
--- src/lib/libc/locale/nb_lc_messages_misc.h:1.6	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/nb_lc_messages_misc.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_messages_misc.h,v 1.6 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: nb_lc_messages_misc.h,v 1.7 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -34,14 +34,6 @@
  */
 #define _CATEGORY_TYPE		_MessagesLocale
 
-static __inline void
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict cache,
-    _MessagesLocale * __restrict data)
-{
-	_DIAGASSERT(cache != NULL);
-	_DIAGASSERT(data != NULL);
-}
-
 /* ARGSUSED */
 static __inline void
 _PREFIX(update_global)(_MessagesLocale *data)
Index: src/lib/libc/locale/nb_lc_monetary_misc.h
diff -u src/lib/libc/locale/nb_lc_monetary_misc.h:1.6 src/lib/libc/locale/nb_lc_monetary_misc.h:1.7
--- src/lib/libc/locale/nb_lc_monetary_misc.h:1.6	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/nb_lc_monetary_misc.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_monetary_misc.h,v 1.6 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: nb_lc_monetary_misc.h,v 1.7 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -34,41 +34,6 @@
  */
 #define _CATEGORY_TYPE		_MonetaryLocale
 
-static __inline void
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict cache,
-    _MonetaryLocale * __restrict data)
-{
-	struct lconv *ldata;
-
-	_DIAGASSERT(cache != NULL);
-	_DIAGASSERT(cache->ldata != NULL);
-	_DIAGASSERT(data != NULL);
-
-	ldata = cache->ldata;
-	ldata->int_curr_symbol   = __UNCONST(data->int_curr_symbol);
-	ldata->currency_symbol   = __UNCONST(data->currency_symbol);
-	ldata->mon_decimal_point = __UNCONST(data->mon_decimal_point);
-	ldata->mon_thousands_sep = __UNCONST(data->mon_thousands_sep);
-	ldata->mon_grouping      = __UNCONST(data->mon_grouping);
-	ldata->positive_sign     = __UNCONST(data->positive_sign);
-	ldata->negative_sign     = __UNCONST(data->negative_sign);
-
-	ldata->int_frac_digits    = data->int_frac_digits;
-	ldata->frac_digits        = data->frac_digits;
-	ldata->p_cs_precedes      = data->p_cs_precedes;
-	ldata->p_sep_by_space     = data->p_sep_by_space;
-	ldata->n_cs_precedes      = data->n_cs_precedes;
-	ldata->n_sep_by_space     = data->n_sep_by_space;
-	ldata->p_sign_posn        = data->p_sign_posn;
-	ldata->n_sign_posn        = data->n_sign_posn;
-	ldata->int_p_cs_precedes  = data->int_p_cs_precedes;
-	ldata->int_n_cs_precedes  = data->int_n_cs_precedes;
-	ldata->int_p_sep_by_space = data-> int_p_sep_by_space;
-	ldata->int_n_sep_by_space = data->int_n_sep_by_space;
-	ldata->int_p_sign_posn    = data->int_p_sign_posn;
-	ldata->int_n_sign_posn    = data->int_n_sign_posn;
-}
-
 /* ARGSUSED */
 static __inline void
 _PREFIX(update_global)(_MonetaryLocale *data)
Index: src/lib/libc/locale/nb_lc_numeric_misc.h
diff -u src/lib/libc/locale/nb_lc_numeric_misc.h:1.6 src/lib/libc/locale/nb_lc_numeric_misc.h:1.7
--- src/lib/libc/locale/nb_lc_numeric_misc.h:1.6	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/nb_lc_numeric_misc.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_numeric_misc.h,v 1.6 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: nb_lc_numeric_misc.h,v 1.7 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -34,22 +34,6 @@
  */
 #define _CATEGORY_TYPE		_NumericLocale
 
-static __inline void
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict cache,
-    _NumericLocale * __restrict data)
-{
-	struct lconv *ldata;
-
-	_DIAGASSERT(cache != NULL);
-	_DIAGASSERT(cache->ldata != NULL);
-	_DIAGASSERT(data != NULL);
-
-	ldata = cache->ldata;
-	ldata->decimal_point = __UNCONST(data->decimal_point);
-	ldata->thousands_sep = __UNCONST(data->thousands_sep);
-	ldata->grouping      = __UNCONST(data->grouping);
-}
-
 /* ARGSUSED */
 static __inline void
 _PREFIX(update_global)(_NumericLocale *data)

Index: src/lib/libc/locale/nb_lc_template.h
diff -u src/lib/libc/locale/nb_lc_template.h:1.7 src/lib/libc/locale/nb_lc_template.h:1.8
--- src/lib/libc/locale/nb_lc_template.h:1.7	Sun Aug 18 20:03:48 2013
+++ src/lib/libc/locale/nb_lc_template.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_template.h,v 1.7 2013/08/18 20:03:48 joerg Exp $ */
+/* $NetBSD: nb_lc_template.h,v 1.8 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)1999, 2008 Citrus Project,
@@ -234,7 +234,6 @@ _PREFIX(setlocale)(const char * __restri
 				return NULL;
 			locale->part_name[(size_t)_CATEGORY_ID] = loaded_name;
 			locale->part_impl[(size_t)_CATEGORY_ID] = loaded_impl;
-			_PREFIX(build_cache)(locale->cache, loaded_impl);
 			if (locale == &_lc_global_locale)
 				_PREFIX(update_global)(loaded_impl);
 		}
Index: src/lib/libc/locale/nb_lc_time_misc.h
diff -u src/lib/libc/locale/nb_lc_time_misc.h:1.7 src/lib/libc/locale/nb_lc_time_misc.h:1.8
--- src/lib/libc/locale/nb_lc_time_misc.h:1.7	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/nb_lc_time_misc.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_time_misc.h,v 1.7 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: nb_lc_time_misc.h,v 1.8 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -40,15 +40,6 @@
 #define MON_IDX(idx)	((size_t)idx - (size_t)MON_1)
 #define AM_PM_IDX(idx)	((size_t)idx - (size_t)AM_STR)
 
-static __inline void
-/*ARGSUSED*/
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict cache,
-    _TimeLocale * __restrict data)
-{
-	_DIAGASSERT(cache != NULL);
-	_DIAGASSERT(data != NULL);
-}
-
 /* ARGSUSED */
 static __inline void
 _PREFIX(update_global)(_TimeLocale *data)

Index: src/lib/libc/locale/nb_lc_template_decl.h
diff -u src/lib/libc/locale/nb_lc_template_decl.h:1.3 src/lib/libc/locale/nb_lc_template_decl.h:1.4
--- src/lib/libc/locale/nb_lc_template_decl.h:1.3	Sun Aug 18 20:03:48 2013
+++ src/lib/libc/locale/nb_lc_template_decl.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: nb_lc_template_decl.h,v 1.3 2013/08/18 20:03:48 joerg Exp $ */
+/* $NetBSD: nb_lc_template_decl.h,v 1.4 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -36,10 +36,6 @@ _PREFIX(create_impl)(const char * __rest
     const char * __restrict, _CATEGORY_TYPE ** __restrict);
 
 static __inline void
-_PREFIX(build_cache)(struct _locale_cache_t * __restrict,
-    _CATEGORY_TYPE * __restrict);
-
-static __inline void
 _PREFIX(update_global)(_CATEGORY_TYPE *);
 
 #endif /*_NB_LC_TEMPLATE_DECL_H_*/

Index: src/lib/libc/locale/newlocale.c
diff -u src/lib/libc/locale/newlocale.c:1.2 src/lib/libc/locale/newlocale.c:1.3
--- src/lib/libc/locale/newlocale.c:1.2	Fri May 17 12:55:57 2013
+++ src/lib/libc/locale/newlocale.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: newlocale.c,v 1.2 2013/05/17 12:55:57 joerg Exp $ */
+/* $NetBSD: newlocale.c,v 1.3 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008, 2011 Citrus Project,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: newlocale.c,v 1.2 2013/05/17 12:55:57 joerg Exp $");
+__RCSID("$NetBSD: newlocale.c,v 1.3 2013/09/13 13:13:32 joerg Exp $");
 
 #include "namespace.h"
 #include <assert.h>
@@ -97,5 +97,9 @@ newlocale(int mask, const char *name, lo
 			}
 		}
 	}
+	if (_setlocale_cache(dst, NULL)) {
+		free(dst);
+		return NULL;
+	}
 	return (locale_t)dst;
 }

Index: src/lib/libc/locale/setlocale.c
diff -u src/lib/libc/locale/setlocale.c:1.63 src/lib/libc/locale/setlocale.c:1.64
--- src/lib/libc/locale/setlocale.c:1.63	Fri May 17 12:55:57 2013
+++ src/lib/libc/locale/setlocale.c	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: setlocale.c,v 1.63 2013/05/17 12:55:57 joerg Exp $ */
+/* $NetBSD: setlocale.c,v 1.64 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,10 +28,11 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: setlocale.c,v 1.63 2013/05/17 12:55:57 joerg Exp $");
+__RCSID("$NetBSD: setlocale.c,v 1.64 2013/09/13 13:13:32 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
+#include <sys/localedef.h>
 #include <locale.h>
 #include <limits.h>
 #include <paths.h>
@@ -53,6 +54,76 @@ static _locale_set_t all_categories[_LC_
 	[LC_MESSAGES] = &_citrus_LC_MESSAGES_setlocale,
 };
 
+/* XXX Consider locking the list. Race condition leaks memory. */
+static SLIST_HEAD(, _locale_cache_t) caches = {
+    __UNCONST(&_C_cache)
+};
+
+int
+_setlocale_cache(locale_t loc, struct _locale_cache_t *cache)
+{
+	const char *monetary_name = loc->part_name[LC_MONETARY];
+	const char *numeric_name = loc->part_name[LC_NUMERIC];
+	_NumericLocale *numeric = loc->part_impl[LC_NUMERIC];
+	_MonetaryLocale *monetary = loc->part_impl[LC_MONETARY];
+	struct lconv *ldata;
+
+	struct _locale_cache_t *old_cache;
+
+	SLIST_FOREACH(old_cache, &caches, cache_link) {
+		if (monetary_name != old_cache->monetary_name &&
+		    strcmp(monetary_name, old_cache->monetary_name) != 0)
+			continue;
+		if (numeric_name != old_cache->numeric_name &&
+		    strcmp(numeric_name, old_cache->numeric_name) != 0)
+			continue;
+		loc->cache = old_cache;
+		free(cache);
+		return 0;
+	}
+
+	if (cache == NULL) {
+		cache = malloc(sizeof(*cache));
+		if (cache == NULL)
+			return -1;
+	}
+
+	cache->monetary_name = monetary_name;
+	cache->numeric_name = numeric_name;
+	ldata = &cache->ldata;
+
+	ldata->decimal_point = __UNCONST(numeric->decimal_point);
+	ldata->thousands_sep = __UNCONST(numeric->thousands_sep);
+	ldata->grouping      = __UNCONST(numeric->grouping);
+
+	ldata->int_curr_symbol   = __UNCONST(monetary->int_curr_symbol);
+	ldata->currency_symbol   = __UNCONST(monetary->currency_symbol);
+	ldata->mon_decimal_point = __UNCONST(monetary->mon_decimal_point);
+	ldata->mon_thousands_sep = __UNCONST(monetary->mon_thousands_sep);
+	ldata->mon_grouping      = __UNCONST(monetary->mon_grouping);
+	ldata->positive_sign     = __UNCONST(monetary->positive_sign);
+	ldata->negative_sign     = __UNCONST(monetary->negative_sign);
+
+	ldata->int_frac_digits    = monetary->int_frac_digits;
+	ldata->frac_digits        = monetary->frac_digits;
+	ldata->p_cs_precedes      = monetary->p_cs_precedes;
+	ldata->p_sep_by_space     = monetary->p_sep_by_space;
+	ldata->n_cs_precedes      = monetary->n_cs_precedes;
+	ldata->n_sep_by_space     = monetary->n_sep_by_space;
+	ldata->p_sign_posn        = monetary->p_sign_posn;
+	ldata->n_sign_posn        = monetary->n_sign_posn;
+	ldata->int_p_cs_precedes  = monetary->int_p_cs_precedes;
+	ldata->int_n_cs_precedes  = monetary->int_n_cs_precedes;
+	ldata->int_p_sep_by_space = monetary-> int_p_sep_by_space;
+	ldata->int_n_sep_by_space = monetary->int_n_sep_by_space;
+	ldata->int_p_sign_posn    = monetary->int_p_sign_posn;
+	ldata->int_n_sign_posn    = monetary->int_n_sign_posn;
+	SLIST_INSERT_HEAD(&caches, cache, cache_link);
+
+	loc->cache = cache;
+	return 0;
+}
+
 _locale_set_t
 _find_category(int category)
 {
@@ -96,13 +167,20 @@ char *
 __setlocale(int category, const char *name)
 {
 	_locale_set_t sl;
-	struct _locale *impl;
+	locale_t loc;
+	struct _locale_cache_t *cache;
+	const char *result;
 
 	sl = _find_category(category);
 	if (sl == NULL)
 		return NULL;
-	impl = _current_locale();
-	return __UNCONST((*sl)(name, impl));
+	cache = malloc(sizeof(*cache));
+	if (cache == NULL)
+		return NULL;
+	loc = _current_locale();
+	result = (*sl)(name, loc);
+	_setlocale_cache(loc, cache);
+	return __UNCONST(result);
 }
 
 char *

Index: src/lib/libc/locale/setlocale_local.h
diff -u src/lib/libc/locale/setlocale_local.h:1.14 src/lib/libc/locale/setlocale_local.h:1.15
--- src/lib/libc/locale/setlocale_local.h:1.14	Tue Aug 20 19:58:30 2013
+++ src/lib/libc/locale/setlocale_local.h	Fri Sep 13 13:13:32 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: setlocale_local.h,v 1.14 2013/08/20 19:58:30 joerg Exp $ */
+/* $NetBSD: setlocale_local.h,v 1.15 2013/09/13 13:13:32 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -29,6 +29,9 @@
 #ifndef _SETLOCALE_LOCAL_H_
 #define _SETLOCALE_LOCAL_H_
 
+#include <sys/queue.h>
+#include <locale.h>
+
 #include "ctype_local.h"
 
 #define _LOCALENAME_LEN_MAX 33
@@ -42,11 +45,14 @@ extern const char		*_PathLocale;
 typedef void *_locale_part_t;
 
 struct _locale_cache_t {
-	struct lconv *ldata;
+	SLIST_ENTRY(_locale_cache_t) cache_link;
+	const char *monetary_name;
+	const char *numeric_name;
+	struct lconv ldata;
 };
 
 struct _locale {
-	struct _locale_cache_t *cache;
+	const struct _locale_cache_t *cache;
 	char query[_LOCALENAME_LEN_MAX * (_LC_LAST - 1)];
 	const char *part_name[_LC_LAST];
 	_locale_part_t part_impl[_LC_LAST];
@@ -74,22 +80,19 @@ const char *_citrus_LC_TIME_setlocale(
     const char * __restrict, struct _locale * __restrict);
 const char *_citrus_LC_MESSAGES_setlocale(
     const char * __restrict, struct _locale * __restrict);
+
+int _setlocale_cache(locale_t, struct _locale_cache_t *);
 __END_DECLS
 
 #ifdef _LIBC
 extern __dso_protected struct _locale	_lc_global_locale;
+extern __dso_hidden const struct _locale_cache_t _C_cache;
 
 static __inline struct _locale *
 _current_locale(void)
 {
 	return &_lc_global_locale;
 }
-
-static __inline struct _locale_cache_t *
-_current_cache(void)
-{
-	return _lc_global_locale.cache;
-}
 #endif
 
 extern size_t __mb_len_max_runtime;

Reply via email to