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