1 /***
2 *initnum.c - contains __acrt_locale_initialize_numeric
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 * Contains the locale-category initialization function: __acrt_locale_initialize_numeric().
8 *
9 * Each initialization function sets up locale-specific information
10 * for their category, for use by functions which are affected by
11 * their locale category.
12 *
13 * *** For internal use by setlocale() only ***
14 *
15 *******************************************************************************/
16 #include <corecrt_internal.h>
17 #include <locale.h>
18
19 extern "C" {
20
21 // Enclaves have no ability to create new locales.
22 #ifndef _UCRT_ENCLAVE_BUILD
23
fix_grouping(_Inout_z_ char * grouping)24 static void fix_grouping(
25 _Inout_z_ char * grouping
26 )
27 {
28 /*
29 * ANSI specifies that the fields should contain "\3" [\3\0] to indicate
30 * thousands groupings (100,000,000.00 for example).
31 * NT uses "3;0"; ASCII 3 instead of value 3 and the ';' is extra.
32 * So here we convert the NT version to the ANSI version.
33 */
34
35 while (*grouping)
36 {
37 /* convert '3' to '\3' */
38 if (*grouping >= '0' && *grouping <= '9')
39 {
40 *grouping = *grouping - '0';
41 grouping++;
42 }
43
44 /* remove ';' */
45 else if (*grouping == ';')
46 {
47 char *tmp = grouping;
48
49 do
50 *tmp = *(tmp+1);
51 while (*++tmp);
52 }
53
54 /* unknown (illegal) character, ignore */
55 else
56 grouping++;
57 }
58 }
59
60 /***
61 *int __acrt_locale_initialize_numeric() - initialization for LC_NUMERIC locale category.
62 *
63 *Purpose:
64 *
65 *Entry:
66 * None.
67 *
68 *Exit:
69 * 0 success
70 * 1 fail
71 *
72 *Exceptions:
73 *
74 *******************************************************************************/
75
__acrt_locale_initialize_numeric(__crt_locale_data * ploci)76 int __cdecl __acrt_locale_initialize_numeric (
77 __crt_locale_data* ploci
78 )
79 {
80 struct lconv *lc;
81 int ret = 0;
82 wchar_t* ctrylocalename;
83 long *lc_refcount;
84 long *lconv_num_refcount = nullptr;
85 __crt_locale_pointers locinfo;
86
87 locinfo.locinfo = ploci;
88 locinfo.mbcinfo = 0;
89
90 if ( (ploci->locale_name[LC_NUMERIC] != nullptr) ||
91 (ploci->locale_name[LC_MONETARY] != nullptr) )
92 {
93 /*
94 * Allocate structure filled with nullptr pointers
95 */
96 if ( (lc = (struct lconv *)_calloc_crt(1, sizeof(struct lconv)))
97 == nullptr )
98 return 1;
99
100 /*
101 * Copy over all fields (esp., the monetary category)
102 */
103 *lc = *ploci->lconv;
104
105 /*
106 * Allocate a new reference counter for the lconv structure
107 */
108 if ( (lc_refcount = _malloc_crt_t(long, 1).detach()) == nullptr )
109 {
110 _free_crt(lc);
111 return 1;
112 }
113 *lc_refcount = 0;
114
115 if ( ploci->locale_name[LC_NUMERIC] != nullptr )
116 {
117 /*
118 * Allocate a new reference counter for the numeric info
119 */
120 if ( (lconv_num_refcount = _malloc_crt_t(long, 1).detach()) == nullptr )
121 {
122 _free_crt(lc);
123 _free_crt(lc_refcount);
124 return 1;
125 }
126 *lconv_num_refcount = 0;
127
128 /*
129 * Numeric data is country--not language--dependent.
130 */
131 ctrylocalename = ploci->locale_name[LC_NUMERIC];
132
133 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename, LOCALE_SDECIMAL,
134 (void *)&lc->decimal_point);
135 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename, LOCALE_STHOUSAND,
136 (void *)&lc->thousands_sep);
137 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename, LOCALE_SGROUPING,
138 (void *)&lc->grouping);
139
140 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename, LOCALE_SDECIMAL,
141 (void *)&lc->_W_decimal_point);
142 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename, LOCALE_STHOUSAND,
143 (void *)&lc->_W_thousands_sep);
144
145 if (ret) {
146 /* Clean up before returning failure */
147 __acrt_locale_free_numeric(lc);
148 _free_crt(lc);
149 _free_crt(lconv_num_refcount);
150 _free_crt(lc_refcount);
151 return -1;
152 }
153
154 fix_grouping(lc->grouping);
155 }
156 else {
157 /*
158 * C locale for just the numeric category.
159 */
160 /*
161 * nullptr out the reference count pointer
162 */
163 lconv_num_refcount = nullptr;
164 lc->decimal_point = __acrt_lconv_c.decimal_point;
165 lc->thousands_sep = __acrt_lconv_c.thousands_sep;
166 lc->grouping = __acrt_lconv_c.grouping;
167 lc->_W_decimal_point = __acrt_lconv_c._W_decimal_point;
168 lc->_W_thousands_sep = __acrt_lconv_c._W_thousands_sep;
169 }
170 (*lc_refcount) = 1;
171 if (lconv_num_refcount)
172 (*lconv_num_refcount) = 1;
173 }
174
175 else {
176 /*
177 * C locale for BOTH numeric and monetary categories.
178 */
179 lconv_num_refcount = nullptr;
180 lc_refcount = nullptr;
181 lc = &__acrt_lconv_c; /* point to new one */
182 }
183 /*
184 * If this is part of LC_ALL, then we need to free the old ploci->lconv
185 * set up in init_monetary() before this.
186 */
187 if ( (ploci->lconv_num_refcount != nullptr) &&
188 (InterlockedDecrement(ploci->lconv_num_refcount) == 0))
189 {
190 _ASSERTE(*ploci->lconv_num_refcount > 0);
191 }
192 if ( (ploci->lconv_intl_refcount != nullptr) &&
193 (InterlockedDecrement(ploci->lconv_intl_refcount) == 0))
194 {
195 _free_crt(ploci->lconv_intl_refcount);
196 _free_crt(ploci->lconv);
197 }
198
199 ploci->lconv_num_refcount = lconv_num_refcount;
200 ploci->lconv_intl_refcount = lc_refcount;
201
202 ploci->lconv = lc;
203 return 0;
204 }
205
206 #endif /* _UCRT_ENCLAVE_BUILD */
207
208 /*
209 * Free the lconv numeric strings.
210 * Numeric values do not need to be freed.
211 */
__acrt_locale_free_numeric(lconv * l)212 void __cdecl __acrt_locale_free_numeric(lconv* l)
213 {
214 if (l == nullptr)
215 return;
216
217 if ( l->decimal_point != __acrt_lconv_c.decimal_point )
218 _free_crt(l->decimal_point);
219
220 if ( l->thousands_sep != __acrt_lconv_c.thousands_sep )
221 _free_crt(l->thousands_sep);
222
223 if ( l->grouping != __acrt_lconv_c.grouping )
224 _free_crt(l->grouping);
225
226 if ( l->_W_decimal_point != __acrt_lconv_c._W_decimal_point )
227 _free_crt(l->_W_decimal_point);
228
229 if ( l->_W_thousands_sep != __acrt_lconv_c._W_thousands_sep )
230 _free_crt(l->_W_thousands_sep);
231 }
232
233
234
235 } // extern "C"
236