xref: /reactos/sdk/lib/ucrt/locale/initmon.cpp (revision 04e0dc4a)
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 
20 extern "C" {
21 
22 
23     // Enclaves have no ability to create new locales.
24 #ifndef _UCRT_ENCLAVE_BUILD
25 
26 static 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 
61 int __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 
223 static 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  */
265 void __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"
313