1/* 2 * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: src/lib/libc/locale/lmonetary.c,v 1.19 2003/06/26 10:46:16 phantom Exp $"); 29 30#include "xlocale_private.h" 31 32#include <limits.h> 33#include <stddef.h> 34#include <stdlib.h> 35#include <string.h> 36 37#include "ldpart.h" 38#include "lmonetary.h" 39 40extern const char * __fix_locale_grouping_str(const char *); 41 42#define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *)) 43#define LCMONETARY_SIZE_MIN \ 44 (offsetof(struct lc_monetary_T, int_p_cs_precedes) / \ 45 sizeof(char *)) 46 47static char empty[] = ""; 48static char numempty[] = { CHAR_MAX, '\0'}; 49 50static const struct lc_monetary_T _C_monetary_locale = { 51 empty, /* int_curr_symbol */ 52 empty, /* currency_symbol */ 53 empty, /* mon_decimal_point */ 54 empty, /* mon_thousands_sep */ 55 empty, /* mon_grouping [C99 7.11.2.1]*/ 56 empty, /* positive_sign */ 57 empty, /* negative_sign */ 58 numempty, /* int_frac_digits */ 59 numempty, /* frac_digits */ 60 numempty, /* p_cs_precedes */ 61 numempty, /* p_sep_by_space */ 62 numempty, /* n_cs_precedes */ 63 numempty, /* n_sep_by_space */ 64 numempty, /* p_sign_posn */ 65 numempty, /* n_sign_posn */ 66 numempty, /* int_p_cs_precedes */ 67 numempty, /* int_n_cs_precedes */ 68 numempty, /* int_p_sep_by_space */ 69 numempty, /* int_n_sep_by_space */ 70 numempty, /* int_p_sign_posn */ 71 numempty /* int_n_sign_posn */ 72}; 73 74static char 75cnv(const char *str) 76{ 77 int i = strtol(str, NULL, 10); 78 79 if (i == -1) 80 i = CHAR_MAX; 81 return ((char)i); 82} 83 84__private_extern__ int 85__monetary_load_locale(const char *name, locale_t loc) 86{ 87 int ret; 88 struct __xlocale_st_monetary *xp; 89 static struct __xlocale_st_monetary *cache = NULL; 90 91 /* 'name' must be already checked. */ 92 if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) { 93 if (!loc->_monetary_using_locale) 94 return (_LDP_CACHE); 95 loc->_monetary_using_locale = 0; 96 XL_RELEASE(loc->__lc_monetary); 97 loc->__lc_monetary = NULL; 98 loc->__mlocale_changed = 1; 99 return (_LDP_CACHE); 100 } 101 102 if (loc->_monetary_using_locale && strcmp(name, loc->__lc_monetary->_monetary_locale_buf) == 0) 103 return (_LDP_CACHE); 104 /* 105 * If the locale name is the same as our cache, use the cache. 106 */ 107 if (cache && cache->_monetary_locale_buf && strcmp(name, cache->_monetary_locale_buf) == 0) { 108 loc->_monetary_using_locale = 1; 109 XL_RELEASE(loc->__lc_monetary); 110 loc->__lc_monetary = cache; 111 XL_RETAIN(loc->__lc_monetary); 112 loc->__mlocale_changed = 1; 113 return (_LDP_CACHE); 114 } 115 if ((xp = (struct __xlocale_st_monetary *)malloc(sizeof(*xp))) == NULL) 116 return _LDP_ERROR; 117 xp->__refcount = 1; 118 xp->__free_extra = (__free_extra_t)__ldpart_free_extra; 119 xp->_monetary_locale_buf = NULL; 120 121 ret = __part_load_locale(name, &loc->_monetary_using_locale, 122 &xp->_monetary_locale_buf, "LC_MONETARY", 123 LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN, 124 (const char **)&xp->_monetary_locale); 125 if (ret != _LDP_ERROR) 126 loc->__mlocale_changed = 1; 127 else 128 free(xp); 129 if (ret == _LDP_LOADED) { 130 xp->_monetary_locale.mon_grouping = 131 __fix_locale_grouping_str(xp->_monetary_locale.mon_grouping); 132 133#define M_ASSIGN_CHAR(NAME) (((char *)xp->_monetary_locale.NAME)[0] = \ 134 cnv(xp->_monetary_locale.NAME)) 135 136 M_ASSIGN_CHAR(int_frac_digits); 137 M_ASSIGN_CHAR(frac_digits); 138 M_ASSIGN_CHAR(p_cs_precedes); 139 M_ASSIGN_CHAR(p_sep_by_space); 140 M_ASSIGN_CHAR(n_cs_precedes); 141 M_ASSIGN_CHAR(n_sep_by_space); 142 M_ASSIGN_CHAR(p_sign_posn); 143 M_ASSIGN_CHAR(n_sign_posn); 144 145 /* 146 * The six additional C99 international monetary formatting 147 * parameters default to the national parameters when 148 * reading FreeBSD LC_MONETARY data files. 149 */ 150#define M_ASSIGN_ICHAR(NAME) \ 151 do { \ 152 if (xp->_monetary_locale.int_##NAME == NULL) \ 153 xp->_monetary_locale.int_##NAME = \ 154 xp->_monetary_locale.NAME; \ 155 else \ 156 M_ASSIGN_CHAR(int_##NAME); \ 157 } while (0) 158 159 M_ASSIGN_ICHAR(p_cs_precedes); 160 M_ASSIGN_ICHAR(n_cs_precedes); 161 M_ASSIGN_ICHAR(p_sep_by_space); 162 M_ASSIGN_ICHAR(n_sep_by_space); 163 M_ASSIGN_ICHAR(p_sign_posn); 164 M_ASSIGN_ICHAR(n_sign_posn); 165 XL_RELEASE(loc->__lc_monetary); 166 loc->__lc_monetary = xp; 167 XL_RELEASE(cache); 168 cache = xp; 169 XL_RETAIN(cache); 170 } 171 return (ret); 172} 173 174__private_extern__ struct lc_monetary_T * 175__get_current_monetary_locale(locale_t loc) 176{ 177 return (loc->_monetary_using_locale 178 ? &loc->__lc_monetary->_monetary_locale 179 : (struct lc_monetary_T *)&_C_monetary_locale); 180} 181 182#ifdef LOCALE_DEBUG 183void 184monetdebug() { 185locale_t loc = __current_locale(); 186printf( "int_curr_symbol = %s\n" 187 "currency_symbol = %s\n" 188 "mon_decimal_point = %s\n" 189 "mon_thousands_sep = %s\n" 190 "mon_grouping = %s\n" 191 "positive_sign = %s\n" 192 "negative_sign = %s\n" 193 "int_frac_digits = %d\n" 194 "frac_digits = %d\n" 195 "p_cs_precedes = %d\n" 196 "p_sep_by_space = %d\n" 197 "n_cs_precedes = %d\n" 198 "n_sep_by_space = %d\n" 199 "p_sign_posn = %d\n" 200 "n_sign_posn = %d\n", 201 "int_p_cs_precedes = %d\n" 202 "int_p_sep_by_space = %d\n" 203 "int_n_cs_precedes = %d\n" 204 "int_n_sep_by_space = %d\n" 205 "int_p_sign_posn = %d\n" 206 "int_n_sign_posn = %d\n", 207 loc->__lc_monetary->_monetary_locale.int_curr_symbol, 208 loc->__lc_monetary->_monetary_locale.currency_symbol, 209 loc->__lc_monetary->_monetary_locale.mon_decimal_point, 210 loc->__lc_monetary->_monetary_locale.mon_thousands_sep, 211 loc->__lc_monetary->_monetary_locale.mon_grouping, 212 loc->__lc_monetary->_monetary_locale.positive_sign, 213 loc->__lc_monetary->_monetary_locale.negative_sign, 214 loc->__lc_monetary->_monetary_locale.int_frac_digits[0], 215 loc->__lc_monetary->_monetary_locale.frac_digits[0], 216 loc->__lc_monetary->_monetary_locale.p_cs_precedes[0], 217 loc->__lc_monetary->_monetary_locale.p_sep_by_space[0], 218 loc->__lc_monetary->_monetary_locale.n_cs_precedes[0], 219 loc->__lc_monetary->_monetary_locale.n_sep_by_space[0], 220 loc->__lc_monetary->_monetary_locale.p_sign_posn[0], 221 loc->__lc_monetary->_monetary_locale.n_sign_posn[0], 222 loc->__lc_monetary->_monetary_locale.int_p_cs_precedes[0], 223 loc->__lc_monetary->_monetary_locale.int_p_sep_by_space[0], 224 loc->__lc_monetary->_monetary_locale.int_n_cs_precedes[0], 225 loc->__lc_monetary->_monetary_locale.int_n_sep_by_space[0], 226 loc->__lc_monetary->_monetary_locale.int_p_sign_posn[0], 227 loc->__lc_monetary->_monetary_locale.int_n_sign_posn[0] 228); 229} 230#endif /* LOCALE_DEBUG */ 231