diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index eb8028dce33..60211ab1684 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -1142,7 +1142,7 @@ @ stub _stricoll_l @ cdecl _strlwr(str) msvcrt._strlwr @ stub _strlwr_l -@ stub _strlwr_s +@ cdecl _strlwr_s(ptr long) msvcrt._strlwr_s @ stub _strlwr_s_l @ stub _strncoll @ stub _strncoll_l diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index b5be55fdd4c..4b0363ffab0 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -996,7 +996,7 @@ @ stub _stricoll_l @ cdecl _strlwr(str) msvcrt._strlwr @ stub _strlwr_l -@ stub _strlwr_s +@ cdecl _strlwr_s(ptr long) msvcrt._strlwr_s @ stub _strlwr_s_l @ stub _strncoll @ stub _strncoll_l diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 5647b134230..967db82247f 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -982,7 +982,7 @@ @ stub _stricoll_l @ cdecl _strlwr(str) msvcrt._strlwr @ stub _strlwr_l -@ stub _strlwr_s +@ cdecl _strlwr_s(ptr long) msvcrt._strlwr_s @ stub _strlwr_s_l @ stub _strncoll @ stub _strncoll_l diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index b9647241770..e6a8670ab40 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -917,7 +917,7 @@ # stub _stricoll_l @ cdecl _strlwr(str) ntdll._strlwr # stub _strlwr_l -# stub _strlwr_s +@ cdecl _strlwr_s(ptr long) # stub _strlwr_s_l @ stub _strncoll #(str str long) # stub _strncoll_l diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 0b1beae63d6..02bd0a5d539 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -50,6 +50,41 @@ char* CDECL _strdup(const char* str) else return 0; } +/********************************************************************* + * _strlwr_s (MSVCRT.@) + */ +int CDECL _strlwr_s(char *str, MSVCRT_size_t len) +{ + char *ptr = str; + + if (!str || !len) + { + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + while (len && *ptr) + { + len--; + ptr++; + } + + if (!len) + { + str[0] = '\0'; + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + while (*str) + { + *str = tolower(*str); + str++; + } + + return 0; +} + /********************************************************************* * _strnset (MSVCRT.@) */ diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 4955f75ca36..a7d033ab5e9 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -60,6 +60,7 @@ 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 errno_t (__cdecl *p_strlwr_s)(char*,size_t); static int *p__mb_cur_max; static unsigned char *p_mbctype; @@ -1370,6 +1371,63 @@ static void test__itoa_s(void) buffer); } +static void test__strlwr_s(void) +{ + errno_t ret; + char buffer[20]; + + if (!p_strlwr_s) + { + win_skip("Skipping _strlwr_s tests\n"); + return; + } + + errno = EBADF; + ret = p_strlwr_s(NULL, 0); + ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + errno = EBADF; + ret = p_strlwr_s(NULL, sizeof(buffer)); + ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + errno = EBADF; + ret = p_strlwr_s(buffer, 0); + ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + strcpy(buffer, "GoRrIsTeR"); + errno = EBADF; + ret = p_strlwr_s(buffer, 5); + ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(!memcmp(buffer, "\0oRrIsTeR", sizeof("\0oRrIsTeR")), + "Expected the output buffer to be \"gorrIsTeR\"\n"); + + strcpy(buffer, "GoRrIsTeR"); + errno = EBADF; + ret = p_strlwr_s(buffer, sizeof("GoRrIsTeR") - 1); + ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(!memcmp(buffer, "\0oRrIsTeR", sizeof("\0oRrIsTeR")), + "Expected the output buffer to be \"gorrIsTeR\"\n"); + + strcpy(buffer, "GoRrIsTeR"); + ret = p_strlwr_s(buffer, sizeof("GoRrIsTeR")); + ok(ret == 0, "Expected _strlwr_s to return 0, got %d\n", ret); + ok(!strcmp(buffer, "gorrister"), + "Expected the output buffer to be \"gorrister\", got \"%s\"\n", + buffer); + + memcpy(buffer, "GoRrIsTeR\0ELLEN", sizeof("GoRrIsTeR\0ELLEN")); + ret = p_strlwr_s(buffer, sizeof(buffer)); + ok(ret == 0, "Expected _strlwr_s to return 0, got %d\n", ret); + ok(!memcmp(buffer, "gorrister\0ELLEN", sizeof("gorrister\0ELLEN")), + "Expected the output buffer to be \"gorrister\\0ELLEN\", got \"%s\"\n", + buffer); +} + START_TEST(string) { char mem[100]; @@ -1396,6 +1454,7 @@ START_TEST(string) pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s"); p_gcvt_s = (void *)GetProcAddress(hMsvcrt, "_gcvt_s"); p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s"); + p_strlwr_s = (void *)GetProcAddress(hMsvcrt, "_strlwr_s"); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -1431,4 +1490,5 @@ START_TEST(string) test_mbstowcs(); test_gcvt(); test__itoa_s(); + test__strlwr_s(); } diff --git a/include/msvcrt/string.h b/include/msvcrt/string.h index 614fa857a98..8ab459ba6c4 100644 --- a/include/msvcrt/string.h +++ b/include/msvcrt/string.h @@ -48,6 +48,7 @@ errno_t __cdecl strerror_s(char*,size_t,int); int __cdecl _stricmp(const char*,const char*); int __cdecl _stricoll(const char*,const char*); char* __cdecl _strlwr(char*); +errno_t __cdecl _strlwr_s(char*,size_t); int __cdecl _strnicmp(const char*,const char*,size_t); char* __cdecl _strnset(char*,int,size_t); char* __cdecl _strrev(char*);