• 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 #define _GNU_SOURCE
17 #include <stdlib.h>
18 #include <locale.h>
19 #ifdef FEATURE_ICU_LOCALE
20 #include <ctype.h>
21 #include <string.h>
22 #include <math.h>
23 #include "locale_impl.h"
24 #endif
25 
strtof_l(const char * restrict s,char ** restrict p,locale_t l)26 float strtof_l(const char *restrict s, char **restrict p, locale_t l)
27 {
28 	return strtof(s, p);
29 }
30 
31 #ifdef FEATURE_ICU_LOCALE
icu_unum_open(char * icu_locale_name,int * cur_status)32 void *icu_unum_open(char *icu_locale_name, int *cur_status)
33 {
34 	/* ICU function: unum_open, returns a format related to specific locale */
35 	get_icu_symbol(ICU_I18N, &(g_icu_opt_func.unum_open), ICU_UNUM_OPEN_SYMBOL);
36 
37 	/* dlopen/dlsym fail */
38 	if (!g_icu_opt_func.unum_open) {
39 		*cur_status = DLSYM_ICU_FAIL;
40 		return NULL;
41 	}
42 
43 	int icu_status = 0;
44 	void *fmt = g_icu_opt_func.unum_open(1, NULL, -1, icu_locale_name, NULL, &icu_status);
45 	/* icu_status is the error code from icu methods, positive error code means errors
46 	 * happening in icu, e.g. invalid input string or no locale source data
47 	 */
48 	if (icu_status > 0) {
49 		*cur_status = ICU_ERROR;
50 		return NULL;
51 	}
52 	return fmt;
53 }
54 
icu_unum_close(void * fmt)55 void icu_unum_close(void *fmt)
56 {
57 	/* ICU function: unum_close, close the formate returned from unum_open */
58 	get_icu_symbol(ICU_I18N, &(g_icu_opt_func.unum_close), ICU_UNUM_CLOSE_SYMBOL);
59 	if (g_icu_opt_func.unum_close) {
60 		g_icu_opt_func.unum_close(fmt);
61 	}
62 }
63 
icu_char_trans(char * src,u_char * des,int des_size)64 static int icu_char_trans(char *src, u_char *des, int des_size)
65 {
66 	/* ICU function: u_strFromUTF8, transfer utf-8 string to Uchar* string which is
67 	 * the input format of icu parse methods
68 	 */
69 	get_icu_symbol(ICU_I18N, &(g_icu_opt_func.u_str_from_utf8), ICU_STR_FROM_UTF8_SYMBOL);
70 	if (!g_icu_opt_func.u_str_from_utf8) {
71 		return DLSYM_ICU_FAIL;
72 	}
73 
74 	int icu_status = 0;
75 	g_icu_opt_func.u_str_from_utf8(des, des_size, NULL, src, -1, &icu_status);
76 	if (icu_status > 0) {
77 		return ICU_ERROR;
78 	}
79 	return DLSYM_ICU_SUCC;
80 }
81 
icu_parse_double(void * fmt,u_char * ustr,int32_t * parse_pos,int * cur_status)82 double icu_parse_double(void *fmt, u_char *ustr, int32_t *parse_pos, int *cur_status)
83 {
84 	/* ICU function: unum_parseDouble, parse the given Uchar* string to double */
85 	get_icu_symbol(ICU_I18N, &(g_icu_opt_func.unum_parse_double), ICU_UNUM_PARSE_DOUBLE_SYMBOL);
86 	if (!g_icu_opt_func.unum_parse_double) {
87 		*cur_status = DLSYM_ICU_FAIL;
88 		return 0;
89 	}
90 
91 	int32_t icu_status = 0;
92 	double res = g_icu_opt_func.unum_parse_double(fmt, ustr, -1, parse_pos, &icu_status);
93 	if (icu_status > 0) {
94 		*cur_status = ICU_ERROR;
95 		return 0;
96 	}
97 
98 	return res;
99 }
100 
icu_strtod_l(char * loc_name,char * s,int * cur_status,int * parse_pos)101 static double icu_strtod_l(char *loc_name, char *s, int *cur_status, int *parse_pos)
102 {
103 	char *icu_locale_name = calloc(1, MAX_VALID_ICU_NAME_LEN);
104 	get_valid_icu_locale_name(loc_name, icu_locale_name, MAX_VALID_ICU_NAME_LEN);
105 	void *fmt = icu_unum_open(icu_locale_name, cur_status);
106 	free(icu_locale_name);
107 	if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
108 		return 0;
109 	}
110 
111 	int n = strlen(s);
112 	u_char *ustr = (u_char *)calloc((n + 1), sizeof(u_char));
113 	*cur_status = icu_char_trans(s, ustr, n);
114 	if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
115 		free(ustr);
116 		icu_unum_close(fmt);
117 		return 0;
118 	}
119 
120 	double res = icu_parse_double(fmt, ustr, parse_pos, cur_status);
121 	if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
122 		free(ustr);
123 		icu_unum_close(fmt);
124 		return 0;
125 	}
126 	free(ustr);
127 	icu_unum_close(fmt);
128 	return res;
129 }
130 #endif
131 
strtod_l(const char * restrict s,char ** restrict p,locale_t l)132 double strtod_l(const char *restrict s, char **restrict p, locale_t l)
133 {
134 #ifdef FEATURE_ICU_LOCALE
135 	if (l && s && l->cat[LC_NUMERIC] && l->cat[LC_NUMERIC]->flag == ICU_VALID) {
136 		int cur_status = DLSYM_ICU_SUCC;
137 		int sign = 1;
138 		int parse_pos = 0;
139 		/* preprocess blank characters */
140 		char *tmp_s = (char *)s;
141 		while (tmp_s && isspace((unsigned char)*tmp_s)) {
142 			tmp_s++;
143 		}
144 
145 		/* preprocess positiv/negative signs */
146 		if (*tmp_s == '+' || *tmp_s == '-') {
147 			sign -= 2 * (*tmp_s == '-');
148 			++tmp_s;
149 		}
150 
151 		/* process inf/infinity */
152 		int i;
153 		for (i = 0; i < 8 && (*(tmp_s + i) | 32) == "infinity"[i]; i++) {}
154 		if (i == 3 || i == 8 || i > 3) {
155 			if (!p) return sign * INFINITY;
156 			if (i != 8) {
157 				*p = tmp_s + 3;
158 			} else {
159 				*p = tmp_s + i;
160 			}
161 			return sign * INFINITY;
162 		}
163 
164 		double res = icu_strtod_l(l->cat[LC_NUMERIC]->name, tmp_s, &cur_status, &parse_pos);
165 		if (cur_status == DLSYM_ICU_SUCC || cur_status == ICU_ERROR) {
166 			if (p) *p = parse_pos ? tmp_s + parse_pos : (char *)s;
167 			return sign * res;
168 		}
169 	}
170 #endif
171 	return strtod(s, p);
172 }
173 
strtold_l(const char * restrict s,char ** restrict p,locale_t l)174 long double strtold_l(const char *restrict s, char **restrict p, locale_t l)
175 {
176 	return strtold(s, p);
177 }
178 
179 weak_alias(strtof_l, __strtof_l);
180 weak_alias(strtod_l, __strtod_l);
181 weak_alias(strtold_l, __strtold_l);
182