Reactos
at master 235 lines 6.8 kB view raw
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 19extern "C" { 20 21 // Enclaves have no ability to create new locales. 22#ifndef _UCRT_ENCLAVE_BUILD 23 24static 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 76int __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 */ 212void __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"