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