Reactos
1/***
2*initmon.c - contains __acrt_locale_initialize_monetary
3*
4* Copyright (c) Microsoft Corporation. All rights reserved.
5*
6*Purpose:
7* Contains the locale-category initialization function: __acrt_locale_initialize_monetary().
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
17#include <corecrt_internal.h>
18#include <locale.h>
19
20extern "C" {
21
22
23 // Enclaves have no ability to create new locales.
24#ifndef _UCRT_ENCLAVE_BUILD
25
26static void fix_grouping(_Inout_z_ char *);
27
28/*
29 * Note that __acrt_lconv_c is used when the monetary category is in the C locale
30 * but the numeric category may not necessarily be in the C locale.
31 */
32
33
34/***
35*int __acrt_locale_initialize_monetary() - initialization for LC_MONETARY locale category.
36*
37*Purpose:
38* In non-C locales, read the localized monetary strings into
39* __acrt_lconv_intl, and also copy the numeric strings from __acrt_lconv into
40* __acrt_lconv_intl. Set __acrt_lconv to point to __acrt_lconv_intl. The old
41* __acrt_lconv_intl is not freed until the new one is fully established.
42*
43* In the C locale, the monetary fields in lconv are filled with
44* contain C locale values. Any allocated __acrt_lconv_intl fields are freed.
45*
46* At startup, __acrt_lconv points to a static lconv structure containing
47* C locale strings. This structure is never used again if
48* __acrt_locale_initialize_monetary is called.
49*
50*Entry:
51* None.
52*
53*Exit:
54* 0 success
55* 1 fail
56*
57*Exceptions:
58*
59*******************************************************************************/
60
61int __cdecl __acrt_locale_initialize_monetary (
62 __crt_locale_data* ploci
63 )
64{
65 struct lconv *lc;
66 int ret;
67 wchar_t* ctrylocalename;
68 long *lc_refcount;
69 long *lconv_mon_refcount = nullptr;
70 __crt_locale_pointers locinfo;
71
72 locinfo.locinfo = ploci;
73 locinfo.mbcinfo = 0;
74
75 if ( (ploci->locale_name[LC_MONETARY] != nullptr) ||
76 (ploci->locale_name[LC_NUMERIC] != nullptr) )
77 {
78 /*
79 * Allocate structure filled with nullptr pointers
80 */
81 if ((lc = _calloc_crt_t(lconv, 1).detach()) == nullptr)
82 return 1;
83
84 /*
85 * Allocate a new reference counter for the lconv structure
86 */
87 if ( (lc_refcount = _calloc_crt_t(long, 1).detach()) == nullptr )
88 {
89 _free_crt(lc);
90 return 1;
91 }
92
93 if ( ploci->locale_name[LC_MONETARY] != nullptr )
94 {
95 /*
96 * Allocate a new reference counter for the numeric info
97 */
98 if ( (lconv_mon_refcount = _calloc_crt_t(long, 1).detach()) == nullptr )
99 {
100 _free_crt(lc);
101 _free_crt(lc_refcount);
102 return 1;
103 }
104
105 /*
106 * Currency is country--not language--dependent. NT
107 * work-around.
108 */
109 ctrylocalename = ploci->locale_name[LC_MONETARY];
110
111 ret = 0;
112
113 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
114 LOCALE_SINTLSYMBOL, (void *)&lc->int_curr_symbol );
115 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
116 LOCALE_SCURRENCY, (void *)&lc->currency_symbol );
117 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
118 LOCALE_SMONDECIMALSEP, (void *)&lc->mon_decimal_point );
119 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
120 LOCALE_SMONTHOUSANDSEP, (void *)&lc->mon_thousands_sep );
121 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
122 LOCALE_SMONGROUPING, (void *)&lc->mon_grouping );
123
124 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
125 LOCALE_SPOSITIVESIGN, (void *)&lc->positive_sign);
126 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_STR_TYPE, ctrylocalename,
127 LOCALE_SNEGATIVESIGN, (void *)&lc->negative_sign);
128
129 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
130 LOCALE_IINTLCURRDIGITS, (void *)&lc->int_frac_digits);
131 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
132 LOCALE_ICURRDIGITS, (void *)&lc->frac_digits);
133 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
134 LOCALE_IPOSSYMPRECEDES, (void *)&lc->p_cs_precedes);
135 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
136 LOCALE_IPOSSEPBYSPACE, (void *)&lc->p_sep_by_space);
137 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
138 LOCALE_INEGSYMPRECEDES, (void *)&lc->n_cs_precedes);
139 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
140 LOCALE_INEGSEPBYSPACE, (void *)&lc->n_sep_by_space);
141 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
142 LOCALE_IPOSSIGNPOSN, (void *)&lc->p_sign_posn);
143 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_INT_TYPE, ctrylocalename,
144 LOCALE_INEGSIGNPOSN, (void *)&lc->n_sign_posn);
145
146 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
147 LOCALE_SINTLSYMBOL, (void *)&lc->_W_int_curr_symbol );
148 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
149 LOCALE_SCURRENCY, (void *)&lc->_W_currency_symbol );
150 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
151 LOCALE_SMONDECIMALSEP, (void *)&lc->_W_mon_decimal_point );
152 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
153 LOCALE_SMONTHOUSANDSEP, (void *)&lc->_W_mon_thousands_sep );
154 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
155 LOCALE_SPOSITIVESIGN, (void *)&lc->_W_positive_sign);
156 ret |= __acrt_GetLocaleInfoA(&locinfo, LC_WSTR_TYPE, ctrylocalename,
157 LOCALE_SNEGATIVESIGN, (void *)&lc->_W_negative_sign);
158
159 if ( ret != 0 ) {
160 __acrt_locale_free_monetary(lc);
161 _free_crt(lc);
162 _free_crt(lc_refcount);
163 _free_crt(lconv_mon_refcount);
164 return 1;
165 }
166
167 fix_grouping(lc->mon_grouping);
168 }
169 else {
170 /*
171 * C locale for monetary category (the numeric category fields,
172 * which are NOT of the C locale, get fixed up below). Note
173 * that __acrt_lconv_c is copied, rather than directly assigning
174 * the fields of lc because of the uncertainty of the values of
175 * the int_frac_digits,..., n_sign_posn fields (SCHAR_MAX or
176 * UCHAR_MAX, depending on whether or a compliand was built
177 * with -J.
178 */
179 *lc = __acrt_lconv_c;
180 }
181
182 /*
183 * Copy the numeric locale fields from the old struct
184 */
185 lc->decimal_point = ploci->lconv->decimal_point;
186 lc->thousands_sep = ploci->lconv->thousands_sep;
187 lc->grouping = ploci->lconv->grouping;
188 lc->_W_decimal_point = ploci->lconv->_W_decimal_point;
189 lc->_W_thousands_sep = ploci->lconv->_W_thousands_sep;
190
191 *lc_refcount = 1;
192 if (lconv_mon_refcount)
193 *lconv_mon_refcount = 1;
194 }
195 else {
196 /*
197 * C locale for BOTH monetary and numeric categories.
198 */
199 lconv_mon_refcount = nullptr;
200 lc_refcount = nullptr;
201 lc = &__acrt_lconv_c; /* point to new one */
202
203 }
204
205 if ( (ploci->lconv_mon_refcount != nullptr) &&
206 (InterlockedDecrement(ploci->lconv_mon_refcount) == 0))
207 {
208 _ASSERTE(*ploci->lconv_mon_refcount > 0);
209 }
210 if ( (ploci->lconv_intl_refcount != nullptr) &&
211 (InterlockedDecrement(ploci->lconv_intl_refcount) == 0))
212 {
213 _free_crt(ploci->lconv);
214 _free_crt(ploci->lconv_intl_refcount);
215 }
216 ploci->lconv_mon_refcount = lconv_mon_refcount;
217 ploci->lconv_intl_refcount = lc_refcount;
218 ploci->lconv = lc; /* point to new one */
219
220 return 0;
221}
222
223static void fix_grouping(
224 char *grouping
225 )
226{
227 /*
228 * ANSI specifies that the fields should contain "\3" [\3\0] to indicate
229 * thousands groupings (100,000,000.00 for example).
230 * NT uses "3;0"; ASCII 3 instead of value 3 and the ';' is extra.
231 * So here we convert the NT version to the ANSI version.
232 */
233
234 while (*grouping)
235 {
236 /* convert '3' to '\3' */
237 if (*grouping >= '0' && *grouping <= '9')
238 {
239 *grouping = *grouping - '0';
240 grouping++;
241 }
242
243 /* remove ';' */
244 else if (*grouping == ';')
245 {
246 char *tmp = grouping;
247
248 do
249 *tmp = *(tmp+1);
250 while (*++tmp);
251 }
252
253 /* unknown (illegal) character, ignore */
254 else
255 grouping++;
256 }
257}
258
259#endif /* _UCRT_ENCLAVE_BUILD */
260
261/*
262 * Free the lconv monetary strings.
263 * Numeric values do not need to be freed.
264 */
265void __cdecl __acrt_locale_free_monetary(lconv* l)
266{
267 if (l == nullptr)
268 return;
269
270 if ( l->int_curr_symbol != __acrt_lconv_c.int_curr_symbol )
271 _free_crt(l->int_curr_symbol);
272
273 if ( l->currency_symbol != __acrt_lconv_c.currency_symbol )
274 _free_crt(l->currency_symbol);
275
276 if ( l->mon_decimal_point != __acrt_lconv_c.mon_decimal_point )
277 _free_crt(l->mon_decimal_point);
278
279 if ( l->mon_thousands_sep != __acrt_lconv_c.mon_thousands_sep )
280 _free_crt(l->mon_thousands_sep);
281
282 if ( l->mon_grouping != __acrt_lconv_c.mon_grouping )
283 _free_crt(l->mon_grouping);
284
285 if ( l->positive_sign != __acrt_lconv_c.positive_sign )
286 _free_crt(l->positive_sign);
287
288 if ( l->negative_sign != __acrt_lconv_c.negative_sign )
289 _free_crt(l->negative_sign);
290
291 if ( l->_W_int_curr_symbol != __acrt_lconv_c._W_int_curr_symbol )
292 _free_crt(l->_W_int_curr_symbol);
293
294 if ( l->_W_currency_symbol != __acrt_lconv_c._W_currency_symbol )
295 _free_crt(l->_W_currency_symbol);
296
297 if ( l->_W_mon_decimal_point != __acrt_lconv_c._W_mon_decimal_point )
298 _free_crt(l->_W_mon_decimal_point);
299
300 if ( l->_W_mon_thousands_sep != __acrt_lconv_c._W_mon_thousands_sep )
301 _free_crt(l->_W_mon_thousands_sep);
302
303 if ( l->_W_positive_sign != __acrt_lconv_c._W_positive_sign )
304 _free_crt(l->_W_positive_sign);
305
306 if ( l->_W_negative_sign != __acrt_lconv_c._W_negative_sign )
307 _free_crt(l->_W_negative_sign);
308}
309
310
311
312} // extern "C"