···11+/*
22+ * Conformance tests for *scanf functions.
33+ *
44+ * Copyright 2002 Uwe Bonnes
55+ *
66+ * This library is free software; you can redistribute it and/or
77+ * modify it under the terms of the GNU Lesser General Public
88+ * License as published by the Free Software Foundation; either
99+ * version 2.1 of the License, or (at your option) any later version.
1010+ *
1111+ * This library is distributed in the hope that it will be useful,
1212+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1414+ * Lesser General Public License for more details.
1515+ *
1616+ * You should have received a copy of the GNU Lesser General Public
1717+ * License along with this library; if not, write to the Free Software
1818+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1919+ */
2020+2121+#include <stdio.h>
2222+#include <math.h>
2323+2424+#include "windef.h"
2525+#include "winbase.h"
2626+#include "winnls.h"
2727+2828+#include "wine/test.h"
2929+3030+static int WINAPIV vsscanf_wrapper(unsigned __int64 options, const char *str, size_t len, const char *format, ...)
3131+{
3232+ int ret;
3333+ va_list valist;
3434+ va_start(valist, format);
3535+ ret = __stdio_common_vsscanf(options, str, len, format, NULL, valist);
3636+ va_end(valist);
3737+ return ret;
3838+}
3939+4040+static void test_sscanf(void)
4141+{
4242+ static const float float1 = -82.6267f, float2 = 27.76f;
4343+ char buffer[100], buffer1[100];
4444+ int result, ret, hour, min, count;
4545+ LONGLONG result64;
4646+ DWORD_PTR result_ptr;
4747+ char c;
4848+ void *ptr;
4949+ float ret_float1, ret_float2;
5050+ double double_res;
5151+ unsigned int i;
5252+ size_t ret_size;
5353+5454+ static const unsigned int tests[] =
5555+ {
5656+ 0,
5757+ _CRT_INTERNAL_SCANF_LEGACY_WIDE_SPECIFIERS,
5858+ _CRT_INTERNAL_SCANF_LEGACY_MSVCRT_COMPATIBILITY,
5959+ };
6060+6161+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
6262+ {
6363+ ret = vsscanf_wrapper(tests[i], "", -1, "%d", &result);
6464+ ok(ret == EOF, "sscanf returned %d for flags %#x\n", ret, tests[i]);
6565+6666+ ret = vsscanf_wrapper(tests[i], "000000000046F170", -1, "%p", &ptr);
6767+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
6868+ ok(ptr == (void *)0x46f170, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
6969+7070+ ret = vsscanf_wrapper(tests[i], "0046F171", -1, "%p", &ptr);
7171+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
7272+ ok(ptr == (void *)0x46f171, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
7373+7474+ ret = vsscanf_wrapper(tests[i], "46F172", -1, "%p", &ptr);
7575+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
7676+ ok(ptr == (void *)0x46f172, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
7777+7878+ ret = vsscanf_wrapper(tests[i], "0x46F173", -1, "%p", &ptr);
7979+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
8080+ todo_wine ok(ptr == (void *)0x46f173, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
8181+8282+ ret = vsscanf_wrapper(tests[i], "-46F174", -1, "%p", &ptr);
8383+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
8484+ ok(ptr == (void *)(ULONG_PTR)-0x46f174, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
8585+8686+ ret = vsscanf_wrapper(tests[i], "+46F175", -1, "%p", &ptr);
8787+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
8888+ ok(ptr == (void *)0x46f175, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
8989+9090+ ret = vsscanf_wrapper(tests[i], "1233", -1, "%p", &ptr);
9191+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
9292+ ok(ptr == (void *)0x1233, "sscanf reads %p for flags %#x\n", ptr, tests[i]);
9393+9494+ ret = vsscanf_wrapper(tests[i], "1234", -1, "%P", &ptr);
9595+ todo_wine ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
9696+9797+ ret = vsscanf_wrapper(tests[i], "0x519", -1, "%x", &result);
9898+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
9999+ ok(result == 0x519, "sscanf reads %#x for flags %#x\n", result, tests[i]);
100100+101101+ ret = vsscanf_wrapper(tests[i], "0x51a", -1, "%x", &result);
102102+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
103103+ ok(result == 0x51a, "sscanf reads %#x for flags %#x\n", result, tests[i]);
104104+105105+ ret = vsscanf_wrapper(tests[i], "0x51g", -1, "%x", &result);
106106+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
107107+ ok(result == 0x51, "sscanf reads %#x for flags %#x\n", result, tests[i]);
108108+109109+ result = 0;
110110+ ret = vsscanf_wrapper(tests[i], "-1", -1, "%x", &result);
111111+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
112112+ ok(result == -1, "sscanf reads %#x for flags %#x\n", result, tests[i]);
113113+114114+ ret = vsscanf_wrapper(tests[i], "\"%12@", -1, "%\"%%%d%@", &result);
115115+ todo_wine ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
116116+117117+ sprintf(buffer, "%f %f", float1, float2);
118118+ ret = vsscanf_wrapper(tests[i], buffer, -1, "%f%f", &ret_float1, &ret_float2);
119119+ ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
120120+ ok(ret_float1 == float1, "got wrong float %.8e for flags %#x\n", ret_float1, tests[i]);
121121+ ok(ret_float2 == float2, "got wrong float %.8e for flags %#x\n", ret_float2, tests[i]);
122122+123123+ sprintf(buffer, "%lf", 32.715);
124124+ ret = vsscanf_wrapper(tests[i], buffer, -1, "%lf", &double_res);
125125+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
126126+ ok(double_res == 32.715, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
127127+ ret = vsscanf_wrapper(tests[i], buffer, -1, "%Lf", &double_res);
128128+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
129129+ ok(double_res == 32.715, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
130130+131131+ ret = vsscanf_wrapper(tests[i], "1.1e-30", -1, "%lf", &double_res);
132132+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
133133+ ok(double_res == 1.1e-30, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
134134+135135+ ret = vsscanf_wrapper(tests[i], " Waverly", -1, "%*c%[^\n]", buffer);
136136+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
137137+ ok(!strcmp(buffer, " Waverly"), "got string '%s' for flags %#x\n", buffer, tests[i]);
138138+139139+ ret = vsscanf_wrapper(tests[i], "abcefgdh", -1, "%*[a-cg-e]%c", &buffer[0]);
140140+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
141141+ ok(buffer[0] == 'd', "got char '%c' for flags %#x\n", buffer[0], tests[i]);
142142+143143+ ret = vsscanf_wrapper(tests[i], "abcefgdh", -1, "%*[a-cd-dg-e]%c", &buffer[0]);
144144+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
145145+ ok(buffer[0] == 'h', "got char '%c' for flags %#x\n", buffer[0], tests[i]);
146146+147147+ strcpy(buffer, "foo");
148148+ strcpy(buffer1, "bar");
149149+ ret = vsscanf_wrapper(tests[i], "a", -1, "%s%s", buffer, buffer1);
150150+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
151151+ ok(!strcmp(buffer, "a"), "got string '%s' for flags %#x\n", buffer, tests[i]);
152152+ ok(!strcmp(buffer1, "bar"), "got string '%s' for flags %#x\n", buffer1, tests[i]);
153153+154154+ ret = vsscanf_wrapper(tests[i], "21:59:20", -1, "%d%n", &result, &count);
155155+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
156156+ ok(result == 21, "got wrong number %d for flags %#x\n", result, tests[i]);
157157+ ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
158158+159159+ ret = vsscanf_wrapper(tests[i], ":59:20", -1, "%*c%n", &count);
160160+ ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
161161+ ok(count == 1, "got wrong count %d for flags %#x\n", count, tests[i]);
162162+163163+ result = 0xdeadbeef;
164164+ ret = vsscanf_wrapper(tests[i], "12345678", -1, "%hd", &result);
165165+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
166166+ ok(result == 0xdead614e, "got wrong number %#x for flags %#x\n", result, tests[i]);
167167+168168+ result = 0xdeadbeef;
169169+ ret = vsscanf_wrapper(tests[i], "12345678", -1, "%hhd", &result);
170170+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
171171+ ok(result == 0xdeadbe4e, "got wrong number %#x for flags %#x\n", result, tests[i]);
172172+173173+ ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%lld", &result64);
174174+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
175175+ ok(result64 == 12345678901234, "got wrong number 0x%s for flags %#x\n",
176176+ wine_dbgstr_longlong(result64), tests[i]);
177177+178178+ ret = vsscanf_wrapper(tests[i], "123", -1, "%i", &result);
179179+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
180180+ ok(result == 123, "got wrong number %d for flags %#x\n", result, tests[i]);
181181+182182+ ret = vsscanf_wrapper(tests[i], "-1", -1, "%i", &result);
183183+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
184184+ ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
185185+186186+ ret = vsscanf_wrapper(tests[i], "123", -1, "%d", &result);
187187+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
188188+ ok(result == 123, "got wrong number %d for flags %#x\n", result, tests[i]);
189189+190190+ ret = vsscanf_wrapper(tests[i], "-1", -1, "%d", &result);
191191+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
192192+ ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
193193+194194+ ret = vsscanf_wrapper(tests[i], "017", -1, "%i", &result);
195195+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
196196+ ok(result == 15, "got wrong number %d for flags %#x\n", result, tests[i]);
197197+198198+ ret = vsscanf_wrapper(tests[i], "0x17", -1, "%i", &result);
199199+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
200200+ ok(result == 23, "got wrong number %d for flags %#x\n", result, tests[i]);
201201+202202+ ret = vsscanf_wrapper(tests[i], "-1", -1, "%o", &result);
203203+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
204204+ ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
205205+206206+ ret = 0xdeadbeef;
207207+ ret = vsscanf_wrapper(tests[i], "-1", -1, "%u", &result);
208208+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
209209+ ok(result == -1, "got wrong number %d for flags %#x\n", result, tests[i]);
210210+211211+ c = 0x55;
212212+ ret = vsscanf_wrapper(tests[i], "a", -1, "%c", &c);
213213+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
214214+ ok(c == 'a', "got wrong char '%c' for flags %#x\n", c, tests[i]);
215215+216216+ c = 0x55;
217217+ ret = vsscanf_wrapper(tests[i], " a", -1, "%c", &c);
218218+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
219219+ ok(c == ' ', "got wrong char '%c' for flags %#x\n", c, tests[i]);
220220+221221+ c = 0x55;
222222+ ret = vsscanf_wrapper(tests[i], "18:59", -1, "%d:%d%c", &hour, &min, &c);
223223+ ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
224224+ ok(hour == 18, "got wrong char '%c' for flags %#x\n", hour, tests[i]);
225225+ ok(min == 59, "got wrong char '%c' for flags %#x\n", min, tests[i]);
226226+ ok(c == 0x55, "got wrong char '%c' for flags %#x\n", c, tests[i]);
227227+228228+ strcpy(buffer, "foo");
229229+ strcpy(buffer1, "bar");
230230+ ret = vsscanf_wrapper(tests[i], "abc def", -1, "%s %n%s", buffer, &count, buffer1);
231231+ ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
232232+ ok(!strcmp(buffer, "abc"), "got wrong string '%s' for flags %#x\n", buffer, tests[i]);
233233+ ok(count == 6, "got wrong count %d for flags %#x\n", count, tests[i]);
234234+ ok(!strcmp(buffer1, "def"), "got wrong string '%s' for flags %#x\n", buffer1, tests[i]);
235235+236236+ ret = vsscanf_wrapper(tests[i], "3:45", -1, "%d:%d%n", &hour, &min, &count);
237237+ ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
238238+ ok(hour == 3, "got wrong char '%c' for flags %#x\n", hour, tests[i]);
239239+ ok(min == 45, "got wrong char '%c' for flags %#x\n", min, tests[i]);
240240+ ok(count == 4, "got wrong count %d for flags %#x\n", count, tests[i]);
241241+242242+ strcpy(buffer, "foo");
243243+ strcpy(buffer1, "bar");
244244+ ret = vsscanf_wrapper(tests[i], "test=value\xda", -1, "%[^=] = %[^;]", buffer, buffer1);
245245+ ok(ret == 2, "sscanf returned %d for flags %#x\n", ret, tests[i]);
246246+ ok(!strcmp(buffer, "test"), "got wrong string '%s' for flags %#x\n", buffer, tests[i]);
247247+ ok(!strcmp(buffer1, "value\xda"), "got wrong string '%s' for flags %#x\n", buffer1, tests[i]);
248248+249249+ ret = vsscanf_wrapper(tests[i], "0.1", 3, "%lf%n", &double_res, &count);
250250+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
251251+ ok(double_res == 0.1, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
252252+ ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
253253+254254+ ret = vsscanf_wrapper(tests[i], "a", -1, "%lf%n", &double_res, &count);
255255+ ok(ret == 0, "sscanf returned %d for flags %#x\n", ret, tests[i]);
256256+257257+ ret = vsscanf_wrapper(tests[i], "aa", -1, "%c%lf%n", &c, &double_res, &count);
258258+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
259259+260260+ ret = vsscanf_wrapper(tests[i], "a0e", -1, "%c%lf%n", &c, &double_res, &count);
261261+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
262262+263263+ ret = vsscanf_wrapper(tests[i], "0.", -1, "%lf%n", &double_res, &count);
264264+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
265265+ ok(double_res == 0, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
266266+ ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
267267+268268+ ret = vsscanf_wrapper(tests[i], "0.", 2, "%lf%n", &double_res, &count);
269269+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
270270+ ok(double_res == 0, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
271271+ ok(count == 2, "got wrong count %d for flags %#x\n", count, tests[i]);
272272+273273+ ret = vsscanf_wrapper(tests[i], "1e", -1, "%lf%n", &double_res, &count);
274274+ ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
275275+276276+ ret = vsscanf_wrapper(tests[i], "1e ", 2, "%lf%n", &double_res, &count);
277277+ ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
278278+279279+ ret = vsscanf_wrapper(tests[i], "1e+", -1, "%lf%n", &double_res, &count);
280280+ ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
281281+282282+ ret = vsscanf_wrapper(tests[i], "inf", -1, "%lf%n", &double_res, &count);
283283+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
284284+ ok(double_res == INFINITY, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
285285+ ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
286286+287287+ ret = vsscanf_wrapper(tests[i], "infa", -1, "%lf%n", &double_res, &count);
288288+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
289289+ ok(double_res == INFINITY, "got wrong double %.16e for flags %#x\n", double_res, tests[i]);
290290+ ok(count == 3, "got wrong count %d for flags %#x\n", count, tests[i]);
291291+292292+ ret = vsscanf_wrapper(tests[i], "infi", -1, "%lf%n", &double_res, &count);
293293+ ok(ret == -1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
294294+295295+ ret_size = ~0;
296296+ ret = vsscanf_wrapper(tests[i], "1", -1, "%zd", &ret_size);
297297+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
298298+ ok(ret_size == 1, "got wrong size_t %s for flags %#x\n",
299299+ wine_dbgstr_longlong((LONGLONG)ret_size), tests[i]);
300300+301301+ result64 = 0;
302302+ ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%I64d", &result64);
303303+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
304304+ ok(result64 == 12345678901234ll, "got wrong number 0x%s for flags %#x\n",
305305+ wine_dbgstr_longlong(result64), tests[i]);
306306+307307+ result = 0;
308308+ ret = vsscanf_wrapper(tests[i], "12345678901234", -1, "%I32d", &result);
309309+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
310310+ ok(result == (int)12345678901234ll, /* this is always truncated to 32bit */
311311+ "got wrong number 0x%d for flags %#x\n", result, tests[i]);
312312+313313+ result_ptr = 0;
314314+ ret = vsscanf_wrapper(tests[i], "0x87654321", -1, "%Ix", &result_ptr);
315315+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
316316+ ok(result_ptr == 0x87654321,
317317+ "got wrong number %Ix for flags %#x\n", result_ptr, tests[i]);
318318+319319+ result_ptr = 0;
320320+ ret = vsscanf_wrapper(tests[i], "0x123456789", -1, "%Ix", &result_ptr);
321321+ ok(ret == 1, "sscanf returned %d for flags %#x\n", ret, tests[i]);
322322+ ok(result_ptr == (DWORD_PTR)0x123456789ull, /* this is truncated on 32bit systems */
323323+ "got wrong number %Ix for flags %#x\n", result_ptr, tests[i]);
324324+ }
325325+}
326326+327327+START_TEST(scanf)
328328+{
329329+ test_sscanf();
330330+}
+860
modules/rostests/winetests/ucrtbase/string.c
···11+/*
22+ * Copyright 2015 Martin Storsjo
33+ *
44+ * This library is free software; you can redistribute it and/or
55+ * modify it under the terms of the GNU Lesser General Public
66+ * License as published by the Free Software Foundation; either
77+ * version 2.1 of the License, or (at your option) any later version.
88+ *
99+ * This library is distributed in the hope that it will be useful,
1010+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1212+ * Lesser General Public License for more details.
1313+ *
1414+ * You should have received a copy of the GNU Lesser General Public
1515+ * License along with this library; if not, write to the Free Software
1616+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1717+ */
1818+1919+#include <errno.h>
2020+#include <stdarg.h>
2121+#include <stdlib.h>
2222+#include <wchar.h>
2323+#include <stdio.h>
2424+#include <locale.h>
2525+#include <mbctype.h>
2626+#include <mbstring.h>
2727+2828+#include <windef.h>
2929+#include <winbase.h>
3030+#include "wine/test.h"
3131+3232+#include <math.h>
3333+3434+#define DEFINE_EXPECT(func) \
3535+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
3636+3737+#define SET_EXPECT(func) \
3838+ expect_ ## func = TRUE
3939+4040+#define CHECK_EXPECT2(func) \
4141+ do { \
4242+ ok(expect_ ##func, "unexpected call " #func "\n"); \
4343+ called_ ## func = TRUE; \
4444+ }while(0)
4545+4646+#define CHECK_EXPECT(func) \
4747+ do { \
4848+ CHECK_EXPECT2(func); \
4949+ expect_ ## func = FALSE; \
5050+ }while(0)
5151+5252+#define CHECK_CALLED(func) \
5353+ do { \
5454+ ok(called_ ## func, "expected " #func "\n"); \
5555+ expect_ ## func = called_ ## func = FALSE; \
5656+ }while(0)
5757+5858+DEFINE_EXPECT(invalid_parameter_handler);
5959+6060+static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
6161+ const wchar_t *function, const wchar_t *file,
6262+ unsigned line, uintptr_t arg)
6363+{
6464+ CHECK_EXPECT(invalid_parameter_handler);
6565+ ok(expression == NULL, "expression is not NULL\n");
6666+ ok(function == NULL, "function is not NULL\n");
6767+ ok(file == NULL, "file is not NULL\n");
6868+ ok(line == 0, "line = %u\n", line);
6969+ ok(arg == 0, "arg = %Ix\n", arg);
7070+}
7171+7272+_ACRTIMP int __cdecl _o_tolower(int);
7373+_ACRTIMP int __cdecl _o_toupper(int);
7474+7575+static BOOL local_isnan(double d)
7676+{
7777+ return d != d;
7878+}
7979+8080+#define test_strtod_str_errno(string, value, length, err) _test_strtod_str(__LINE__, string, value, length, err)
8181+#define test_strtod_str(string, value, length) _test_strtod_str(__LINE__, string, value, length, 0)
8282+static void _test_strtod_str(int line, const char* string, double value, int length, int err)
8383+{
8484+ char *end;
8585+ double d;
8686+ errno = 0xdeadbeef;
8787+ d = strtod(string, &end);
8888+ if(!err)
8989+ ok_(__FILE__, line)(errno == 0xdeadbeef, "errno = %d\n", errno);
9090+ else
9191+ ok_(__FILE__, line)(errno == err, "errno = %d\n", errno);
9292+ if (local_isnan(value))
9393+ ok_(__FILE__, line)(local_isnan(d), "d = %.16le (\"%s\")\n", d, string);
9494+ else
9595+ ok_(__FILE__, line)(d == value, "d = %.16le (\"%s\")\n", d, string);
9696+ ok_(__FILE__, line)(end == string + length, "incorrect end (%d, \"%s\")\n", (int)(end - string), string);
9797+}
9898+9999+static void test_strtod(void)
100100+{
101101+ test_strtod_str("infinity", INFINITY, 8);
102102+ test_strtod_str("INFINITY", INFINITY, 8);
103103+ test_strtod_str("InFiNiTy", INFINITY, 8);
104104+ test_strtod_str("INF", INFINITY, 3);
105105+ test_strtod_str("-inf", -INFINITY, 4);
106106+ test_strtod_str("inf42", INFINITY, 3);
107107+ test_strtod_str("inffoo", INFINITY, 3);
108108+ test_strtod_str("infini", INFINITY, 3);
109109+ test_strtod_str("input", 0, 0);
110110+ test_strtod_str("-input", 0, 0);
111111+ test_strtod_str_errno("1.7976931348623159e+308", INFINITY, 23, ERANGE);
112112+ test_strtod_str_errno("-1.7976931348623159e+308", -INFINITY, 24, ERANGE);
113113+114114+ test_strtod_str("NAN", NAN, 3);
115115+ test_strtod_str("nan", NAN, 3);
116116+ test_strtod_str("NaN", NAN, 3);
117117+118118+ test_strtod_str("0x42", 66, 4);
119119+ test_strtod_str("0X42", 66, 4);
120120+ test_strtod_str("-0x42", -66, 5);
121121+ test_strtod_str("0x1p1", 2, 5);
122122+ test_strtod_str("0x1P1", 2, 5);
123123+ test_strtod_str("0x1p+1", 2, 6);
124124+ test_strtod_str("0x2p-1", 1, 6);
125125+ test_strtod_str("0xA", 10, 3);
126126+ test_strtod_str("0xa", 10, 3);
127127+ test_strtod_str("0xABCDEF", 11259375, 8);
128128+ test_strtod_str("0Xabcdef", 11259375, 8);
129129+130130+ test_strtod_str("0x1.1", 1.0625, 5);
131131+ test_strtod_str("0x1.1p1", 2.125, 7);
132132+ test_strtod_str("0x1.A", 1.625, 5);
133133+ test_strtod_str("0x1p1a", 2, 5);
134134+ test_strtod_str("0xp3", 0, 1);
135135+ test_strtod_str("0x.", 0, 1);
136136+ test_strtod_str("0x.8", 0.5, 4);
137137+ test_strtod_str("0x.8p", 0.5, 4);
138138+ test_strtod_str("0x0p10000000000000000000000000", 0, 30);
139139+ test_strtod_str("0x1p-1026", 1.3906711615670009e-309, 9);
140140+141141+ test_strtod_str("0x1ffffffffffffe.80000000000000000000", 9007199254740990.0, 37);
142142+ test_strtod_str("0x1ffffffffffffe.80000000000000000001", 9007199254740991.0, 37);
143143+ test_strtod_str("0x1fffffffffffff.80000000000000000000", 9007199254740992.0, 37);
144144+ test_strtod_str("0x1fffffffffffff.80000000000000000001", 9007199254740992.0, 37);
145145+146146+ test_strtod_str("4.0621786324484881721115322e-53", 4.0621786324484881721115322e-53, 31);
147147+ test_strtod_str("1.8905590910042396899370942", 1.8905590910042396899370942, 27);
148148+ test_strtod_str("1.7976931348623158e+308", 1.7976931348623158e+308, 23);
149149+ test_strtod_str("2.2250738585072014e-308", 2.2250738585072014e-308, 23);
150150+ test_strtod_str("4.9406564584124654e-324", 4.9406564584124654e-324, 23);
151151+ test_strtod_str("2.48e-324", 4.9406564584124654e-324, 9);
152152+ test_strtod_str_errno("2.47e-324", 0, 9, ERANGE);
153153+}
154154+155155+static void test_strtof(void)
156156+{
157157+ static const struct {
158158+ const char *str;
159159+ int len;
160160+ float ret;
161161+ int err;
162162+ } tests[] = {
163163+ { "12.1", 4, 12.1f },
164164+ { "-13.721", 7, -13.721f },
165165+ { "1.e40", 5, INFINITY, ERANGE },
166166+ { "-1.e40", 6, -INFINITY, ERANGE },
167167+ { "0.0", 3, 0.0f },
168168+ { "-0.0", 4, 0.0f },
169169+ { "1.4e-45", 7, 1.4e-45f },
170170+ { "-1.4e-45", 8, -1.4e-45f },
171171+ { "1.e-60", 6, 0, ERANGE },
172172+ { "-1.e-60", 7, 0, ERANGE },
173173+ };
174174+175175+ char *end;
176176+ float f;
177177+ int i;
178178+179179+ for (i=0; i<ARRAY_SIZE(tests); i++)
180180+ {
181181+ errno = 0xdeadbeef;
182182+ f = strtof(tests[i].str, &end);
183183+ ok(f == tests[i].ret, "%d) f = %.16e\n", i, f);
184184+ ok(end == tests[i].str + tests[i].len, "%d) len = %d\n",
185185+ i, (int)(end - tests[i].str));
186186+ ok(errno == tests[i].err || (!tests[i].err && errno == 0xdeadbeef),
187187+ "%d) errno = %d\n", i, errno);
188188+ }
189189+}
190190+191191+static void test__memicmp(void)
192192+{
193193+ static const char *s1 = "abc";
194194+ static const char *s2 = "aBd";
195195+ int ret;
196196+197197+ ret = _memicmp(NULL, NULL, 0);
198198+ ok(!ret, "got %d\n", ret);
199199+200200+ SET_EXPECT(invalid_parameter_handler);
201201+ errno = 0xdeadbeef;
202202+ ret = _memicmp(NULL, NULL, 1);
203203+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
204204+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
205205+ CHECK_CALLED(invalid_parameter_handler);
206206+207207+ SET_EXPECT(invalid_parameter_handler);
208208+ errno = 0xdeadbeef;
209209+ ret = _memicmp(s1, NULL, 1);
210210+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
211211+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
212212+ CHECK_CALLED(invalid_parameter_handler);
213213+214214+ SET_EXPECT(invalid_parameter_handler);
215215+ errno = 0xdeadbeef;
216216+ ret = _memicmp(NULL, s2, 1);
217217+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
218218+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
219219+ CHECK_CALLED(invalid_parameter_handler);
220220+221221+ ret = _memicmp(s1, s2, 2);
222222+ ok(!ret, "got %d\n", ret);
223223+224224+ ret = _memicmp(s1, s2, 3);
225225+ ok(ret == -1, "got %d\n", ret);
226226+}
227227+228228+static void test__memicmp_l(void)
229229+{
230230+ static const char *s1 = "abc";
231231+ static const char *s2 = "aBd";
232232+ int ret;
233233+234234+ ret = _memicmp_l(NULL, NULL, 0, NULL);
235235+ ok(!ret, "got %d\n", ret);
236236+237237+ SET_EXPECT(invalid_parameter_handler);
238238+ errno = 0xdeadbeef;
239239+ ret = _memicmp_l(NULL, NULL, 1, NULL);
240240+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
241241+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
242242+ CHECK_CALLED(invalid_parameter_handler);
243243+244244+ SET_EXPECT(invalid_parameter_handler);
245245+ errno = 0xdeadbeef;
246246+ ret = _memicmp_l(s1, NULL, 1, NULL);
247247+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
248248+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
249249+ CHECK_CALLED(invalid_parameter_handler);
250250+251251+ SET_EXPECT(invalid_parameter_handler);
252252+ errno = 0xdeadbeef;
253253+ ret = _memicmp_l(NULL, s2, 1, NULL);
254254+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
255255+ ok(errno == EINVAL, "Unexpected errno = %d\n", errno);
256256+ CHECK_CALLED(invalid_parameter_handler);
257257+258258+ ret = _memicmp_l(s1, s2, 2, NULL);
259259+ ok(!ret, "got %d\n", ret);
260260+261261+ ret = _memicmp_l(s1, s2, 3, NULL);
262262+ ok(ret == -1, "got %d\n", ret);
263263+}
264264+265265+266266+static void test___strncnt(void)
267267+{
268268+ static const struct
269269+ {
270270+ const char *str;
271271+ size_t size;
272272+ size_t ret;
273273+ }
274274+ strncnt_tests[] =
275275+ {
276276+ { "a", 0, 0 },
277277+ { "a", 1, 1 },
278278+ { "a", 10, 1 },
279279+ { "abc", 1, 1 },
280280+ };
281281+ unsigned int i;
282282+ size_t ret;
283283+284284+ for (i = 0; i < ARRAY_SIZE(strncnt_tests); ++i)
285285+ {
286286+ ret = __strncnt(strncnt_tests[i].str, strncnt_tests[i].size);
287287+ ok(ret == strncnt_tests[i].ret, "%u: unexpected return value %u.\n", i, (int)ret);
288288+ }
289289+290290+ if (0) /* crashes */
291291+ {
292292+ ret = __strncnt(NULL, 0);
293293+ ret = __strncnt(NULL, 1);
294294+ }
295295+}
296296+297297+static void test_C_locale(void)
298298+{
299299+ int i, j;
300300+ wint_t ret, exp;
301301+ _locale_t locale;
302302+ static const char *locales[] = { NULL, "C" };
303303+304304+ /* C locale only converts case for [a-zA-Z] */
305305+ setlocale(LC_ALL, "C");
306306+ for (i = 0; i <= 0xffff; i++)
307307+ {
308308+ ret = tolower(i);
309309+ if (i >= 'A' && i <= 'Z')
310310+ {
311311+ exp = i + 'a' - 'A';
312312+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
313313+ }
314314+ else
315315+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
316316+317317+ ret = _tolower(i);
318318+ exp = i + 'a' - 'A';
319319+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
320320+321321+ ret = _o_tolower(i);
322322+ if (i >= 'A' && i <= 'Z')
323323+ {
324324+ exp = i + 'a' - 'A';
325325+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
326326+ }
327327+ else
328328+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
329329+330330+ ret = towlower(i);
331331+ if (i >= 'A' && i <= 'Z')
332332+ {
333333+ exp = i + 'a' - 'A';
334334+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
335335+ }
336336+ else
337337+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
338338+339339+ ret = toupper(i);
340340+ if (i >= 'a' && i <= 'z')
341341+ {
342342+ exp = i + 'A' - 'a';
343343+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
344344+ }
345345+ else
346346+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
347347+348348+ ret = _toupper(i);
349349+ exp = i + 'A' - 'a';
350350+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
351351+352352+ ret = _o_toupper(i);
353353+ if (i >= 'a' && i <= 'z')
354354+ {
355355+ exp = i + 'A' - 'a';
356356+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
357357+ }
358358+ else
359359+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
360360+361361+ ret = towupper(i);
362362+ if (i >= 'a' && i <= 'z')
363363+ {
364364+ exp = i + 'A' - 'a';
365365+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
366366+ }
367367+ else
368368+ ok(ret == i, "expected self %x, got %x for C locale\n", i, ret);
369369+ }
370370+371371+ for (i = 0; i < ARRAY_SIZE(locales); i++) {
372372+ locale = locales[i] ? _create_locale(LC_ALL, locales[i]) : NULL;
373373+374374+ for (j = 0; j <= 0xffff; j++) {
375375+ ret = _towlower_l(j, locale);
376376+ if (j >= 'A' && j <= 'Z')
377377+ {
378378+ exp = j + 'a' - 'A';
379379+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
380380+ }
381381+ else
382382+ ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
383383+384384+ ret = _towupper_l(j, locale);
385385+ if (j >= 'a' && j <= 'z')
386386+ {
387387+ exp = j + 'A' - 'a';
388388+ ok(ret == exp, "expected %x, got %x for C locale\n", exp, ret);
389389+ }
390390+ else
391391+ ok(ret == j, "expected self %x, got %x for C locale\n", j, ret);
392392+ }
393393+394394+ _free_locale(locale);
395395+ }
396396+}
397397+398398+static void test_mbsspn( void)
399399+{
400400+ unsigned char str1[] = "cabernet";
401401+ unsigned char str2[] = "shiraz";
402402+ unsigned char set[] = "abc";
403403+ unsigned char empty[] = "";
404404+ unsigned char mbstr[] = " 2019\x94\x4e" "6\x8c\x8e" "29\x93\xfa";
405405+ unsigned char mbset1[] = "0123456789 \x94\x4e";
406406+ unsigned char mbset2[] = " \x94\x4e\x8c\x8e";
407407+ unsigned char mbset3[] = "\x8e";
408408+ int ret, cp = _getmbcp();
409409+410410+ ret = _mbsspn(str1, set);
411411+ ok(ret == 3, "_mbsspn returns %d should be 3\n", ret);
412412+ ret = _mbsspn(str2, set);
413413+ ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
414414+ ret = _mbsspn(str1, empty);
415415+ ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
416416+417417+ _setmbcp(932);
418418+ ret = _mbsspn(mbstr, mbset1);
419419+ ok(ret == 8, "_mbsspn returns %d should be 8\n", ret);
420420+ ret = _mbsspn(mbstr, mbset2);
421421+ ok(ret == 1, "_mbsspn returns %d should be 1\n", ret);
422422+ ret = _mbsspn(mbstr+8, mbset1);
423423+ ok(ret == 0, "_mbsspn returns %d should be 0\n", ret);
424424+ ret = _mbsspn(mbstr+8, mbset2);
425425+ ok(ret == 2, "_mbsspn returns %d should be 2\n", ret);
426426+ ret = _mbsspn(mbstr, mbset3);
427427+ ok(ret == 14, "_mbsspn returns %d should be 14\n", ret);
428428+429429+ _setmbcp(cp);
430430+}
431431+432432+static void test_wcstok(void)
433433+{
434434+ static const wchar_t *input = L"two words";
435435+ wchar_t buffer[16];
436436+ wchar_t *token;
437437+ wchar_t *next;
438438+439439+ next = NULL;
440440+ wcscpy(buffer, input);
441441+ token = wcstok(buffer, L" ", &next);
442442+ ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
443443+ ok(next == token + 4, "expected %p, got %p\n", token + 4, next);
444444+ token = wcstok(NULL, L" ", &next);
445445+ ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
446446+ ok(next == token + 5, "expected %p, got %p\n", token + 5, next);
447447+ token = wcstok(NULL, L" ", &next);
448448+ ok(!token, "expected NULL, got %p\n", token);
449449+450450+ wcscpy(buffer, input);
451451+ token = wcstok(buffer, L" ", NULL);
452452+ ok(!wcscmp(L"two", token), "expected \"two\", got \"%ls\"\n", token);
453453+ token = wcstok(NULL, L" ", NULL);
454454+ ok(!wcscmp(L"words", token), "expected \"words\", got \"%ls\"\n", token);
455455+ token = wcstok(NULL, L" ", NULL);
456456+ ok(!token, "expected NULL, got %p\n", token);
457457+458458+ next = NULL;
459459+ wcscpy(buffer, input);
460460+ token = wcstok(buffer, L"=", &next);
461461+ ok(!wcscmp(token, input), "expected \"%ls\", got \"%ls\"\n", input, token);
462462+ ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
463463+ token = wcstok(NULL, L"=", &next);
464464+ ok(!token, "expected NULL, got \"%ls\"\n", token);
465465+ ok(next == buffer + wcslen(input), "expected %p, got %p\n", buffer + wcslen(input), next);
466466+467467+ next = NULL;
468468+ wcscpy(buffer, L"");
469469+ token = wcstok(buffer, L"=", &next);
470470+ ok(token == NULL, "expected NULL, got \"%ls\"\n", token);
471471+ ok(next == buffer, "expected %p, got %p\n", buffer, next);
472472+ token = wcstok(NULL, L"=", &next);
473473+ ok(!token, "expected NULL, got \"%ls\"\n", token);
474474+ ok(next == buffer, "expected %p, got %p\n", buffer, next);
475475+}
476476+477477+static void test__strnicmp(void)
478478+{
479479+ static const char str1[] = "TEST";
480480+ static const char str2[] = "test";
481481+ int ret;
482482+483483+ SET_EXPECT(invalid_parameter_handler);
484484+ errno = 0xdeadbeef;
485485+ ret = _strnicmp(str1, NULL, 2);
486486+ CHECK_CALLED(invalid_parameter_handler);
487487+ ok(ret == _NLSCMPERROR, "got %d.\n", ret);
488488+ ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
489489+490490+ SET_EXPECT(invalid_parameter_handler);
491491+ errno = 0xdeadbeef;
492492+ ret = _strnicmp(str1, str2, -1);
493493+ CHECK_CALLED(invalid_parameter_handler);
494494+ ok(ret == _NLSCMPERROR, "got %d.\n", ret);
495495+ ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
496496+497497+ ret = _strnicmp(str1, str2, 0);
498498+ ok(!ret, "got %d.\n", ret);
499499+500500+ ret = _strnicmp(str1, str2, 0x7fffffff);
501501+ ok(!ret, "got %d.\n", ret);
502502+503503+ /* If numbers of characters to compare is too big return error */
504504+ SET_EXPECT(invalid_parameter_handler);
505505+ errno = 0xdeadbeef;
506506+ ret = _strnicmp(str1, str2, 0x80000000);
507507+ CHECK_CALLED(invalid_parameter_handler);
508508+ ok(ret == _NLSCMPERROR, "got %d.\n", ret);
509509+ ok(errno == EINVAL, "Unexpected errno %d.\n", errno);
510510+}
511511+512512+static void test_wcsnicmp(void)
513513+{
514514+ static const wchar_t str1[] = L"TEST";
515515+ static const wchar_t str2[] = L"test";
516516+ int ret;
517517+518518+ errno = 0xdeadbeef;
519519+ ret = wcsnicmp(str1, str2, -1);
520520+ ok(!ret, "got %d.\n", ret);
521521+522522+ ret = wcsnicmp(str1, str2, 0x7fffffff);
523523+ ok(!ret, "got %d.\n", ret);
524524+}
525525+526526+static void test_SpecialCasing(void)
527527+{
528528+ int i;
529529+ wint_t ret, exp;
530530+ _locale_t locale;
531531+ struct test {
532532+ const char *lang;
533533+ wint_t ch;
534534+ wint_t exp;
535535+ };
536536+537537+ struct test ucases[] = {
538538+ {"English", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
539539+ {"English", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
540540+541541+ {"Turkish", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
542542+ {"Turkish", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
543543+ };
544544+ struct test lcases[] = {
545545+ {"English", 'i', 'I'}, /* LATIN SMALL LETTER I */
546546+ {"English", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
547547+548548+ {"Turkish", 'i', 'I'}, /* LATIN SMALL LETTER I */
549549+ {"Turkish", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
550550+ };
551551+552552+ for (i = 0; i < ARRAY_SIZE(ucases); i++) {
553553+ if (!setlocale(LC_ALL, ucases[i].lang)) {
554554+ win_skip("skipping special case tests for %s\n", ucases[i].lang);
555555+ continue;
556556+ }
557557+558558+ ret = towlower(ucases[i].ch);
559559+ exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
560560+ ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
561561+ }
562562+563563+ for (i = 0; i < ARRAY_SIZE(lcases); i++) {
564564+ if (!setlocale(LC_ALL, lcases[i].lang)) {
565565+ win_skip("skipping special case tests for %s\n", lcases[i].lang);
566566+ continue;
567567+ }
568568+569569+ ret = towupper(lcases[i].ch);
570570+ exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
571571+ ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
572572+ }
573573+574574+ setlocale(LC_ALL, "C");
575575+576576+ /* test _towlower_l creating locale */
577577+ for (i = 0; i < ARRAY_SIZE(ucases); i++) {
578578+ if (!(locale = _create_locale(LC_ALL, ucases[i].lang))) {
579579+ win_skip("locale %s not available. skipping\n", ucases[i].lang);
580580+ continue;
581581+ }
582582+583583+ ret = _towlower_l(ucases[i].ch, locale);
584584+ exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
585585+ ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
586586+587587+ _free_locale(locale);
588588+ }
589589+590590+ /* test _towupper_l creating locale */
591591+ for (i = 0; i < ARRAY_SIZE(lcases); i++) {
592592+ if (!(locale = _create_locale(LC_ALL, lcases[i].lang))) {
593593+ win_skip("locale %s not available. skipping\n", lcases[i].lang);
594594+ continue;
595595+ }
596596+597597+ ret = _towupper_l(lcases[i].ch, locale);
598598+ exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
599599+ ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
600600+601601+ _free_locale(locale);
602602+ }
603603+}
604604+605605+static void test__mbbtype_l(void)
606606+{
607607+ int expected, ret;
608608+ unsigned int c;
609609+610610+ _setmbcp(_MB_CP_LOCALE);
611611+ for (c = 0; c < 256; ++c)
612612+ {
613613+ expected = _mbbtype(c, 0);
614614+ ret = _mbbtype_l(c, 0, NULL);
615615+ ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
616616+617617+ expected = _mbbtype(c, 1);
618618+ ret = _mbbtype_l(c, 1, NULL);
619619+ ok(ret == expected, "c %#x, got ret %#x, expected %#x.\n", c, ret, expected);
620620+ }
621621+}
622622+623623+static void test_strcmp(void)
624624+{
625625+ int ret = strcmp( "abc", "abcd" );
626626+ ok( ret == -1, "wrong ret %d\n", ret );
627627+ ret = strcmp( "", "abc" );
628628+ ok( ret == -1, "wrong ret %d\n", ret );
629629+ ret = strcmp( "abc", "ab\xa0" );
630630+ ok( ret == -1, "wrong ret %d\n", ret );
631631+ ret = strcmp( "ab\xb0", "ab\xa0" );
632632+ ok( ret == 1, "wrong ret %d\n", ret );
633633+ ret = strcmp( "ab\xc2", "ab\xc2" );
634634+ ok( ret == 0, "wrong ret %d\n", ret );
635635+636636+ ret = strncmp( "abc", "abcd", 3 );
637637+ ok( ret == 0, "wrong ret %d\n", ret );
638638+ ret = strncmp( "", "abc", 3 );
639639+ ok( ret == -1, "wrong ret %d\n", ret );
640640+ ret = strncmp( "abc", "ab\xa0", 4 );
641641+ ok( ret == -1, "wrong ret %d\n", ret );
642642+ ret = strncmp( "ab\xb0", "ab\xa0", 3 );
643643+ ok( ret == 1, "wrong ret %d\n", ret );
644644+ ret = strncmp( "ab\xb0", "ab\xa0", 2 );
645645+ ok( ret == 0, "wrong ret %d\n", ret );
646646+ ret = strncmp( "ab\xc2", "ab\xc2", 3 );
647647+ ok( ret == 0, "wrong ret %d\n", ret );
648648+ ret = strncmp( "abc", "abd", 0 );
649649+ ok( ret == 0, "wrong ret %d\n", ret );
650650+ ret = strncmp( "abc", "abc", 12 );
651651+ ok( ret == 0, "wrong ret %d\n", ret );
652652+}
653653+654654+#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, \
655655+ "Binary buffer mismatch - expected %s, got %s\n", \
656656+ debugstr_an(value, len), debugstr_an((char *)(buf), len)); }
657657+658658+static void test__mbsncpy_s(void)
659659+{
660660+ unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0";
661661+ unsigned char *mbstring2 = (unsigned char *)"\xb0\x0";
662662+ unsigned char buf[16];
663663+ errno_t err;
664664+ int oldcp;
665665+666666+ oldcp = _getmbcp();
667667+ if (_setmbcp(936))
668668+ {
669669+ skip("Code page 936 is not available, skipping test.\n");
670670+ return;
671671+ }
672672+673673+ errno = 0xdeadbeef;
674674+ memset(buf, 0xcc, sizeof(buf));
675675+ err = _mbsncpy_s(NULL, 0, mbstring, 0);
676676+ ok(errno == 0xdeadbeef, "got %d\n", errno);
677677+ ok(!err, "got %d.\n", err);
678678+679679+ errno = 0xdeadbeef;
680680+ memset(buf, 0xcc, sizeof(buf));
681681+ err = _mbsncpy_s(buf, 6, mbstring, 1);
682682+ ok(errno == 0xdeadbeef, "got %d\n", errno);
683683+ ok(!err, "got %d.\n", err);
684684+ expect_bin(buf, "\xb0\xb1\0\xcc", 4);
685685+686686+ memset(buf, 0xcc, sizeof(buf));
687687+ errno = 0xdeadbeef;
688688+ err = _mbsncpy_s(buf, 6, mbstring, 2);
689689+ ok(errno == 0xdeadbeef, "got %d\n", errno);
690690+ ok(!err, "got %d.\n", err);
691691+ expect_bin(buf, "\xb0\xb1\xb2\xb3\0\xcc", 6);
692692+693693+ errno = 0xdeadbeef;
694694+ memset(buf, 0xcc, sizeof(buf));
695695+ err = _mbsncpy_s(buf, 2, mbstring, _TRUNCATE);
696696+ ok(errno == 0xdeadbeef, "got %d\n", errno);
697697+ ok(err == STRUNCATE, "got %d.\n", err);
698698+ expect_bin(buf, "\x00\xb1\xcc", 3);
699699+700700+ memset(buf, 0xcc, sizeof(buf));
701701+ SET_EXPECT(invalid_parameter_handler);
702702+ errno = 0xdeadbeef;
703703+ err = _mbsncpy_s(buf, 2, mbstring, 1);
704704+ ok(errno == err, "got %d.\n", errno);
705705+ CHECK_CALLED(invalid_parameter_handler);
706706+ ok(err == ERANGE, "got %d.\n", err);
707707+ expect_bin(buf, "\x0\xcc\xcc", 3);
708708+709709+ memset(buf, 0xcc, sizeof(buf));
710710+ SET_EXPECT(invalid_parameter_handler);
711711+ errno = 0xdeadbeef;
712712+ err = _mbsncpy_s(buf, 2, mbstring, 3);
713713+ ok(errno == err, "got %d\n", errno);
714714+ CHECK_CALLED(invalid_parameter_handler);
715715+ ok(err == ERANGE, "got %d.\n", err);
716716+ expect_bin(buf, "\x0\xcc\xcc", 3);
717717+718718+ memset(buf, 0xcc, sizeof(buf));
719719+ SET_EXPECT(invalid_parameter_handler);
720720+ errno = 0xdeadbeef;
721721+ err = _mbsncpy_s(buf, 1, mbstring, 3);
722722+ ok(errno == err, "got %d\n", errno);
723723+ CHECK_CALLED(invalid_parameter_handler);
724724+ ok(err == ERANGE, "got %d.\n", err);
725725+ expect_bin(buf, "\x0\xcc", 2);
726726+727727+ memset(buf, 0xcc, sizeof(buf));
728728+ SET_EXPECT(invalid_parameter_handler);
729729+ errno = 0xdeadbeef;
730730+ err = _mbsncpy_s(buf, 0, mbstring, 3);
731731+ ok(errno == err, "got %d\n", errno);
732732+ CHECK_CALLED(invalid_parameter_handler);
733733+ ok(err == EINVAL, "got %d.\n", err);
734734+ expect_bin(buf, "\xcc", 1);
735735+736736+ memset(buf, 0xcc, sizeof(buf));
737737+ SET_EXPECT(invalid_parameter_handler);
738738+ errno = 0xdeadbeef;
739739+ err = _mbsncpy_s(buf, 0, mbstring, 0);
740740+ ok(errno == err, "got %d\n", errno);
741741+ CHECK_CALLED(invalid_parameter_handler);
742742+ ok(err == EINVAL, "got %d.\n", err);
743743+ expect_bin(buf, "\xcc", 1);
744744+745745+ memset(buf, 0xcc, sizeof(buf));
746746+ errno = 0xdeadbeef;
747747+ err = _mbsncpy_s(buf, -1, mbstring, 0);
748748+ ok(errno == 0xdeadbeef, "got %d\n", errno);
749749+ ok(!err, "got %d.\n", err);
750750+ expect_bin(buf, "\x0\xcc", 2);
751751+752752+ memset(buf, 0xcc, sizeof(buf));
753753+ errno = 0xdeadbeef;
754754+ err = _mbsncpy_s(buf, -1, mbstring, 256);
755755+ ok(errno == 0xdeadbeef, "got %d\n", errno);
756756+ ok(!err, "got %d.\n", err);
757757+ expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9);
758758+759759+ memset(buf, 0xcc, sizeof(buf));
760760+ errno = 0xdeadbeef;
761761+ err = _mbsncpy_s(buf, 1, mbstring2, 4);
762762+ ok(errno == err, "got %d\n", errno);
763763+ ok(err == EILSEQ, "got %d.\n", err);
764764+ expect_bin(buf, "\x0\xcc", 2);
765765+766766+ memset(buf, 0xcc, sizeof(buf));
767767+ errno = 0xdeadbeef;
768768+ err = _mbsncpy_s(buf, 2, mbstring2, 4);
769769+ ok(errno == err, "got %d\n", errno);
770770+ ok(err == EILSEQ, "got %d.\n", err);
771771+ expect_bin(buf, "\x0\xcc", 2);
772772+773773+ memset(buf, 0xcc, sizeof(buf));
774774+ errno = 0xdeadbeef;
775775+ err = _mbsncpy_s(buf, 1, mbstring2, _TRUNCATE);
776776+ ok(errno == 0xdeadbeef, "got %d\n", errno);
777777+ ok(err == STRUNCATE, "got %d.\n", err);
778778+ expect_bin(buf, "\x0\xcc", 2);
779779+780780+ memset(buf, 0xcc, sizeof(buf));
781781+ errno = 0xdeadbeef;
782782+ err = _mbsncpy_s(buf, 2, mbstring2, _TRUNCATE);
783783+ ok(errno == 0xdeadbeef, "got %d\n", errno);
784784+ ok(!err, "got %d.\n", err);
785785+ expect_bin(buf, "\xb0\x0\xcc", 3);
786786+787787+ memset(buf, 0xcc, sizeof(buf));
788788+ errno = 0xdeadbeef;
789789+ err = _mbsncpy_s(buf, 1, mbstring2, 1);
790790+ ok(errno == err, "got %d\n", errno);
791791+ ok(err == EILSEQ, "got %d.\n", err);
792792+ expect_bin(buf, "\x0\xcc", 2);
793793+794794+ memset(buf, 0xcc, sizeof(buf));
795795+ errno = 0xdeadbeef;
796796+ err = _mbsncpy_s(buf, 2, mbstring2, 1);
797797+ ok(errno == err, "got %d\n", errno);
798798+ ok(err == EILSEQ, "got %d.\n", err);
799799+ expect_bin(buf, "\x0\xcc", 2);
800800+801801+ memset(buf, 0xcc, sizeof(buf));
802802+ errno = 0xdeadbeef;
803803+ err = _mbsncpy_s(buf, 3, mbstring2, 1);
804804+ ok(errno == err, "got %d\n", errno);
805805+ ok(err == EILSEQ, "got %d.\n", err);
806806+ expect_bin(buf, "\x0\xcc", 2);
807807+808808+ memset(buf, 0xcc, sizeof(buf));
809809+ errno = 0xdeadbeef;
810810+ err = _mbsncpy_s(buf, 3, mbstring2, 2);
811811+ ok(errno == err, "got %d\n", errno);
812812+ ok(err == EILSEQ, "got %d.\n", err);
813813+ expect_bin(buf, "\x0\xcc", 2);
814814+815815+ _setmbcp(oldcp);
816816+}
817817+818818+static void test_mbstowcs(void)
819819+{
820820+ static const char mbs[] = { 0xc3, 0xa9, 0 };
821821+ WCHAR wcs[2];
822822+ size_t ret;
823823+824824+ if (!setlocale(LC_ALL, "en_US.UTF-8"))
825825+ {
826826+ win_skip("skipping UTF8 mbstowcs tests\n");
827827+ return;
828828+ }
829829+830830+ ret = mbstowcs(NULL, mbs, 0);
831831+ ok(ret == 1, "mbstowcs returned %Id\n", ret);
832832+ memset(wcs, 0xfe, sizeof(wcs));
833833+ ret = mbstowcs(wcs, mbs, 1);
834834+ ok(ret == 1, "mbstowcs returned %Id\n", ret);
835835+ ok(wcs[0] == 0xe9, "wcsstring[0] = %x\n", wcs[0]);
836836+ ok(wcs[1] == 0xfefe, "wcsstring[1] = %x\n", wcs[1]);
837837+ setlocale(LC_ALL, "C");
838838+}
839839+840840+START_TEST(string)
841841+{
842842+ ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
843843+ "Invalid parameter handler was already set\n");
844844+845845+ test_strtod();
846846+ test_strtof();
847847+ test__memicmp();
848848+ test__memicmp_l();
849849+ test___strncnt();
850850+ test_C_locale();
851851+ test_mbsspn();
852852+ test_wcstok();
853853+ test__strnicmp();
854854+ test_wcsnicmp();
855855+ test_SpecialCasing();
856856+ test__mbbtype_l();
857857+ test_strcmp();
858858+ test__mbsncpy_s();
859859+ test_mbstowcs();
860860+}
+184
modules/rostests/winetests/ucrtbase/thread.c
···11+/*
22+ * Copyright 2021 Arkadiusz Hiler for CodeWeavers
33+ *
44+ * This library is free software; you can redistribute it and/or
55+ * modify it under the terms of the GNU Lesser General Public
66+ * License as published by the Free Software Foundation; either
77+ * version 2.1 of the License, or (at your option) any later version.
88+ *
99+ * This library is distributed in the hope that it will be useful,
1010+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1212+ * Lesser General Public License for more details.
1313+ *
1414+ * You should have received a copy of the GNU Lesser General Public
1515+ * License along with this library; if not, write to the Free Software
1616+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1717+ */
1818+1919+#include <errno.h>
2020+#include <stdarg.h>
2121+#include <process.h>
2222+2323+#include <windef.h>
2424+#include <winbase.h>
2525+#include "wine/test.h"
2626+2727+#include "threaddll.h"
2828+2929+enum beginthread_method
3030+{
3131+ use_beginthread,
3232+ use_beginthreadex
3333+};
3434+3535+static char *get_thread_dll_path(void)
3636+{
3737+ static char path[MAX_PATH];
3838+ const char dll_name[] = "threaddll.dll";
3939+ DWORD written;
4040+ HANDLE file;
4141+ HRSRC res;
4242+ void *ptr;
4343+4444+ GetTempPathA(ARRAY_SIZE(path), path);
4545+ strcat(path, dll_name);
4646+4747+ file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
4848+ ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n",
4949+ debugstr_a(path), GetLastError());
5050+5151+ res = FindResourceA(NULL, dll_name, "TESTDLL");
5252+ ok(!!res, "Failed to load resource: %lu\n", GetLastError());
5353+ ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res));
5454+ WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL);
5555+ ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n");
5656+ CloseHandle(file);
5757+5858+ return path;
5959+}
6060+6161+static void set_thead_dll_detach_event(HANDLE dll, HANDLE event)
6262+{
6363+ void (WINAPI *_set_detach_event)(HANDLE event);
6464+ _set_detach_event = (void*) GetProcAddress(dll, "set_detach_event");
6565+ ok(_set_detach_event != NULL, "Failed to get set_detach_event: %lu\n", GetLastError());
6666+ _set_detach_event(event);
6767+}
6868+6969+static void test_thread_library_reference(char *thread_dll,
7070+ enum beginthread_method beginthread_method,
7171+ enum thread_exit_method exit_method)
7272+{
7373+ HANDLE detach_event;
7474+ HMODULE dll;
7575+ DWORD ret;
7676+ uintptr_t thread_handle;
7777+ struct threaddll_args args;
7878+7979+ args.exit_method = exit_method;
8080+8181+ detach_event = CreateEventA(NULL, FALSE, FALSE, NULL);
8282+ ok(detach_event != NULL, "Failed to create an event: %lu\n", GetLastError());
8383+ args.confirm_running = CreateEventA(NULL, FALSE, FALSE, NULL);
8484+ ok(args.confirm_running != NULL, "Failed to create an event: %lu\n", GetLastError());
8585+ args.past_free = CreateEventA(NULL, FALSE, FALSE, NULL);
8686+ ok(args.past_free != NULL, "Failed to create an event: %lu\n", GetLastError());
8787+8888+ dll = LoadLibraryA(thread_dll);
8989+ ok(dll != NULL, "Failed to load the test dll: %lu\n", GetLastError());
9090+9191+ set_thead_dll_detach_event(dll, detach_event);
9292+9393+ if (beginthread_method == use_beginthreadex)
9494+ {
9595+ _beginthreadex_start_routine_t proc = (void*) GetProcAddress(dll, "stdcall_thread_proc");
9696+ ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError());
9797+ thread_handle = _beginthreadex(NULL, 0, proc, &args, 0, NULL);
9898+ }
9999+ else
100100+ {
101101+ _beginthread_start_routine_t proc = (void*) GetProcAddress(dll, "cdecl_thread_proc");
102102+ ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError());
103103+ thread_handle = _beginthread(proc, 0, &args);
104104+ }
105105+106106+ ok(thread_handle != -1 && thread_handle != 0, "Failed to begin thread: %u\n", errno);
107107+108108+ ret = FreeLibrary(dll);
109109+ ok(ret, "Failed to free the library: %lu\n", GetLastError());
110110+111111+ ret = WaitForSingleObject(args.confirm_running, 200);
112112+ ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %lu, err: %lu\n", ret, GetLastError());
113113+114114+ ret = WaitForSingleObject(detach_event, 0);
115115+ ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %ld, err: %lu\n", ret, GetLastError());
116116+117117+ ret = SetEvent(args.past_free);
118118+ ok(ret, "Failed to signal event: %ld\n", GetLastError());
119119+120120+ if (beginthread_method == use_beginthreadex)
121121+ {
122122+ ret = WaitForSingleObject((HANDLE)thread_handle, 200);
123123+ ok(ret == WAIT_OBJECT_0, "Thread has not exited, ret: %ld, err: %lu\n", ret, GetLastError());
124124+ }
125125+126126+ ret = WaitForSingleObject(detach_event, 200);
127127+ ok(ret == WAIT_OBJECT_0, "Detach event was not signaled, ret: %ld, err: %lu\n", ret, GetLastError());
128128+129129+ if (beginthread_method == use_beginthreadex)
130130+ CloseHandle((HANDLE)thread_handle);
131131+132132+ CloseHandle(args.past_free);
133133+ CloseHandle(args.confirm_running);
134134+ CloseHandle(detach_event);
135135+}
136136+137137+static BOOL handler_called;
138138+139139+void CDECL test_invalid_parameter_handler(const wchar_t *expression,
140140+ const wchar_t *function_name,
141141+ const wchar_t *file_name,
142142+ unsigned line_number,
143143+ uintptr_t reserved)
144144+{
145145+ handler_called = TRUE;
146146+}
147147+148148+static void test_thread_invalid_params(void)
149149+{
150150+ uintptr_t hThread;
151151+ _invalid_parameter_handler old = _set_invalid_parameter_handler(test_invalid_parameter_handler);
152152+153153+ errno = 0;
154154+ handler_called = FALSE;
155155+ hThread = _beginthreadex(NULL, 0, NULL, NULL, 0, NULL);
156156+ ok(hThread == 0, "_beginthreadex unexpected ret: %Iu\n", hThread);
157157+ ok(errno == EINVAL, "_beginthreadex unexpected errno: %d\n", errno);
158158+ ok(handler_called, "Expected invalid_parameter_handler to be called\n");
159159+160160+ errno = 0;
161161+ handler_called = FALSE;
162162+ hThread = _beginthread(NULL, 0, NULL);
163163+ ok(hThread == -1, "_beginthread unexpected ret: %Iu\n", hThread);
164164+ ok(errno == EINVAL, "_beginthread unexpected errno: %d\n", errno);
165165+ ok(handler_called, "Expected invalid_parameter_handler to be called\n");
166166+167167+ _set_invalid_parameter_handler(old);
168168+}
169169+170170+START_TEST(thread)
171171+{
172172+ BOOL ret;
173173+ char *thread_dll = get_thread_dll_path();
174174+175175+ test_thread_library_reference(thread_dll, use_beginthread, thread_exit_return);
176176+ test_thread_library_reference(thread_dll, use_beginthread, thread_exit_endthread);
177177+ test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_return);
178178+ test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_endthreadex);
179179+180180+ ret = DeleteFileA(thread_dll);
181181+ ok(ret, "Failed to remove the test dll, err: %lu\n", GetLastError());
182182+183183+ test_thread_invalid_params();
184184+}
+71
modules/rostests/winetests/ucrtbase/threaddll.c
···11+/*
22+ * Copyright 2021 Arkadiusz Hiler for CodeWeavers
33+ *
44+ * This library is free software; you can redistribute it and/or
55+ * modify it under the terms of the GNU Lesser General Public
66+ * License as published by the Free Software Foundation; either
77+ * version 2.1 of the License, or (at your option) any later version.
88+ *
99+ * This library is distributed in the hope that it will be useful,
1010+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1212+ * Lesser General Public License for more details.
1313+ *
1414+ * You should have received a copy of the GNU Lesser General Public
1515+ * License along with this library; if not, write to the Free Software
1616+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1717+ */
1818+1919+#if 0
2020+#pragma makedep testdll
2121+#endif
2222+2323+#include <windows.h>
2424+2525+#include "threaddll.h"
2626+2727+static HANDLE detach_event;
2828+2929+void CDECL _endthread(void);
3030+void CDECL _endthreadex(unsigned int);
3131+3232+void WINAPI set_detach_event(HANDLE event)
3333+{
3434+ detach_event = event;
3535+}
3636+3737+static unsigned internal_thread_proc(void *param)
3838+{
3939+ struct threaddll_args *args = param;
4040+ SetEvent(args->confirm_running);
4141+ WaitForSingleObject(args->past_free, INFINITE);
4242+4343+ if (args->exit_method == thread_exit_endthread)
4444+ _endthread();
4545+ else if (args->exit_method == thread_exit_endthreadex)
4646+ _endthreadex(0);
4747+4848+ return 0;
4949+}
5050+5151+unsigned WINAPI stdcall_thread_proc(void *param)
5252+{
5353+ return internal_thread_proc(param);
5454+}
5555+5656+void CDECL cdecl_thread_proc(void *param)
5757+{
5858+ internal_thread_proc(param);
5959+}
6060+6161+BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
6262+{
6363+ switch (reason)
6464+ {
6565+ case DLL_PROCESS_DETACH:
6666+ if (detach_event) SetEvent(detach_event);
6767+ break;
6868+ }
6969+7070+ return TRUE;
7171+}
+30
modules/rostests/winetests/ucrtbase/threaddll.h
···11+/*
22+ * Copyright 2021 Arkadiusz Hiler for CodeWeavers
33+ *
44+ * This library is free software; you can redistribute it and/or
55+ * modify it under the terms of the GNU Lesser General Public
66+ * License as published by the Free Software Foundation; either
77+ * version 2.1 of the License, or (at your option) any later version.
88+ *
99+ * This library is distributed in the hope that it will be useful,
1010+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1212+ * Lesser General Public License for more details.
1313+ *
1414+ * You should have received a copy of the GNU Lesser General Public
1515+ * License along with this library; if not, write to the Free Software
1616+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1717+ */
1818+1919+enum thread_exit_method {
2020+ thread_exit_return,
2121+ thread_exit_endthread,
2222+ thread_exit_endthreadex
2323+};
2424+2525+struct threaddll_args
2626+{
2727+ HANDLE confirm_running;
2828+ HANDLE past_free;
2929+ enum thread_exit_method exit_method;
3030+};