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 #ifdef FEATURE_ICU_LOCALE
17 #define _GNU_SOURCE
18 #include <stdlib.h>
19 #include <locale.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <math.h>
23 #include <wchar.h>
24 #include "locale_impl.h"
25
icu_wchar_trans(wchar_t * src,u_char * des,int des_size)26 static int icu_wchar_trans(wchar_t *src, u_char *des, int des_size)
27 {
28 get_icu_symbol(ICU_I18N, &(g_icu_opt_func.u_strFrom_utf32), ICU_SYMBOL(u_strFromUTF32));
29
30 if (!g_icu_opt_func.u_strFrom_utf32) {
31 return DLSYM_ICU_FAIL;
32 }
33
34 int icu_status = 0;
35 void *res_tmp = g_icu_opt_func.u_strFrom_utf32(des, des_size, NULL, src, -1, &icu_status);
36 if (icu_status > 0) {
37 return ICU_ERROR;
38 }
39 return DLSYM_ICU_SUCC;
40 }
41
icu_wcstod_l(char * loc_name,wchar_t * s,int * cur_status,int * parse_pos)42 static double icu_wcstod_l(char *loc_name, wchar_t *s, int *cur_status, int *parse_pos)
43 {
44 char *icu_locale_name = NULL;
45 icu_locale_name = get_valid_icu_locale_name(loc_name);
46
47 void *fmt = icu_unum_open(icu_locale_name, cur_status);
48 if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
49 icu_unum_close(fmt);
50 return 0;
51 }
52
53 int n = wcslen(s);
54 u_char *ustr = (u_char *)calloc((n + 1), sizeof(u_char));
55 *cur_status = icu_wchar_trans(s, ustr, n);
56 if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
57 free(ustr);
58 icu_unum_close(fmt);
59 return 0;
60 }
61
62 double res = icu_parse_double(fmt, ustr, parse_pos, cur_status);
63 if (*cur_status == DLSYM_ICU_FAIL || *cur_status == ICU_ERROR) {
64 free(ustr);
65 icu_unum_close(fmt);
66 return 0;
67 }
68 free(ustr);
69 icu_unum_close(fmt);
70 return res;
71 }
72
wcstod_l(const wchar_t * restrict s,wchar_t ** restrict p,locale_t l)73 double wcstod_l(const wchar_t *restrict s, wchar_t **restrict p, locale_t l)
74 {
75 if (l && s && l->cat[LC_NUMERIC] && l->cat[LC_NUMERIC]->flag == ICU_VALID) {
76 int cur_status = DLSYM_ICU_SUCC;
77 int sign = 1;
78 int parse_pos = 0;
79 wchar_t *tmp_s = (wchar_t *)s;
80 while (tmp_s && iswspace(*tmp_s)) {
81 tmp_s++;
82 }
83 if (*tmp_s == L'+' || *tmp_s == L'-') {
84 sign -= 2 * (*tmp_s == L'-');
85 ++tmp_s;
86 }
87
88 int i;
89 for (i = 0; i < 8 && towlower(*(tmp_s + i)) == L"infinity"[i]; i++) {}
90 if (i == 3 || i == 8 || i > 3) {
91 if (i != 8) {
92 *p = tmp_s + 3;
93 } else {
94 *p = tmp_s + i;
95 }
96 return sign * INFINITY;
97 }
98
99 double res = icu_wcstod_l(l->cat[LC_NUMERIC]->name, tmp_s, &cur_status, &parse_pos);
100 if (cur_status == DLSYM_ICU_SUCC || cur_status == ICU_ERROR) {
101 *p = parse_pos ? tmp_s + parse_pos : (char *)s;
102 return sign * res;
103 }
104 }
105
106 return wcstod(s, p);
107 }
108 #endif
109