diff --git a/configure b/configure index be06b95b845..c291a433b61 100755 --- a/configure +++ b/configure @@ -17163,6 +17163,7 @@ wine_fn_config_dll msvcr100 enable_msvcr100 implib wine_fn_config_test dlls/msvcr100/tests msvcr100_test wine_fn_config_dll msvcr110 enable_msvcr110 implib wine_fn_config_dll msvcr120 enable_msvcr120 implib +wine_fn_config_test dlls/msvcr120/tests msvcr120_test wine_fn_config_dll msvcr70 enable_msvcr70 implib wine_fn_config_dll msvcr71 enable_msvcr71 implib wine_fn_config_dll msvcr80 enable_msvcr80 implib diff --git a/configure.ac b/configure.ac index c33869e41e5..8f8a732c55b 100644 --- a/configure.ac +++ b/configure.ac @@ -3037,6 +3037,7 @@ WINE_CONFIG_DLL(msvcr100,,[implib]) WINE_CONFIG_TEST(dlls/msvcr100/tests) WINE_CONFIG_DLL(msvcr110,,[implib]) WINE_CONFIG_DLL(msvcr120,,[implib]) +WINE_CONFIG_TEST(dlls/msvcr120/tests) WINE_CONFIG_DLL(msvcr70,,[implib]) WINE_CONFIG_DLL(msvcr71,,[implib]) WINE_CONFIG_DLL(msvcr80,,[implib]) diff --git a/dlls/msvcr120/tests/Makefile.in b/dlls/msvcr120/tests/Makefile.in new file mode 100644 index 00000000000..5a88f38d276 --- /dev/null +++ b/dlls/msvcr120/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = msvcr120.dll +APPMODE = -mno-cygwin + +C_SRCS = \ + msvcr120.c diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c new file mode 100644 index 00000000000..bed10022192 --- /dev/null +++ b/dlls/msvcr120/tests/msvcr120.c @@ -0,0 +1,155 @@ +/* + * Copyright 2014 Yifu Wang for ESRI + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "wine/test.h" + +#include + +struct MSVCRT_lconv +{ + char* decimal_point; + char* thousands_sep; + char* grouping; + char* int_curr_symbol; + char* currency_symbol; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + wchar_t* _W_decimal_point; + wchar_t* _W_thousands_sep; + wchar_t* _W_int_curr_symbol; + wchar_t* _W_currency_symbol; + wchar_t* _W_mon_decimal_point; + wchar_t* _W_mon_thousands_sep; + wchar_t* _W_positive_sign; + wchar_t* _W_negative_sign; +}; + +static char* (CDECL *p_setlocale)(int category, const char* locale); +static struct MSVCRT_lconv* (CDECL *p_localeconv)(void); +static size_t (CDECL *p_wcstombs_s)(size_t *ret, char* dest, size_t sz, const wchar_t* src, size_t max); + +static BOOL init(void) +{ + HMODULE module; + + module = LoadLibraryA("msvcr120.dll"); + if (!module) + { + win_skip("msvcr120.dll not installed\n"); + return FALSE; + } + + p_setlocale = (void*)GetProcAddress(module, "setlocale"); + p_localeconv = (void*)GetProcAddress(module, "localeconv"); + p_wcstombs_s = (void*)GetProcAddress(module, "wcstombs_s"); + return TRUE; +} + +void test_lconv_helper(const char *locstr) +{ + struct MSVCRT_lconv *lconv; + char mbs[256]; + size_t i; + + if(!p_setlocale(LC_ALL, locstr)) + { + win_skip("locale %s not available\n", locstr); + return; + } + + lconv = p_localeconv(); + + /* If multi-byte version available, asserts that wide char version also available. + * If wide char version can be converted to a multi-byte string , asserts that the + * conversion result is the same as the multi-byte version. + */ + if(strlen(lconv->decimal_point) > 0) + ok(wcslen(lconv->_W_decimal_point) > 0, "%s: decimal_point\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_decimal_point, 256) == 0) + ok(strcmp(mbs, lconv->decimal_point) == 0, "%s: decimal_point\n", locstr); + + if(strlen(lconv->thousands_sep) > 0) + ok(wcslen(lconv->_W_thousands_sep) > 0, "%s: thousands_sep\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_thousands_sep, 256) == 0) + ok(strcmp(mbs, lconv->thousands_sep) == 0, "%s: thousands_sep\n", locstr); + + if(strlen(lconv->int_curr_symbol) > 0) + ok(wcslen(lconv->_W_int_curr_symbol) > 0, "%s: int_curr_symbol\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_int_curr_symbol, 256) == 0) + ok(strcmp(mbs, lconv->int_curr_symbol) == 0, "%s: int_curr_symbol\n", locstr); + + if(strlen(lconv->currency_symbol) > 0) + ok(wcslen(lconv->_W_currency_symbol) > 0, "%s: currency_symbol\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_currency_symbol, 256) == 0) + ok(strcmp(mbs, lconv->currency_symbol) == 0, "%s: currency_symbol\n", locstr); + + if(strlen(lconv->mon_decimal_point) > 0) + ok(wcslen(lconv->_W_mon_decimal_point) > 0, "%s: decimal_point\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_mon_decimal_point, 256) == 0) + ok(strcmp(mbs, lconv->mon_decimal_point) == 0, "%s: decimal_point\n", locstr); + + if(strlen(lconv->positive_sign) > 0) + ok(wcslen(lconv->_W_positive_sign) > 0, "%s: positive_sign\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_positive_sign, 256) == 0) + ok(strcmp(mbs, lconv->positive_sign) == 0, "%s: positive_sign\n", locstr); + + if(strlen(lconv->negative_sign) > 0) + ok(wcslen(lconv->_W_negative_sign) > 0, "%s: negative_sign\n", locstr); + if(p_wcstombs_s(&i, mbs, 256, lconv->_W_negative_sign, 256) == 0) + ok(strcmp(mbs, lconv->negative_sign) == 0, "%s: negative_sign\n", locstr); +} + +void test_lconv(void) +{ + int i; + const char *locstrs[] = + { + "American", "Belgian", "Chinese", + "Dutch", "English", "French", + "German", "Hungarian", "Icelandic", + "Japanese", "Korean", "Spanish" + }; + + for(i = 0; i < sizeof(locstrs) / sizeof(char *); i ++) + test_lconv_helper(locstrs[i]); +} + +START_TEST(msvcr120) +{ + if (!init()) return; + test_lconv(); +} diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 992aa3ecb7f..2b1efc6ac1c 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -659,6 +659,16 @@ void free_locinfo(MSVCRT_pthreadlocinfo locinfo) MSVCRT_free(locinfo->lconv->mon_grouping); MSVCRT_free(locinfo->lconv->positive_sign); MSVCRT_free(locinfo->lconv->negative_sign); +#if _MSVCR_VER >= 120 + MSVCRT_free(locinfo->lconv->_W_decimal_point); + MSVCRT_free(locinfo->lconv->_W_thousands_sep); + MSVCRT_free(locinfo->lconv->_W_int_curr_symbol); + MSVCRT_free(locinfo->lconv->_W_currency_symbol); + MSVCRT_free(locinfo->lconv->_W_mon_decimal_point); + MSVCRT_free(locinfo->lconv->_W_mon_thousands_sep); + MSVCRT_free(locinfo->lconv->_W_positive_sign); + MSVCRT_free(locinfo->lconv->_W_negative_sign); +#endif } MSVCRT_free(locinfo->lconv_intl_refcount); MSVCRT_free(locinfo->lconv_num_refcount); @@ -755,6 +765,9 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) LCID lcid[6] = { 0 }, lcid_tmp; unsigned short cp[6] = { 0 }; char buf[256]; +#if _MSVCR_VER >= 120 + MSVCRT_wchar_t wbuf[256]; +#endif int i, ret, size; TRACE("(%d %s)\n", category, locale); @@ -1092,6 +1105,63 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) MSVCRT__free_locale(loc); return NULL; } + +#if _MSVCR_VER >= 120 + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_int_curr_symbol, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_currency_symbol, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_mon_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_mon_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_positive_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_positive_sign, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_negative_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_negative_sign, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } +#endif + } else { loc->locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char)); loc->locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char)); @@ -1125,6 +1195,29 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) loc->locinfo->lconv->p_sign_posn = 127; loc->locinfo->lconv->n_sign_posn = 127; +#if _MSVCR_VER >= 120 + loc->locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + loc->locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + loc->locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + loc->locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + loc->locinfo->lconv->_W_positive_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + loc->locinfo->lconv->_W_negative_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + + if(!loc->locinfo->lconv->_W_int_curr_symbol || !loc->locinfo->lconv->_W_currency_symbol + || !loc->locinfo->lconv->_W_mon_decimal_point || !loc->locinfo->lconv->_W_mon_thousands_sep + || !loc->locinfo->lconv->positive_sign || !loc->locinfo->lconv->negative_sign) { + MSVCRT__free_locale(loc); + return NULL; + } + + loc->locinfo->lconv->_W_int_curr_symbol[0] = '\0'; + loc->locinfo->lconv->_W_currency_symbol[0] = '\0'; + loc->locinfo->lconv->_W_mon_decimal_point[0] = '\0'; + loc->locinfo->lconv->_W_mon_thousands_sep[0] = '\0'; + loc->locinfo->lconv->_W_positive_sign[0] = '\0'; + loc->locinfo->lconv->_W_negative_sign[0] = '\0'; +#endif + loc->locinfo->lc_category[MSVCRT_LC_MONETARY].locale = MSVCRT__strdup("C"); } @@ -1177,6 +1270,27 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) MSVCRT__free_locale(loc); return NULL; } + +#if _MSVCR_VER >= 120 + i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } + + i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + if(i && (loc->locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t)))) + memcpy(loc->locinfo->lconv->_W_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t)); + else { + MSVCRT__free_locale(loc); + return NULL; + } +#endif + } else { loc->locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2])); loc->locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char)); @@ -1192,6 +1306,20 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) loc->locinfo->lconv->thousands_sep[0] = '\0'; loc->locinfo->lconv->grouping[0] = '\0'; +#if _MSVCR_VER >= 120 + loc->locinfo->lconv->_W_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t[2])); + loc->locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t)); + + if(!loc->locinfo->lconv->_W_decimal_point || !loc->locinfo->lconv->_W_thousands_sep) { + MSVCRT__free_locale(loc); + return NULL; + } + + loc->locinfo->lconv->_W_decimal_point[0] = '.'; + loc->locinfo->lconv->_W_decimal_point[1] = '\0'; + loc->locinfo->lconv->_W_thousands_sep[0] = '\0'; +#endif + loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale = MSVCRT__strdup("C"); } @@ -1357,6 +1485,22 @@ char* CDECL MSVCRT_setlocale(int category, const char* locale) (void**)&loc->locinfo->lconv->positive_sign); swap_pointers((void**)&locinfo->lconv->negative_sign, (void**)&loc->locinfo->lconv->negative_sign); + +#if _MSVCR_VER >= 120 + swap_pointers((void**)&locinfo->lconv->_W_int_curr_symbol, + (void**)&loc->locinfo->lconv->_W_int_curr_symbol); + swap_pointers((void**)&locinfo->lconv->_W_currency_symbol, + (void**)&loc->locinfo->lconv->_W_currency_symbol); + swap_pointers((void**)&locinfo->lconv->_W_mon_decimal_point, + (void**)&loc->locinfo->lconv->_W_mon_decimal_point); + swap_pointers((void**)&locinfo->lconv->_W_mon_thousands_sep, + (void**)&loc->locinfo->lconv->_W_mon_thousands_sep); + swap_pointers((void**)&locinfo->lconv->_W_positive_sign, + (void**)&loc->locinfo->lconv->_W_positive_sign); + swap_pointers((void**)&locinfo->lconv->_W_negative_sign, + (void**)&loc->locinfo->lconv->_W_negative_sign); +#endif + locinfo->lconv->int_frac_digits = loc->locinfo->lconv->int_frac_digits; locinfo->lconv->frac_digits = loc->locinfo->lconv->frac_digits; locinfo->lconv->p_cs_precedes = loc->locinfo->lconv->p_cs_precedes; @@ -1384,6 +1528,13 @@ char* CDECL MSVCRT_setlocale(int category, const char* locale) swap_pointers((void**)&locinfo->lconv->grouping, (void**)&loc->locinfo->lconv->grouping); +#if _MSVCR_VER >= 120 + swap_pointers((void**)&locinfo->lconv->_W_decimal_point, + (void**)&loc->locinfo->lconv->_W_decimal_point); + swap_pointers((void**)&locinfo->lconv->_W_thousands_sep, + (void**)&loc->locinfo->lconv->_W_thousands_sep); +#endif + if(category != MSVCRT_LC_ALL) break; /* fall through */ diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 72d529d7982..f3970877914 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -366,6 +366,16 @@ struct MSVCRT_lconv { char n_sep_by_space; char p_sign_posn; char n_sign_posn; +#if _MSVCR_VER >= 120 + MSVCRT_wchar_t* _W_decimal_point; + MSVCRT_wchar_t* _W_thousands_sep; + MSVCRT_wchar_t* _W_int_curr_symbol; + MSVCRT_wchar_t* _W_currency_symbol; + MSVCRT_wchar_t* _W_mon_decimal_point; + MSVCRT_wchar_t* _W_mon_thousands_sep; + MSVCRT_wchar_t* _W_positive_sign; + MSVCRT_wchar_t* _W_negative_sign; +#endif }; struct MSVCRT__exception {