• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <locale.h>
17 #include <limits.h>
18 #include "libc.h"
19 #include <string.h>
20 #include "locale_impl.h"
21 
22 static const struct lconv posix_lconv = {
23 	.decimal_point = ".",
24 	.thousands_sep = "",
25 	.grouping = "",
26 	.int_curr_symbol = "",
27 	.currency_symbol = "",
28 	.mon_decimal_point = "",
29 	.mon_thousands_sep = "",
30 	.mon_grouping = "",
31 	.positive_sign = "",
32 	.negative_sign = "",
33 	.int_frac_digits = CHAR_MAX,
34 	.frac_digits = CHAR_MAX,
35 	.p_cs_precedes = CHAR_MAX,
36 	.p_sep_by_space = CHAR_MAX,
37 	.n_cs_precedes = CHAR_MAX,
38 	.n_sep_by_space = CHAR_MAX,
39 	.p_sign_posn = CHAR_MAX,
40 	.n_sign_posn = CHAR_MAX,
41 	.int_p_cs_precedes = CHAR_MAX,
42 	.int_p_sep_by_space = CHAR_MAX,
43 	.int_n_cs_precedes = CHAR_MAX,
44 	.int_n_sep_by_space = CHAR_MAX,
45 	.int_p_sign_posn = CHAR_MAX,
46 	.int_n_sign_posn = CHAR_MAX,
47 };
48 
49 #ifdef FEATURE_ICU_LOCALE
50 #define ICU_BUFFER_SIZE 16
51 #define CHAR_BUFFER_SIZE 8
52 #define INITIALIZE_ICURES_PTR(posix_lconv_ptr, lconv_icures_ptr, buffsize)             \
53 	do {                                                                               \
54 		memset(lconv_icures_ptr, 0, buffsize);                                         \
55 		strncpy(lconv_icures_ptr, posix_lconv_ptr, strlen(posix_lconv_ptr));           \
56 	} while (0)
57 
58 static struct lconv g_lconv_icures;
59 static int g_localeconv_initialize = 1;
60 
61 typedef enum {
62 	ICU_DECIMAL_POINT = 0,
63 	ICU_THOUSANDS_SEP = 1,
64 	ICU_NEGATIVE_SIGN = 6,
65 	ICU_POSITIVE_SIGN = 7,
66 	ICU_CURR_SYMBOL = 8,
67 	ICU_INT_CURR_SYMBOL = 9,
68 	ICU_MON_DECIMAL_POINT = 10,
69 	ICU_MON_THOUSANDS_SEP = 17,
70 } icu_getsymbol_type;
71 
update_lconv_member(u_char * icu_symbol,void * fmt,char * lconv_member,icu_getsymbol_type type)72 static void update_lconv_member(u_char *icu_symbol, void *fmt, char *lconv_member, icu_getsymbol_type type)
73 {
74 	int icu_status = 0;
75 	if (!g_icu_opt_func.unum_get_symbol) {
76 		return;
77 	}
78 	int len = g_icu_opt_func.unum_get_symbol(fmt, type, icu_symbol, ICU_BUFFER_SIZE, &icu_status);
79 	if (icu_status <= 0) {
80 		if (g_icu_opt_func.u_austrncpy) {
81 			g_icu_opt_func.u_austrncpy(lconv_member, icu_symbol, ICU_BUFFER_SIZE);
82 		}
83 	}
84 }
85 
86 // refresh the lconv_icures, fills with the default value
refresh_lconv_icures(void)87 static void refresh_lconv_icures(void)
88 {
89 	if (g_localeconv_initialize == 1) {
90 		memcpy(&g_lconv_icures, &posix_lconv, sizeof(struct lconv));
91 		g_lconv_icures.decimal_point = (char *)malloc(ICU_BUFFER_SIZE);
92 		g_lconv_icures.thousands_sep = (char *)malloc(ICU_BUFFER_SIZE);
93 		g_lconv_icures.int_curr_symbol = (char *)malloc(ICU_BUFFER_SIZE);
94 		g_lconv_icures.currency_symbol = (char *)malloc(ICU_BUFFER_SIZE);
95 		g_lconv_icures.mon_decimal_point = (char *)malloc(ICU_BUFFER_SIZE);
96 		g_lconv_icures.mon_thousands_sep = (char *)malloc(ICU_BUFFER_SIZE);
97 		g_lconv_icures.positive_sign = (char *)malloc(ICU_BUFFER_SIZE);
98 		g_lconv_icures.negative_sign = (char *)malloc(ICU_BUFFER_SIZE);
99 		g_localeconv_initialize = 0;
100 	}
101 
102 	INITIALIZE_ICURES_PTR(posix_lconv.decimal_point, g_lconv_icures.decimal_point, ICU_BUFFER_SIZE);
103 	INITIALIZE_ICURES_PTR(posix_lconv.thousands_sep, g_lconv_icures.thousands_sep, ICU_BUFFER_SIZE);
104 	INITIALIZE_ICURES_PTR(posix_lconv.int_curr_symbol, g_lconv_icures.int_curr_symbol, ICU_BUFFER_SIZE);
105 	INITIALIZE_ICURES_PTR(posix_lconv.currency_symbol, g_lconv_icures.currency_symbol, ICU_BUFFER_SIZE);
106 	INITIALIZE_ICURES_PTR(posix_lconv.mon_decimal_point, g_lconv_icures.mon_decimal_point, ICU_BUFFER_SIZE);
107 	INITIALIZE_ICURES_PTR(posix_lconv.mon_thousands_sep, g_lconv_icures.mon_thousands_sep, ICU_BUFFER_SIZE);
108 	INITIALIZE_ICURES_PTR(posix_lconv.positive_sign, g_lconv_icures.positive_sign, ICU_BUFFER_SIZE);
109 	INITIALIZE_ICURES_PTR(posix_lconv.negative_sign, g_lconv_icures.negative_sign, ICU_BUFFER_SIZE);
110 }
111 #endif
112 
localeconv(void)113 struct lconv *localeconv(void)
114 {
115 #ifdef FEATURE_ICU_LOCALE
116 	if ((libc.global_locale.cat[LC_NUMERIC] && libc.global_locale.cat[LC_NUMERIC]->flag == ICU_VALID) ||
117 		(libc.global_locale.cat[LC_MONETARY] && libc.global_locale.cat[LC_MONETARY]->flag == ICU_VALID)) {
118 		int cur_status = 0;
119 		refresh_lconv_icures();
120 
121 		/* ICU function: unum_getSymbol, return specific information, e.g. currency symbol */
122 		get_icu_symbol(ICU_I18N, &(g_icu_opt_func.unum_get_symbol), ICU_UNUM_GET_SYMBOL_SYMBOL);
123 		/* ICU function: u_austrncpy, transfer result from unum_getSymbol to utf-8 string */
124 		get_icu_symbol(ICU_UC, &(g_icu_opt_func.u_austrncpy), ICU_AUSTRNCPY_SYMBOL);
125 
126 		if (!(g_icu_opt_func.unum_get_symbol) || !(g_icu_opt_func.u_austrncpy)) {
127 			return (void *)&g_lconv_icures;
128 		}
129 
130 		u_char icu_symbol[ICU_BUFFER_SIZE] = { 0 };
131 		void *fmt = NULL;
132 
133 		if (libc.global_locale.cat[LC_NUMERIC]) {
134 			char *icu_locale_name_num = calloc(1, MAX_VALID_ICU_NAME_LEN);
135 			get_valid_icu_locale_name(libc.global_locale.cat[LC_NUMERIC]->name, icu_locale_name_num,
136 				MAX_VALID_ICU_NAME_LEN);
137 			fmt = icu_unum_open(icu_locale_name_num, &cur_status);
138 			free(icu_locale_name_num);
139 			if (cur_status == 0) {
140 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
141 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.decimal_point, ICU_DECIMAL_POINT);
142 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
143 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.thousands_sep, ICU_THOUSANDS_SEP);
144 				icu_unum_close(fmt);
145 			}
146 		}
147 
148 		if (libc.global_locale.cat[LC_MONETARY]) {
149 			char *icu_locale_name_mon = calloc(1, MAX_VALID_ICU_NAME_LEN);
150 			get_valid_icu_locale_name(libc.global_locale.cat[LC_MONETARY]->name, icu_locale_name_mon,
151 				MAX_VALID_ICU_NAME_LEN);
152 			fmt = icu_unum_open(icu_locale_name_mon, &cur_status);
153 			free(icu_locale_name_mon);
154 			if (cur_status == 0) {
155 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
156 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.int_curr_symbol, ICU_INT_CURR_SYMBOL);
157 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
158 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.currency_symbol, ICU_CURR_SYMBOL);
159 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
160 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.mon_decimal_point, ICU_MON_DECIMAL_POINT);
161 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
162 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.mon_thousands_sep, ICU_MON_THOUSANDS_SEP);
163 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
164 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.positive_sign, ICU_POSITIVE_SIGN);
165 				memset(icu_symbol, 0, ICU_BUFFER_SIZE);
166 				update_lconv_member(icu_symbol, fmt, g_lconv_icures.negative_sign, ICU_NEGATIVE_SIGN);
167 				icu_unum_close(fmt);
168 			}
169 		}
170 		return (void *)&g_lconv_icures;
171 	}
172 #endif
173 	return (void *)&posix_lconv;
174 }
175