From: André Hentschel Subject: msvcrt: Add bsearch_s implementation by reusing code and tests from ntdll (try 5) Message-Id: <4F85D354.9020800@dawncrow.de> Date: Wed, 11 Apr 2012 20:54:12 +0200 --- dlls/msvcr100/msvcr100.spec | 2 +- dlls/msvcr80/msvcr80.spec | 2 +- dlls/msvcr90/msvcr90.spec | 2 +- dlls/msvcrt/misc.c | 32 ++++++++++++++ dlls/msvcrt/msvcrt.spec | 2 +- dlls/msvcrt/tests/misc.c | 97 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 4 deletions(-) diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index ade980c..5c424b1 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -1434,7 +1434,7 @@ @ cdecl atoi(str) msvcrt.atoi @ cdecl atol(str) msvcrt.atol @ cdecl bsearch(ptr ptr long long ptr) msvcrt.bsearch -@ stub bsearch_s +@ cdecl bsearch_s(ptr ptr long long ptr ptr) msvcrt.bsearch_s @ cdecl btowc(long) msvcrt.btowc @ cdecl calloc(long long) msvcrt.calloc @ cdecl ceil(double) msvcrt.ceil diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index d4d7a86..410e294 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -1290,7 +1290,7 @@ @ cdecl atoi(str) msvcrt.atoi @ cdecl atol(str) msvcrt.atol @ cdecl bsearch(ptr ptr long long ptr) msvcrt.bsearch -@ stub bsearch_s +@ cdecl bsearch_s(ptr ptr long long ptr ptr) msvcrt.bsearch_s @ cdecl btowc(long) msvcrt.btowc @ cdecl calloc(long long) msvcrt.calloc @ cdecl ceil(double) msvcrt.ceil diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 70bc2b3..98bde4d 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -1285,7 +1285,7 @@ @ cdecl atoi(str) msvcrt.atoi @ cdecl atol(str) msvcrt.atol @ cdecl bsearch(ptr ptr long long ptr) msvcrt.bsearch -@ stub bsearch_s +@ cdecl bsearch_s(ptr ptr long long ptr ptr) msvcrt.bsearch_s @ cdecl btowc(long) msvcrt.btowc @ cdecl calloc(long long) msvcrt.calloc @ cdecl ceil(double) msvcrt.ceil diff --git a/dlls/msvcrt/misc.c b/dlls/msvcrt/misc.c index d40e38f..754b7d1 100644 --- a/dlls/msvcrt/misc.c +++ b/dlls/msvcrt/misc.c @@ -124,6 +124,38 @@ void* CDECL _lsearch(const void* match, void* start, } /********************************************************************* + * bsearch_s (msvcrt.@) + */ +void* CDECL MSVCRT_bsearch_s(const void *key, const void *base, + MSVCRT_size_t nmemb, MSVCRT_size_t size, + int (__cdecl *compare)(void *, const void *, const void *), void *ctx) +{ + ssize_t min = 0; + ssize_t max; + + if (!MSVCRT_CHECK_PMT(key != NULL) || !MSVCRT_CHECK_PMT(base != NULL) || + !MSVCRT_CHECK_PMT(size != 0) || !MSVCRT_CHECK_PMT(compare != NULL)) + { + *MSVCRT__errno() = MSVCRT_EINVAL; + return NULL; + } + + max = nmemb - 1; + while (min <= max) + { + ssize_t cursor = (min + max) / 2; + int ret = compare(ctx, key,(const char *)base+(cursor*size)); + if (!ret) + return (char*)base+(cursor*size); + if (ret < 0) + max = cursor - 1; + else + min = cursor + 1; + } + return NULL; +} + +/********************************************************************* * _chkesp (MSVCRT.@) * * Trap to a debugger if the value of the stack pointer has changed. diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 04ef9ad..934c247 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -1226,7 +1226,7 @@ @ cdecl atoi(str) ntdll.atoi @ cdecl atol(str) ntdll.atol @ cdecl bsearch(ptr ptr long long ptr) ntdll.bsearch -# stub bsearch_s(ptr ptr long long ptr ptr) +@ cdecl bsearch_s(ptr ptr long long ptr ptr) MSVCRT_bsearch_s @ cdecl btowc(long) MSVCRT_btowc @ cdecl calloc(long long) MSVCRT_calloc @ cdecl ceil(double) MSVCRT_ceil diff --git a/dlls/msvcrt/tests/misc.c b/dlls/msvcrt/tests/misc.c index 7135248..b72e309 100644 --- a/dlls/msvcrt/tests/misc.c +++ b/dlls/msvcrt/tests/misc.c @@ -26,10 +26,15 @@ static int (__cdecl *prand_s)(unsigned int *); static int (__cdecl *pmemcpy_s)(void *, MSVCRT_size_t, void*, MSVCRT_size_t); static int (__cdecl *pI10_OUTPUT)(long double, int, int, void*); static int (__cdecl *pstrerror_s)(char *, MSVCRT_size_t, int); +static void* (__cdecl *pbsearch_s)(const void *, const void *, MSVCRT_size_t, MSVCRT_size_t, + int (__cdecl *compare)(void *, const void *, const void *), void *); static int (__cdecl *p_get_doserrno)(int *); static int (__cdecl *p_get_errno)(int *); static int (__cdecl *p_set_doserrno)(int); static int (__cdecl *p_set_errno)(int); +static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler); + +static int invalid_parameter_cnt; static void init(void) { @@ -39,10 +44,19 @@ static void init(void) pmemcpy_s = (void*)GetProcAddress(hmod, "memcpy_s"); pI10_OUTPUT = (void*)GetProcAddress(hmod, "$I10_OUTPUT"); pstrerror_s = (void *)GetProcAddress(hmod, "strerror_s"); + pbsearch_s = (void *)GetProcAddress(hmod, "bsearch_s"); p_get_doserrno = (void *)GetProcAddress(hmod, "_get_doserrno"); p_get_errno = (void *)GetProcAddress(hmod, "_get_errno"); p_set_doserrno = (void *)GetProcAddress(hmod, "_set_doserrno"); p_set_errno = (void *)GetProcAddress(hmod, "_set_errno"); + p_set_invalid_parameter_handler = (void *)GetProcAddress(hmod, "_set_invalid_parameter_handler"); +} + +static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, + const wchar_t *function, const wchar_t *file, + unsigned line, uintptr_t arg) +{ + invalid_parameter_cnt++; } static void test_rand_s(void) @@ -260,6 +274,88 @@ static void test_strerror_s(void) ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret); } +static int __cdecl intcomparefunc(void* ctx, const void *a, const void *b) +{ + const int *p = a, *q = b; + + ok(a != b, "must never get the same pointer\n"); + ok(ctx == pbsearch_s, "Got the wrong context pointer: %p\n", ctx); + + return *p - *q; +} + +static void test_bsearch_s(void) +{ + int arr[7] = { 1, 3, 4, 8, 16, 23, 42 }; + int *x, l, i, j = 1; + + if (!pbsearch_s) + { + win_skip("bsearch_s is not available\n"); + return; + } + + if (p_set_invalid_parameter_handler) + { + ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, + "Invalid parameter handler was already set\n"); + + invalid_parameter_cnt = 0; + errno = 0xdeadbeef; + x = pbsearch_s(NULL, NULL, 0, 0, NULL, NULL); + ok(x == NULL, "Expected bsearch_s to return NULL, got %p\n", x); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(invalid_parameter_cnt == 1, "Expected invalid_parameter_handler to be called once, got %i\n", + invalid_parameter_cnt); + + errno = 0xdeadbeef; + x = pbsearch_s(NULL, arr, j, sizeof(arr[0]), intcomparefunc, pbsearch_s); + ok(x == NULL, "Expected bsearch_s to return NULL, got %p\n", x); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(invalid_parameter_cnt == 2, "Expected invalid_parameter_handler to be called 2 times, got %i\n", + invalid_parameter_cnt); + + errno = 0xdeadbeef; + x = pbsearch_s(&l, NULL, j, sizeof(arr[0]), intcomparefunc, pbsearch_s); + ok(x == NULL, "Expected bsearch_s to return NULL, got %p\n", x); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(invalid_parameter_cnt == 3, "Expected invalid_parameter_handler to be called 3 times, got %i\n", + invalid_parameter_cnt); + + errno = 0xdeadbeef; + x = pbsearch_s(&l, arr, j, 0, intcomparefunc, pbsearch_s); + ok(x == NULL, "Expected bsearch_s to return NULL, got %p\n", x); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(invalid_parameter_cnt == 4, "Expected invalid_parameter_handler to be called 5 times, got %i\n", + invalid_parameter_cnt); + + errno = 0xdeadbeef; + x = pbsearch_s(&l, arr, j, sizeof(arr[0]), NULL, pbsearch_s); + ok(x == NULL, "Expected bsearch_s to return NULL, got %p\n", x); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(invalid_parameter_cnt == 5, "Expected invalid_parameter_handler to be called 6 times, got %i\n", + invalid_parameter_cnt); + } + + /* just try all array sizes */ + for (j=1;j