diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 042437e7fc7..eb8028dce33 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -834,7 +834,7 @@ @ stub _iswxdigit_l @ stub _isxdigit_l @ cdecl _itoa(long ptr long) msvcrt._itoa -@ stub _itoa_s +@ cdecl _itoa_s(long ptr long long) msvcrt._itoa_s @ cdecl _itow(long ptr long) msvcrt._itow @ stub _itow_s @ cdecl _j0(double) msvcrt._j0 diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index c1d18d6ac97..b5be55fdd4c 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -680,7 +680,7 @@ @ stub _iswxdigit_l @ stub _isxdigit_l @ cdecl _itoa(long ptr long) msvcrt._itoa -@ stub _itoa_s +@ cdecl _itoa_s(long ptr long long) msvcrt._itoa_s @ cdecl _itow(long ptr long) msvcrt._itow @ stub _itow_s @ cdecl _j0(double) msvcrt._j0 diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 6d5d5186550..5647b134230 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -668,7 +668,7 @@ @ stub _iswxdigit_l @ stub _isxdigit_l @ cdecl _itoa(long ptr long) msvcrt._itoa -@ stub _itoa_s +@ cdecl _itoa_s(long ptr long long) msvcrt._itoa_s @ cdecl _itow(long ptr long) msvcrt._itow @ stub _itow_s @ cdecl _j0(double) msvcrt._j0 diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index e628e489efe..b9647241770 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -607,7 +607,7 @@ # stub _iswxdigit_l # stub _isxdigit_l @ cdecl _itoa(long ptr long) ntdll._itoa -# stub _itoa_s +@ cdecl _itoa_s(long ptr long long) @ cdecl _itow(long ptr long) ntdll._itow # stub _itow_s @ cdecl _j0(double) diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index f44e6ebf7e9..0b1beae63d6 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -636,6 +636,81 @@ unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int bas return MSVCRT_strtoui64_l(nptr, endptr, base, NULL); } +/********************************************************************* + * _itoa_s (MSVCRT.@) + */ +int CDECL _itoa_s(int value, char *str, MSVCRT_size_t size, int radix) +{ + unsigned int val, digit; + int is_negative; + char buffer[33], *pos; + size_t len; + + if (!str || !size || radix < 2 || radix > 36) + { + if (str && size) + str[0] = '\0'; + + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + if (value < 0 && radix == 10) + { + is_negative = 1; + val = -value; + } + else + { + is_negative = 0; + val = value; + } + + pos = buffer + 32; + *pos = '\0'; + + do + { + digit = val % radix; + val /= radix; + + if (digit < 10) + *--pos = '0' + digit; + else + *--pos = 'a' + digit - 10; + } + while (val != 0); + + if (is_negative) + *--pos = '-'; + + len = buffer + 33 - pos; + if (len > size) + { + size_t i; + char *p = str; + + /* Copy the temporary buffer backwards up to the available number of + * characters. Don't copy the negative sign if present. */ + + if (is_negative) + { + p++; + size--; + } + + for (pos = buffer + 31, i = 0; i < size; i++) + *p++ = *pos--; + + str[0] = '\0'; + *MSVCRT__errno() = MSVCRT_ERANGE; + return MSVCRT_ERANGE; + } + + memcpy(str, pos, len); + return 0; +} + /********************************************************************* * _ui64toa_s (MSVCRT.@) */ diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 0ea1198eac8..4955f75ca36 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -59,6 +59,7 @@ static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int); static int (__cdecl *pwcstombs_s)(size_t*,char*,size_t,const wchar_t*,size_t); static int (__cdecl *pmbstowcs_s)(size_t*,wchar_t*,size_t,const char*,size_t); static errno_t (__cdecl *p_gcvt_s)(char*,size_t,double,int); +static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int); static int *p__mb_cur_max; static unsigned char *p_mbctype; @@ -1277,6 +1278,98 @@ static void test_gcvt(void) ok(buf[0] == '\0', "buf[0] = %c\n", buf[0]); } +static void test__itoa_s(void) +{ + errno_t ret; + char buffer[33]; + + if (!p_itoa_s) + { + win_skip("Skipping _itoa_s tests\n"); + return; + } + + errno = EBADF; + ret = p_itoa_s(0, NULL, 0, 0); + ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(0, buffer, 0, 0); + ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n"); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(0, buffer, sizeof(buffer), 0); + ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n"); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(0, buffer, sizeof(buffer), 64); + ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n"); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(12345678, buffer, 4, 10); + ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret); + ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno); + ok(!memcmp(buffer, "\000765", 4), + "Expected the output buffer to be null terminated with truncated output\n"); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(12345678, buffer, 8, 10); + ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret); + ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno); + ok(!memcmp(buffer, "\0007654321", 8), + "Expected the output buffer to be null terminated with truncated output\n"); + + memset(buffer, 'X', sizeof(buffer)); + errno = EBADF; + ret = p_itoa_s(-12345678, buffer, 9, 10); + ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret); + ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno); + ok(!memcmp(buffer, "\00087654321", 9), + "Expected the output buffer to be null terminated with truncated output\n"); + + ret = p_itoa_s(12345678, buffer, 9, 10); + ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "12345678"), + "Expected output buffer string to be \"12345678\", got \"%s\"\n", + buffer); + + ret = p_itoa_s(43690, buffer, sizeof(buffer), 2); + ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "1010101010101010"), + "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n", + buffer); + + ret = p_itoa_s(1092009, buffer, sizeof(buffer), 36); + ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "nell"), + "Expected output buffer string to be \"nell\", got \"%s\"\n", + buffer); + + ret = p_itoa_s(5704, buffer, sizeof(buffer), 18); + ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "hag"), + "Expected output buffer string to be \"hag\", got \"%s\"\n", + buffer); + + ret = p_itoa_s(-12345678, buffer, sizeof(buffer), 10); + ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "-12345678"), + "Expected output buffer string to be \"-12345678\", got \"%s\"\n", + buffer); +} + START_TEST(string) { char mem[100]; @@ -1302,6 +1395,7 @@ START_TEST(string) pmbstowcs_s = (void *)GetProcAddress(hMsvcrt, "mbstowcs_s"); pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s"); p_gcvt_s = (void *)GetProcAddress(hMsvcrt, "_gcvt_s"); + p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s"); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -1336,4 +1430,5 @@ START_TEST(string) test__strtod(); test_mbstowcs(); test_gcvt(); + test__itoa_s(); } diff --git a/include/msvcrt/stdlib.h b/include/msvcrt/stdlib.h index bef83f4b10c..086c3e141fa 100644 --- a/include/msvcrt/stdlib.h +++ b/include/msvcrt/stdlib.h @@ -148,6 +148,7 @@ char* __cdecl _fullpath(char*,const char*,size_t); char* __cdecl _gcvt(double,int,char*); char* __cdecl _i64toa(__int64,char*,int); char* __cdecl _itoa(int,char*,int); +errno_t __cdecl _itoa_s(int,char*,size_t,int); char* __cdecl _ltoa(__msvcrt_long,char*,int); __msvcrt_ulong __cdecl _lrotl(__msvcrt_ulong,int); __msvcrt_ulong __cdecl _lrotr(__msvcrt_ulong,int);