xref: /reactos/sdk/lib/ucrt/locale/initnum.cpp (revision 2d753d95)
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