Print this page
2964 need POSIX 2008 locale object support
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Approved by: TBD

@@ -1,6 +1,7 @@
 /*
+ * 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.
  *
  * Redistribution and use in source and binary forms, with or without

@@ -27,24 +28,27 @@
 
 #include "lint.h"
 #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 */
         empty,          /* mon_thousands_sep */
         numempty,       /* mon_grouping */

@@ -61,16 +65,19 @@
         numempty,       /* int_p_cs_precedes */
         numempty,       /* int_n_cs_precedes */
         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)
 {
         int i = strtol(str, NULL, 10);

@@ -78,28 +85,43 @@
         if (i == -1)
                 i = CHAR_MAX;
         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);

@@ -112,27 +134,47 @@
                  * 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;              \
+        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);
+
+        /*
+         * 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;
         }
-        return (ret);
-}
+                (void) snprintf(lmon->crncystr, clen, "%c%s", sign,
+                    lmon->currency_symbol);
+        }
 
-struct lc_monetary_T *
-__get_current_monetary_locale(void)
-{
-        return (_monetary_using_locale ? &_monetary_locale :
-            (struct lc_monetary_T *)&_C_monetary_locale);
+        return (ldata);
 }