xref: /freebsd/lib/libc/locale/lmonetary.c (revision 5b5fa75acff11d871d0c90045f8c1a58fed85365)
1d915a14eSPedro F. Giffuni /*-
2d915a14eSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3d915a14eSPedro F. Giffuni  *
474f2b975SAlexey Zelkin  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
590423eceSAlexey Zelkin  * All rights reserved.
690423eceSAlexey Zelkin  *
73c87aa1dSDavid Chisnall  * Copyright (c) 2011 The FreeBSD Foundation
8*5b5fa75aSEd Maste  *
93c87aa1dSDavid Chisnall  * Portions of this software were developed by David Chisnall
103c87aa1dSDavid Chisnall  * under sponsorship from the FreeBSD Foundation.
113c87aa1dSDavid Chisnall  *
1290423eceSAlexey Zelkin  * Redistribution and use in source and binary forms, with or without
1390423eceSAlexey Zelkin  * modification, are permitted provided that the following conditions
1490423eceSAlexey Zelkin  * are met:
1590423eceSAlexey Zelkin  * 1. Redistributions of source code must retain the above copyright
1690423eceSAlexey Zelkin  *    notice, this list of conditions and the following disclaimer.
1790423eceSAlexey Zelkin  * 2. Redistributions in binary form must reproduce the above copyright
1890423eceSAlexey Zelkin  *    notice, this list of conditions and the following disclaimer in the
1990423eceSAlexey Zelkin  *    documentation and/or other materials provided with the distribution.
2090423eceSAlexey Zelkin  *
2190423eceSAlexey Zelkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2290423eceSAlexey Zelkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2390423eceSAlexey Zelkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2490423eceSAlexey Zelkin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2590423eceSAlexey Zelkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2690423eceSAlexey Zelkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2790423eceSAlexey Zelkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2890423eceSAlexey Zelkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2990423eceSAlexey Zelkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3090423eceSAlexey Zelkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3190423eceSAlexey Zelkin  * SUCH DAMAGE.
3290423eceSAlexey Zelkin  */
3390423eceSAlexey Zelkin 
34333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
35333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
36333fc21eSDavid E. O'Brien 
371bd7723dSAlexey Zelkin #include <limits.h>
38f4da1a75STim J. Robbins #include <stddef.h>
39831e8f61SAndrey A. Chernov #include <stdlib.h>
40683fe113SAlexey Zelkin 
4190423eceSAlexey Zelkin #include "ldpart.h"
42683fe113SAlexey Zelkin #include "lmonetary.h"
4390423eceSAlexey Zelkin 
441bd7723dSAlexey Zelkin extern const char * __fix_locale_grouping_str(const char *);
4590423eceSAlexey Zelkin 
468a093dadSAndrey A. Chernov #define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *))
478a093dadSAndrey A. Chernov #define LCMONETARY_SIZE_MIN \
488a093dadSAndrey A. Chernov 		(offsetof(struct lc_monetary_T, int_p_cs_precedes) / \
498a093dadSAndrey A. Chernov 		    sizeof(char *))
5090423eceSAlexey Zelkin 
5190423eceSAlexey Zelkin static char	empty[] = "";
521bd7723dSAlexey Zelkin static char	numempty[] = { CHAR_MAX, '\0'};
5390423eceSAlexey Zelkin 
5490423eceSAlexey Zelkin static const struct lc_monetary_T _C_monetary_locale = {
5590423eceSAlexey Zelkin 	empty,		/* int_curr_symbol */
5690423eceSAlexey Zelkin 	empty,		/* currency_symbol */
5754e3bc25SAndrey A. Chernov 	empty,		/* mon_decimal_point */
5890423eceSAlexey Zelkin 	empty,		/* mon_thousands_sep */
5990423eceSAlexey Zelkin 	numempty,	/* mon_grouping */
6090423eceSAlexey Zelkin 	empty,		/* positive_sign */
6190423eceSAlexey Zelkin 	empty,		/* negative_sign */
6290423eceSAlexey Zelkin 	numempty,	/* int_frac_digits */
6390423eceSAlexey Zelkin 	numempty,	/* frac_digits */
6490423eceSAlexey Zelkin 	numempty,	/* p_cs_precedes */
6590423eceSAlexey Zelkin 	numempty,	/* p_sep_by_space */
6690423eceSAlexey Zelkin 	numempty,	/* n_cs_precedes */
6790423eceSAlexey Zelkin 	numempty,	/* n_sep_by_space */
6890423eceSAlexey Zelkin 	numempty,	/* p_sign_posn */
69f4da1a75STim J. Robbins 	numempty,	/* n_sign_posn */
70f4da1a75STim J. Robbins 	numempty,	/* int_p_cs_precedes */
71f4da1a75STim J. Robbins 	numempty,	/* int_n_cs_precedes */
72f4da1a75STim J. Robbins 	numempty,	/* int_p_sep_by_space */
73f4da1a75STim J. Robbins 	numempty,	/* int_n_sep_by_space */
74f4da1a75STim J. Robbins 	numempty,	/* int_p_sign_posn */
75f4da1a75STim J. Robbins 	numempty	/* int_n_sign_posn */
7690423eceSAlexey Zelkin };
7790423eceSAlexey Zelkin 
783c87aa1dSDavid Chisnall struct xlocale_monetary __xlocale_global_monetary;
7990423eceSAlexey Zelkin 
80831e8f61SAndrey A. Chernov static char
81ecc4c620SAndrey A. Chernov cnv(const char *str)
82ecc4c620SAndrey A. Chernov {
83831e8f61SAndrey A. Chernov 	int i = strtol(str, NULL, 10);
84ecc4c620SAndrey A. Chernov 
85831e8f61SAndrey A. Chernov 	if (i == -1)
86831e8f61SAndrey A. Chernov 		i = CHAR_MAX;
87ecc4c620SAndrey A. Chernov 	return ((char)i);
88831e8f61SAndrey A. Chernov }
89831e8f61SAndrey A. Chernov 
903c87aa1dSDavid Chisnall static void
913c87aa1dSDavid Chisnall destruct_monetary(void *v)
923c87aa1dSDavid Chisnall {
933c87aa1dSDavid Chisnall 	struct xlocale_monetary *l = v;
943c87aa1dSDavid Chisnall 	if (l->buffer)
953c87aa1dSDavid Chisnall 		free(l->buffer);
963c87aa1dSDavid Chisnall 	free(l);
973c87aa1dSDavid Chisnall }
983c87aa1dSDavid Chisnall 
993c87aa1dSDavid Chisnall static int
1003c87aa1dSDavid Chisnall monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
1013c87aa1dSDavid Chisnall     int *changed, const char *name)
102ecc4c620SAndrey A. Chernov {
10390423eceSAlexey Zelkin 	int ret;
1043c87aa1dSDavid Chisnall 	struct lc_monetary_T *l = &loc->locale;
105ecc4c620SAndrey A. Chernov 
1063c87aa1dSDavid Chisnall 	ret = __part_load_locale(name, using_locale,
1073c87aa1dSDavid Chisnall 	    &loc->buffer, "LC_MONETARY",
1088a093dadSAndrey A. Chernov 	    LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
1093c87aa1dSDavid Chisnall 	    (const char **)l);
11076692b80SAndrey A. Chernov 	if (ret == _LDP_LOADED) {
1113c87aa1dSDavid Chisnall 		l->mon_grouping =
1123c87aa1dSDavid Chisnall 		     __fix_locale_grouping_str(l->mon_grouping);
113831e8f61SAndrey A. Chernov 
1143c87aa1dSDavid Chisnall #define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \
1153c87aa1dSDavid Chisnall 			     cnv(l->NAME))
116831e8f61SAndrey A. Chernov 
117831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(int_frac_digits);
118831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(frac_digits);
119831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(p_cs_precedes);
120831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(p_sep_by_space);
121831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(n_cs_precedes);
122831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(n_sep_by_space);
123831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(p_sign_posn);
124831e8f61SAndrey A. Chernov 		M_ASSIGN_CHAR(n_sign_posn);
125f4da1a75STim J. Robbins 
126f4da1a75STim J. Robbins 		/*
127f4da1a75STim J. Robbins 		 * The six additional C99 international monetary formatting
128f4da1a75STim J. Robbins 		 * parameters default to the national parameters when
129683fe113SAlexey Zelkin 		 * reading FreeBSD LC_MONETARY data files.
130f4da1a75STim J. Robbins 		 */
131f4da1a75STim J. Robbins #define	M_ASSIGN_ICHAR(NAME)						\
132f4da1a75STim J. Robbins 		do {							\
1333c87aa1dSDavid Chisnall 			if (l->int_##NAME == NULL)	\
1343c87aa1dSDavid Chisnall 				l->int_##NAME =		\
1353c87aa1dSDavid Chisnall 				    l->NAME;		\
136f4da1a75STim J. Robbins 			else						\
137f4da1a75STim J. Robbins 				M_ASSIGN_CHAR(int_##NAME);		\
138f4da1a75STim J. Robbins 		} while (0)
139f4da1a75STim J. Robbins 
140f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(p_cs_precedes);
141f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(n_cs_precedes);
142f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(p_sep_by_space);
143f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(n_sep_by_space);
144f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(p_sign_posn);
145f4da1a75STim J. Robbins 		M_ASSIGN_ICHAR(n_sign_posn);
146831e8f61SAndrey A. Chernov 	}
1477eb138a9SMark Johnston 	if (ret != _LDP_ERROR)
1487eb138a9SMark Johnston 		atomic_store_rel_int(changed, 1);
149ecc4c620SAndrey A. Chernov 	return (ret);
15090423eceSAlexey Zelkin }
1510fed1e6fSKonstantin Belousov 
1523c87aa1dSDavid Chisnall int
1533c87aa1dSDavid Chisnall __monetary_load_locale(const char *name)
1543c87aa1dSDavid Chisnall {
1550fed1e6fSKonstantin Belousov 	return (monetary_load_locale_l(&__xlocale_global_monetary,
1563c87aa1dSDavid Chisnall 	    &__xlocale_global_locale.using_monetary_locale,
1570fed1e6fSKonstantin Belousov 	    &__xlocale_global_locale.monetary_locale_changed, name));
1583c87aa1dSDavid Chisnall }
1593c87aa1dSDavid Chisnall 
1600fed1e6fSKonstantin Belousov void *
1610fed1e6fSKonstantin Belousov __monetary_load(const char *name, locale_t l)
1620fed1e6fSKonstantin Belousov {
1630fed1e6fSKonstantin Belousov 	struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary),
1640fed1e6fSKonstantin Belousov 	    1);
1654d3b84f6SKonstantin Belousov 	if (new == NULL)
1664d3b84f6SKonstantin Belousov 		return (NULL);
1670fed1e6fSKonstantin Belousov 	new->header.header.destructor = destruct_monetary;
1680fed1e6fSKonstantin Belousov 	if (monetary_load_locale_l(new, &l->using_monetary_locale,
1690fed1e6fSKonstantin Belousov 	    &l->monetary_locale_changed, name) == _LDP_ERROR) {
1700fed1e6fSKonstantin Belousov 		xlocale_release(new);
1710fed1e6fSKonstantin Belousov 		return (NULL);
1720fed1e6fSKonstantin Belousov 	}
1730fed1e6fSKonstantin Belousov 	return (new);
1740fed1e6fSKonstantin Belousov }
17590423eceSAlexey Zelkin 
17690423eceSAlexey Zelkin struct lc_monetary_T *
1773c87aa1dSDavid Chisnall __get_current_monetary_locale(locale_t loc)
178ecc4c620SAndrey A. Chernov {
1790fed1e6fSKonstantin Belousov 	return (loc->using_monetary_locale ?
1800fed1e6fSKonstantin Belousov 	    &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale :
1810fed1e6fSKonstantin Belousov 	    (struct lc_monetary_T *)&_C_monetary_locale);
18290423eceSAlexey Zelkin }
18390423eceSAlexey Zelkin 
18490423eceSAlexey Zelkin #ifdef LOCALE_DEBUG
18590423eceSAlexey Zelkin void
1860fed1e6fSKonstantin Belousov monetdebug(void) {
18790423eceSAlexey Zelkin printf(	"int_curr_symbol = %s\n"
18890423eceSAlexey Zelkin 	"currency_symbol = %s\n"
18990423eceSAlexey Zelkin 	"mon_decimal_point = %s\n"
19090423eceSAlexey Zelkin 	"mon_thousands_sep = %s\n"
19190423eceSAlexey Zelkin 	"mon_grouping = %s\n"
19290423eceSAlexey Zelkin 	"positive_sign = %s\n"
19390423eceSAlexey Zelkin 	"negative_sign = %s\n"
194831e8f61SAndrey A. Chernov 	"int_frac_digits = %d\n"
195831e8f61SAndrey A. Chernov 	"frac_digits = %d\n"
196831e8f61SAndrey A. Chernov 	"p_cs_precedes = %d\n"
197831e8f61SAndrey A. Chernov 	"p_sep_by_space = %d\n"
198831e8f61SAndrey A. Chernov 	"n_cs_precedes = %d\n"
199831e8f61SAndrey A. Chernov 	"n_sep_by_space = %d\n"
200831e8f61SAndrey A. Chernov 	"p_sign_posn = %d\n"
2019908eab8SPedro F. Giffuni 	"n_sign_posn = %d\n"
202683fe113SAlexey Zelkin 	"int_p_cs_precedes = %d\n"
203683fe113SAlexey Zelkin 	"int_p_sep_by_space = %d\n"
204683fe113SAlexey Zelkin 	"int_n_cs_precedes = %d\n"
205683fe113SAlexey Zelkin 	"int_n_sep_by_space = %d\n"
206683fe113SAlexey Zelkin 	"int_p_sign_posn = %d\n"
207683fe113SAlexey Zelkin 	"int_n_sign_posn = %d\n",
20890423eceSAlexey Zelkin 	_monetary_locale.int_curr_symbol,
20990423eceSAlexey Zelkin 	_monetary_locale.currency_symbol,
21090423eceSAlexey Zelkin 	_monetary_locale.mon_decimal_point,
21190423eceSAlexey Zelkin 	_monetary_locale.mon_thousands_sep,
21290423eceSAlexey Zelkin 	_monetary_locale.mon_grouping,
21390423eceSAlexey Zelkin 	_monetary_locale.positive_sign,
21490423eceSAlexey Zelkin 	_monetary_locale.negative_sign,
215831e8f61SAndrey A. Chernov 	_monetary_locale.int_frac_digits[0],
216831e8f61SAndrey A. Chernov 	_monetary_locale.frac_digits[0],
217831e8f61SAndrey A. Chernov 	_monetary_locale.p_cs_precedes[0],
218831e8f61SAndrey A. Chernov 	_monetary_locale.p_sep_by_space[0],
219831e8f61SAndrey A. Chernov 	_monetary_locale.n_cs_precedes[0],
220831e8f61SAndrey A. Chernov 	_monetary_locale.n_sep_by_space[0],
221831e8f61SAndrey A. Chernov 	_monetary_locale.p_sign_posn[0],
222683fe113SAlexey Zelkin 	_monetary_locale.n_sign_posn[0],
223683fe113SAlexey Zelkin 	_monetary_locale.int_p_cs_precedes[0],
224683fe113SAlexey Zelkin 	_monetary_locale.int_p_sep_by_space[0],
225683fe113SAlexey Zelkin 	_monetary_locale.int_n_cs_precedes[0],
226683fe113SAlexey Zelkin 	_monetary_locale.int_n_sep_by_space[0],
227683fe113SAlexey Zelkin 	_monetary_locale.int_p_sign_posn[0],
228683fe113SAlexey Zelkin 	_monetary_locale.int_n_sign_posn[0]
22990423eceSAlexey Zelkin );
23090423eceSAlexey Zelkin }
23190423eceSAlexey Zelkin #endif /* LOCALE_DEBUG */
232