diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 7512d91acab..e44ad0f85e5 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -958,8 +958,8 @@ @ cdecl _strtime(ptr) msvcrt._strtime @ stub _strtime_s @ stub _strtod_l -@ stub _strtoi64 -@ stub _strtoi64_l +@ cdecl _strtoi64(str ptr long) msvcrt._strtoi64 +@ cdecl _strtoi64_l(str ptr long ptr) msvcrt._strtoi64_l @ stub _strtol_l @ stub _strtoui64 @ stub _strtoui64_l diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 74b1614a19e..1cec19c68b4 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -944,8 +944,8 @@ @ cdecl _strtime(ptr) msvcrt._strtime @ stub _strtime_s @ stub _strtod_l -@ stub _strtoi64 -@ stub _strtoi64_l +@ cdecl _strtoi64(str ptr long) msvcrt._strtoi64 +@ cdecl _strtoi64_l(str ptr long ptr) msvcrt._strtoi64_l @ stub _strtol_l @ stub _strtoui64 @ stub _strtoui64_l diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 6df324e05bb..3f231ac7159 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -43,6 +43,9 @@ #define MSVCRT_LONG_MAX 0x7fffffffL #define MSVCRT_ULONG_MAX 0xffffffffUL +#define MSVCRT_I64_MAX (((__int64)0x7fffffff << 32) | 0xffffffff) +#define MSVCRT_I64_MIN (-MSVCRT_I64_MAX-1) +#define MSVCRT_UI64_MAX (((unsigned __int64)0xffffffff << 32) | 0xffffffff) typedef unsigned short MSVCRT_wchar_t; typedef unsigned short MSVCRT_wint_t; @@ -739,6 +742,47 @@ int __cdecl MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, __ms_va_list valist ); int __cdecl MSVCRT_raise(int sig); +typedef struct MSVCRT_tagLC_ID { + unsigned short wLanguage; + unsigned short wCountry; + unsigned short wCodePage; +} MSVCRT_LC_ID, *MSVCRT_LPLC_ID; + +typedef struct MSVCRT_threadlocaleinfostruct { + int refcount; + unsigned int lc_codepage; + unsigned int lc_collate_cp; + unsigned long lc_handle[6]; + MSVCRT_LC_ID lc_id[6]; + struct { + char *locale; + wchar_t *wlocale; + int *refcount; + int *wrefcount; + } lc_category[6]; + int lc_clike; + int mb_cur_max; + int *lconv_intl_refcount; + int *lconv_num_refcount; + int *lconv_mon_refcount; + struct lconv *lconv; + int *ctype1_refcount; + unsigned short *ctype1; + const unsigned short *pctype; + const unsigned char *pclmap; + const unsigned char *pcumap; + struct __lc_time_data *lc_time_curr; +} MSVCRT_threadlocinfo; + +typedef struct MSVCRT_threadlocaleinfostruct *MSVCRT_pthreadlocinfo; +typedef struct MSVCRT_threadmbcinfostruct *MSVCRT_pthreadmbcinfo; + +typedef struct MSVCRT_localeinfo_struct +{ + MSVCRT_pthreadlocinfo locinfo; + MSVCRT_pthreadmbcinfo mbcinfo; +} MSVCRT__locale_tstruct, *MSVCRT__locale_t; + #ifndef __WINE_MSVCRT_TEST int __cdecl MSVCRT__write(int,const void*,unsigned int); int __cdecl _getch(void); diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 5eec07f9290..d25bcc43d62 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -891,8 +891,8 @@ @ cdecl _strtime(ptr) # stub _strtime_s # stub _strtod_l -# stub _strtoi64 -# stub _strtoi64_l +@ cdecl _strtoi64(str ptr long) MSVCRT_strtoi64 +@ cdecl _strtoi64_l(str ptr long ptr) MSVCRT_strtoi64_l # stub _strtol_l # stub _strtoui64 # stub _strtoui64_l diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index e3c36d296f9..d64cd45dd35 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -327,3 +327,83 @@ MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen) return i; } + +/********************************************************************* + * _strtoi64_l (MSVCR90.@) + * + * FIXME: locale parameter is ignored + */ +__int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale) +{ + BOOL negative = FALSE; + __int64 ret = 0; + + TRACE("(%s %p %d %p)\n", nptr, endptr, base, locale); + + if(!nptr || base<0 || base>36 || base==1) { + MSVCRT_invalid_parameter(NULL, NULL, NULL, 0, NULL); + return 0; + } + + while(isspace(*nptr)) nptr++; + + if(*nptr == '-') { + negative = TRUE; + nptr++; + } else if(*nptr == '+') + nptr++; + + if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') { + base = 16; + nptr += 2; + } + + if(base == 0) { + if(*nptr=='0') + base = 8; + else + base = 10; + } + + while(*nptr) { + char cur = tolower(*nptr); + int v; + + if(isdigit(cur)) { + if(cur >= '0'+base) + break; + v = cur-'0'; + } else { + if(cur<'a' || cur>='a'+base-10) + break; + v = cur-'a'+10; + } + + if(negative) + v = -v; + + nptr++; + + if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) { + ret = MSVCRT_I64_MAX; + *MSVCRT__errno() = ERANGE; + } else if(negative && (ret #include #include +#include static char *buf_to_string(const unsigned char *bin, int len, int nr) { @@ -53,6 +54,7 @@ static int (__cdecl *p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsig static int (__cdecl *p_wcscpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc); static int (__cdecl *p_wcsupr_s)(wchar_t *str, size_t size); static size_t (__cdecl *p_strnlen)(const char *, size_t); +static __int64 (__cdecl *p_strtoi64)(const char *, char **, int); static _invalid_parameter_handler *p_invalid_parameter; static int *p__mb_cur_max; static unsigned char *p_mbctype; @@ -944,6 +946,125 @@ static void test_strnlen(void) ok(res == 0, "Returned length = %d\n", (int)res); } +static void test__strtoi64(void) +{ + static const char no1[] = "31923"; + static const char no2[] = "-213312"; + static const char no3[] = "12aa"; + static const char no4[] = "abc12"; + static const char overflow[] = "99999999999999999999"; + static const char neg_overflow[] = "-99999999999999999999"; + static const char hex[] = "0x123"; + static const char oct[] = "000123"; + static const char blanks[] = " 12 212.31"; + + __int64 res; + char *endpos; + + if(!p_strtoi64) { + win_skip("_strtoi64 not found\n"); + return; + } + + if(p_invalid_parameter) { + errno = 0xdeadbeef; + res = p_strtoi64(NULL, NULL, 10); + ok(res == 0, "res != 0\n"); + res = p_strtoi64(no1, NULL, 1); + ok(res == 0, "res != 0\n"); + res = p_strtoi64(no1, NULL, 37); + ok(res == 0, "res != 0\n"); + ok(errno == 0xdeadbeef, "errno = %x\n", errno); + } + + errno = 0xdeadbeef; + res = p_strtoi64(no1, NULL, 10); + ok(res == 31923, "res != 31923\n"); + res = p_strtoi64(no2, NULL, 10); + ok(res == -213312, "res != -213312\n"); + res = p_strtoi64(no3, NULL, 10); + ok(res == 12, "res != 12\n"); + res = p_strtoi64(no4, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == no4, "Scanning was not stopped on first character\n"); + res = p_strtoi64(hex, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == hex+1, "Incorrect endpos (%p-%p)\n", hex, endpos); + res = p_strtoi64(oct, &endpos, 10); + ok(res == 123, "res != 123\n"); + ok(endpos == oct+strlen(oct), "Incorrect endpos (%p-%p)\n", oct, endpos); + res = p_strtoi64(blanks, &endpos, 10); + ok(res == 12, "res != 12"); + ok(endpos == blanks+10, "Incorrect endpos (%p-%p)\n", blanks, endpos); + ok(errno == 0xdeadbeef, "errno = %x\n", errno); + + errno = 0xdeadbeef; + res = p_strtoi64(overflow, &endpos, 10); + ok(res == _I64_MAX, "res != _I64_MAX\n"); + ok(endpos == overflow+strlen(overflow), "Incorrect endpos (%p-%p)\n", overflow, endpos); + ok(errno == ERANGE, "errno = %x\n", errno); + + errno = 0xdeadbeef; + res = p_strtoi64(neg_overflow, &endpos, 10); + ok(res == _I64_MIN, "res != _I64_MIN\n"); + ok(endpos == neg_overflow+strlen(neg_overflow), "Incorrect endpos (%p-%p)\n", neg_overflow, endpos); + ok(errno == ERANGE, "errno = %x\n", errno); + + errno = 0xdeadbeef; + res = p_strtoi64(no1, &endpos, 16); + ok(res == 203043, "res != 203043\n"); + ok(endpos == no1+strlen(no1), "Incorrect endpos (%p-%p)\n", no1, endpos); + res = p_strtoi64(no2, &endpos, 16); + ok(res == -2175762, "res != -2175762\n"); + ok(endpos == no2+strlen(no2), "Incorrect endpos (%p-%p)\n", no2, endpos); + res = p_strtoi64(no3, &endpos, 16); + ok(res == 4778, "res != 4778\n"); + ok(endpos == no3+strlen(no3), "Incorrect endpos (%p-%p)\n", no3, endpos); + res = p_strtoi64(no4, &endpos, 16); + ok(res == 703506, "res != 703506\n"); + ok(endpos == no4+strlen(no4), "Incorrect endpos (%p-%p)\n", no4, endpos); + res = p_strtoi64(hex, &endpos, 16); + ok(res == 291, "res != 291\n"); + ok(endpos == hex+strlen(hex), "Incorrect endpos (%p-%p)\n", hex, endpos); + res = p_strtoi64(oct, &endpos, 16); + ok(res == 291, "res != 291\n"); + ok(endpos == oct+strlen(oct), "Incorrect endpos (%p-%p)\n", oct, endpos); + res = p_strtoi64(blanks, &endpos, 16); + ok(res == 18, "res != 18\n"); + ok(endpos == blanks+10, "Incorrect endpos (%p-%p)\n", blanks, endpos); + ok(errno == 0xdeadbeef, "errno = %x\n", errno); + + errno = 0xdeadbeef; + res = p_strtoi64(hex, &endpos, 36); + ok(res == 1541019, "res != 1541019\n"); + ok(endpos == hex+strlen(hex), "Incorrect endpos (%p-%p)\n", hex, endpos); + ok(errno == 0xdeadbeef, "errno = %x\n", errno); + + errno = 0xdeadbeef; + res = p_strtoi64(no1, &endpos, 0); + ok(res == 31923, "res != 31923\n"); + ok(endpos == no1+strlen(no1), "Incorrect endpos (%p-%p)\n", no1, endpos); + res = p_strtoi64(no2, &endpos, 0); + ok(res == -213312, "res != -213312\n"); + ok(endpos == no2+strlen(no2), "Incorrect endpos (%p-%p)\n", no2, endpos); + res = p_strtoi64(no3, &endpos, 10); + ok(res == 12, "res != 12\n"); + ok(endpos == no3+2, "Incorrect endpos (%p-%p)\n", no3, endpos); + res = p_strtoi64(no4, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == no4, "Incorrect endpos (%p-%p)\n", no4, endpos); + res = p_strtoi64(hex, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == hex+1, "Incorrect endpos (%p-%p)\n", hex, endpos); + res = p_strtoi64(oct, &endpos, 10); + ok(res == 123, "res != 123\n"); + ok(endpos == oct+strlen(oct), "Incorrect endpos (%p-%p)\n", oct, endpos); + res = p_strtoi64(blanks, &endpos, 10); + ok(res == 12, "res != 12\n"); + ok(endpos == blanks+10, "Incorrect endpos (%p-%p)\n", blanks, endpos); + ok(errno == 0xdeadbeef, "errno = %x\n", errno); +} + START_TEST(string) { char mem[100]; @@ -967,6 +1088,7 @@ START_TEST(string) p_wcscpy_s = (void *)GetProcAddress( hMsvcrt,"wcscpy_s" ); p_wcsupr_s = (void *)GetProcAddress( hMsvcrt,"_wcsupr_s" ); p_strnlen = (void *)GetProcAddress( hMsvcrt,"strnlen" ); + p_strtoi64 = (void *) GetProcAddress(hMsvcrt, "_strtoi64"); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -997,4 +1119,5 @@ START_TEST(string) test__wcsupr_s(); test_strtol(); test_strnlen(); + test__strtoi64(); }