xref: /freebsd/lib/libc/locale/lnumeric.c (revision 559a218c)
1d915a14eSPedro F. Giffuni /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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
85b5fa75aSEd 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 
341bd7723dSAlexey Zelkin #include <limits.h>
35683fe113SAlexey Zelkin 
3690423eceSAlexey Zelkin #include "ldpart.h"
37683fe113SAlexey Zelkin #include "lnumeric.h"
3890423eceSAlexey Zelkin 
391bd7723dSAlexey Zelkin extern const char *__fix_locale_grouping_str(const char *);
4090423eceSAlexey Zelkin 
4190423eceSAlexey Zelkin #define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
4290423eceSAlexey Zelkin 
431bd7723dSAlexey Zelkin static char	numempty[] = { CHAR_MAX, '\0' };
44051f867fSAndrey A. Chernov 
4590423eceSAlexey Zelkin static const struct lc_numeric_T _C_numeric_locale = {
4690423eceSAlexey Zelkin 	".",		/* decimal_point */
4790423eceSAlexey Zelkin 	"",		/* thousands_sep */
48051f867fSAndrey A. Chernov 	numempty	/* grouping */
4990423eceSAlexey Zelkin };
5090423eceSAlexey Zelkin 
513c87aa1dSDavid Chisnall static void
destruct_numeric(void * v)523c87aa1dSDavid Chisnall destruct_numeric(void *v)
533c87aa1dSDavid Chisnall {
543c87aa1dSDavid Chisnall 	struct xlocale_numeric *l = v;
553c87aa1dSDavid Chisnall 	if (l->buffer)
563c87aa1dSDavid Chisnall 		free(l->buffer);
573c87aa1dSDavid Chisnall 	free(l);
583c87aa1dSDavid Chisnall }
5990423eceSAlexey Zelkin 
603c87aa1dSDavid Chisnall struct xlocale_numeric __xlocale_global_numeric;
613c87aa1dSDavid Chisnall 
623c87aa1dSDavid Chisnall static int
numeric_load_locale(struct xlocale_numeric * loc,int * using_locale,int * changed,const char * name)631aa669c5SKonstantin Belousov numeric_load_locale(struct xlocale_numeric *loc, int *using_locale,
641aa669c5SKonstantin Belousov     int *changed, const char *name)
65ecc4c620SAndrey A. Chernov {
6690423eceSAlexey Zelkin 	int ret;
673c87aa1dSDavid Chisnall 	struct lc_numeric_T *l = &loc->locale;
6890423eceSAlexey Zelkin 
693c87aa1dSDavid Chisnall 	ret = __part_load_locale(name, using_locale,
703c87aa1dSDavid Chisnall 	    &loc->buffer, "LC_NUMERIC",
7139d2c772SAlexey Zelkin 	    LCNUMERIC_SIZE, LCNUMERIC_SIZE,
723c87aa1dSDavid Chisnall 	    (const char**)l);
73befb332aSAndrey A. Chernov 	if (ret == _LDP_LOADED) {
74befb332aSAndrey A. Chernov 		/* Can't be empty according to C99 */
753c87aa1dSDavid Chisnall 		if (*l->decimal_point == '\0')
763c87aa1dSDavid Chisnall 			l->decimal_point =
77befb332aSAndrey A. Chernov 			    _C_numeric_locale.decimal_point;
783c87aa1dSDavid Chisnall 		l->grouping =
793c87aa1dSDavid Chisnall 		    __fix_locale_grouping_str(l->grouping);
80befb332aSAndrey A. Chernov 	}
817eb138a9SMark Johnston 	if (ret != _LDP_ERROR)
827eb138a9SMark Johnston 		atomic_store_rel_int(changed, 1);
83ecc4c620SAndrey A. Chernov 	return (ret);
8490423eceSAlexey Zelkin }
8590423eceSAlexey Zelkin 
863c87aa1dSDavid Chisnall int
__numeric_load_locale(const char * name)873c87aa1dSDavid Chisnall __numeric_load_locale(const char *name)
88ecc4c620SAndrey A. Chernov {
891aa669c5SKonstantin Belousov 	return (numeric_load_locale(&__xlocale_global_numeric,
903c87aa1dSDavid Chisnall 	    &__xlocale_global_locale.using_numeric_locale,
911aa669c5SKonstantin Belousov 	    &__xlocale_global_locale.numeric_locale_changed, name));
923c87aa1dSDavid Chisnall }
931aa669c5SKonstantin Belousov 
943c87aa1dSDavid Chisnall void *
__numeric_load(const char * name,locale_t l)953c87aa1dSDavid Chisnall __numeric_load(const char *name, locale_t l)
963c87aa1dSDavid Chisnall {
971aa669c5SKonstantin Belousov 	struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric),
981aa669c5SKonstantin Belousov 	    1);
9987151b60SKonstantin Belousov 	if (new == NULL)
10087151b60SKonstantin Belousov 		return (NULL);
1013c87aa1dSDavid Chisnall 	new->header.header.destructor = destruct_numeric;
1023c87aa1dSDavid Chisnall 	if (numeric_load_locale(new, &l->using_numeric_locale,
1031aa669c5SKonstantin Belousov 	    &l->numeric_locale_changed, name) == _LDP_ERROR) {
1043c87aa1dSDavid Chisnall 		xlocale_release(new);
1051aa669c5SKonstantin Belousov 		return (NULL);
1063c87aa1dSDavid Chisnall 	}
1071aa669c5SKonstantin Belousov 	return (new);
1083c87aa1dSDavid Chisnall }
1093c87aa1dSDavid Chisnall 
1103c87aa1dSDavid Chisnall struct lc_numeric_T *
__get_current_numeric_locale(locale_t loc)1113c87aa1dSDavid Chisnall __get_current_numeric_locale(locale_t loc)
1123c87aa1dSDavid Chisnall {
1131aa669c5SKonstantin Belousov 	return (loc->using_numeric_locale ?
1141aa669c5SKonstantin Belousov 	    &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale :
1151aa669c5SKonstantin Belousov 	    (struct lc_numeric_T *)&_C_numeric_locale);
11690423eceSAlexey Zelkin }
11790423eceSAlexey Zelkin 
11890423eceSAlexey Zelkin #ifdef LOCALE_DEBUG
11990423eceSAlexey Zelkin void
numericdebug(void)12090423eceSAlexey Zelkin numericdebug(void) {
12190423eceSAlexey Zelkin printf(	"decimal_point = %s\n"
12290423eceSAlexey Zelkin 	"thousands_sep = %s\n"
12390423eceSAlexey Zelkin 	"grouping = %s\n",
12490423eceSAlexey Zelkin 	_numeric_locale.decimal_point,
12590423eceSAlexey Zelkin 	_numeric_locale.thousands_sep,
12690423eceSAlexey Zelkin 	_numeric_locale.grouping
12790423eceSAlexey Zelkin );
12890423eceSAlexey Zelkin }
12990423eceSAlexey Zelkin #endif /* LOCALE_DEBUG */
130