--- old/usr/src/lib/libc/port/locale/lmonetary.c	Tue May 20 07:58:48 2014
+++ new/usr/src/lib/libc/port/locale/lmonetary.c	Tue May 20 07:58:48 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
  * All rights reserved.
@@ -29,20 +30,23 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
 #include "ldpart.h"
 #include "lmonetary.h"
+#include "localeimpl.h"
 
-extern int __mlocale_changed;
 extern const char *__fix_locale_grouping_str(const char *);
 
-#define	LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary_T) / sizeof (char *))
+#define	LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary) / sizeof (char *))
 #define	LCMONETARY_SIZE_MIN \
-	(offsetof(struct lc_monetary_T, int_p_cs_precedes) / sizeof (char *))
+	(offsetof(struct lc_monetary, int_p_cs_precedes) / sizeof (char *))
 
 static char	empty[] = "";
 static char	numempty[] = { CHAR_MAX, '\0' };
 
-static const struct lc_monetary_T _C_monetary_locale = {
+struct lc_monetary lc_monetary_posix = {
 	empty,		/* int_curr_symbol */
 	empty,		/* currency_symbol */
 	empty,		/* mon_decimal_point */
@@ -63,12 +67,15 @@
 	numempty,	/* int_p_sep_by_space */
 	numempty,	/* int_n_sep_by_space */
 	numempty,	/* int_p_sign_posn */
-	numempty	/* int_n_sign_posn */
+	numempty,	/* int_n_sign_posn */
+	empty		/* crncystr */
 };
 
-static struct lc_monetary_T _monetary_locale;
-static int	_monetary_using_locale;
-static char	*_monetary_locale_buf;
+struct locdata __posix_monetary_locdata = {
+	.l_lname = "C",
+	.l_refcnt = (uint32_t)-1,
+	.l_data = { &lc_monetary_posix }
+};
 
 static char
 cnv(const char *str)
@@ -80,59 +87,94 @@
 	return ((char)i);
 }
 
-int
-__monetary_load_locale(const char *name)
+struct locdata *
+__lc_monetary_load(const char *name)
 {
 	int ret;
+	int clen;
+	struct lc_monetary	*lmon;
+	struct locdata		*ldata;
 
-	ret = __part_load_locale(name, &_monetary_using_locale,
-	    &_monetary_locale_buf, "LC_MONETARY",
-	    LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
-	    (const char **)&_monetary_locale);
-	if (ret != _LDP_ERROR)
-		__mlocale_changed = 1;
-	if (ret == _LDP_LOADED) {
-		_monetary_locale.mon_grouping =
-		    __fix_locale_grouping_str(_monetary_locale.mon_grouping);
+	if ((ldata = __locdata_alloc(name, sizeof (*lmon))) == NULL) {
+		return (NULL);
+	}
+	lmon = ldata->l_data[0];
 
+	ret = __part_load_locale(name, (char **)&ldata->l_data[1],
+	    "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
+	    (const char **)lmon);
+
+	if (ret != _LDP_LOADED) {
+		__locdata_release(ldata);
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	/* special storage for currency string */
+	clen = strlen(lmon->currency_symbol) + 2;
+	ldata->l_data[2] = malloc(clen);
+	lmon->crncystr = ldata->l_data[2];
+	lmon->crncystr[0] = '\0';
+
+	lmon->mon_grouping = __fix_locale_grouping_str(lmon->mon_grouping);
+
 #define	M_ASSIGN_CHAR(NAME) \
-		(((char *)_monetary_locale.NAME)[0] = \
-			cnv(_monetary_locale.NAME))
+	(((char *)lmon->NAME)[0] = cnv(lmon->NAME))
 
-		M_ASSIGN_CHAR(int_frac_digits);
-		M_ASSIGN_CHAR(frac_digits);
-		M_ASSIGN_CHAR(p_cs_precedes);
-		M_ASSIGN_CHAR(p_sep_by_space);
-		M_ASSIGN_CHAR(n_cs_precedes);
-		M_ASSIGN_CHAR(n_sep_by_space);
-		M_ASSIGN_CHAR(p_sign_posn);
-		M_ASSIGN_CHAR(n_sign_posn);
+	M_ASSIGN_CHAR(int_frac_digits);
+	M_ASSIGN_CHAR(frac_digits);
+	M_ASSIGN_CHAR(p_cs_precedes);
+	M_ASSIGN_CHAR(p_sep_by_space);
+	M_ASSIGN_CHAR(n_cs_precedes);
+	M_ASSIGN_CHAR(n_sep_by_space);
+	M_ASSIGN_CHAR(p_sign_posn);
+	M_ASSIGN_CHAR(n_sign_posn);
 
-		/*
-		 * The six additional C99 international monetary formatting
-		 * parameters default to the national parameters when
-		 * reading FreeBSD LC_MONETARY data files.
-		 */
-#define	M_ASSIGN_ICHAR(NAME)					\
-		if (_monetary_locale.int_##NAME == NULL)	\
-			_monetary_locale.int_##NAME =		\
-			    _monetary_locale.NAME;		\
-		else						\
-			M_ASSIGN_CHAR(int_##NAME);
+	/*
+	 * The six additional C99 international monetary formatting
+	 * parameters default to the national parameters when
+	 * reading FreeBSD LC_MONETARY data files.
+	 */
+#define	M_ASSIGN_ICHAR(NAME)				\
+	if (lmon->int_##NAME == NULL)			\
+		lmon->int_##NAME = lmon->NAME;		\
+	else						\
+		M_ASSIGN_CHAR(int_##NAME);
 
-		M_ASSIGN_ICHAR(p_cs_precedes);
-		M_ASSIGN_ICHAR(n_cs_precedes);
-		M_ASSIGN_ICHAR(p_sep_by_space);
-		M_ASSIGN_ICHAR(n_sep_by_space);
-		M_ASSIGN_ICHAR(p_sign_posn);
-		M_ASSIGN_ICHAR(n_sign_posn);
+	M_ASSIGN_ICHAR(p_cs_precedes);
+	M_ASSIGN_ICHAR(n_cs_precedes);
+	M_ASSIGN_ICHAR(p_sep_by_space);
+	M_ASSIGN_ICHAR(n_sep_by_space);
+	M_ASSIGN_ICHAR(p_sign_posn);
+	M_ASSIGN_ICHAR(n_sign_posn);
+
+	/*
+	 * Now calculate the currency string (CRNCYSTR) for nl_langinfo.
+	 * This is a legacy SUSv2 interface.
+	 */
+	if ((lmon->p_cs_precedes[0] == lmon->n_cs_precedes[0]) &&
+	    (lmon->currency_symbol[0] != '\0')) {
+		char sign = '\0';
+		switch (lmon->p_cs_precedes[0]) {
+		case 0:
+			sign = '-';
+			break;
+		case 1:
+			sign = '+';
+			break;
+		case CHAR_MAX:
+			/*
+			 * Substitute currency string for radix character.
+			 * To the best of my knowledge, no locale uses this.
+			 */
+			if (strcmp(lmon->mon_decimal_point,
+			    lmon->currency_symbol) == 0)
+				sign = '.';
+			break;
+		}
+		(void) snprintf(lmon->crncystr, clen, "%c%s", sign,
+		    lmon->currency_symbol);
 	}
-	return (ret);
-}
 
-struct lc_monetary_T *
-__get_current_monetary_locale(void)
-{
-	return (_monetary_using_locale ? &_monetary_locale :
-	    (struct lc_monetary_T *)&_C_monetary_locale);
+	return (ldata);
 }
