Reactos
1/*
2 * Copyright 2016 Nikolay Sivov for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19#include <errno.h>
20#include <stdarg.h>
21#include <stdlib.h>
22#include <wchar.h>
23#include <stdio.h>
24#include <math.h>
25#include <float.h>
26#include <io.h>
27#include <sys/stat.h>
28#include <share.h>
29#include <fcntl.h>
30#include <time.h>
31#include <direct.h>
32#include <locale.h>
33#include <process.h>
34#include <fenv.h>
35#include <malloc.h>
36
37#include <windef.h>
38#include <winbase.h>
39#include "wine/test.h"
40
41#define DEFINE_EXPECT(func) \
42 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
43
44#define SET_EXPECT(func) \
45 expect_ ## func = TRUE
46
47#define CHECK_EXPECT2(func) \
48 do { \
49 ok(expect_ ##func, "unexpected call " #func "\n"); \
50 called_ ## func = TRUE; \
51 }while(0)
52
53#define CHECK_EXPECT(func) \
54 do { \
55 CHECK_EXPECT2(func); \
56 expect_ ## func = FALSE; \
57 }while(0)
58
59#define CHECK_CALLED(func) \
60 do { \
61 ok(called_ ## func, "expected " #func "\n"); \
62 expect_ ## func = called_ ## func = FALSE; \
63 }while(0)
64
65static inline double __port_min_pos_double(void)
66{
67 static const UINT64 __min_pos_double = 0x10000000000000;
68 return *(const double *)&__min_pos_double;
69}
70
71static inline double __port_max_double(void)
72{
73 static const UINT64 __max_double = 0x7FEFFFFFFFFFFFFF;
74 return *(const double *)&__max_double;
75}
76
77DEFINE_EXPECT(global_invalid_parameter_handler);
78DEFINE_EXPECT(thread_invalid_parameter_handler);
79
80typedef struct {
81 const char *short_wday[7];
82 const char *wday[7];
83 const char *short_mon[12];
84 const char *mon[12];
85 const char *am;
86 const char *pm;
87 const char *short_date;
88 const char *date;
89 const char *time;
90 int unk;
91 int refcount;
92 const wchar_t *short_wdayW[7];
93 const wchar_t *wdayW[7];
94 const wchar_t *short_monW[12];
95 const wchar_t *monW[12];
96 const wchar_t *amW;
97 const wchar_t *pmW;
98 const wchar_t *short_dateW;
99 const wchar_t *dateW;
100 const wchar_t *timeW;
101 const wchar_t *locnameW;
102} __lc_time_data;
103
104typedef void (__cdecl *_se_translator_function)(unsigned int code, struct _EXCEPTION_POINTERS *info);
105
106static LONGLONG crt_init_end;
107
108_ACRTIMP int __cdecl _o__initialize_onexit_table(_onexit_table_t *table);
109_ACRTIMP int __cdecl _o__register_onexit_function(_onexit_table_t *table, _onexit_t func);
110_ACRTIMP int __cdecl _o__execute_onexit_table(_onexit_table_t *table);
111_ACRTIMP void *__cdecl _o_malloc(size_t);
112_se_translator_function __cdecl _set_se_translator(_se_translator_function func);
113void** __cdecl __current_exception(void);
114int* __cdecl __processing_throw(void);
115
116#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF)
117
118static void test__initialize_onexit_table(void)
119{
120 _onexit_table_t table, table2;
121 int ret;
122
123 ret = _initialize_onexit_table(NULL);
124 ok(ret == -1, "got %d\n", ret);
125
126 memset(&table, 0, sizeof(table));
127 ret = _initialize_onexit_table(&table);
128 ok(ret == 0, "got %d\n", ret);
129 ok(table._first == table._last && table._first == table._end, "got first %p, last %p, end %p\n",
130 table._first, table._last, table._end);
131
132 memset(&table2, 0, sizeof(table2));
133 ret = _initialize_onexit_table(&table2);
134 ok(ret == 0, "got %d\n", ret);
135 ok(table2._first == table._first, "got %p, %p\n", table2._first, table._first);
136 ok(table2._last == table._last, "got %p, %p\n", table2._last, table._last);
137 ok(table2._end == table._end, "got %p, %p\n", table2._end, table._end);
138
139 memset(&table2, 0, sizeof(table2));
140 ret = _o__initialize_onexit_table(&table2);
141 ok(ret == 0, "got %d\n", ret);
142 ok(table2._first == table._first, "got %p, %p\n", table2._first, table._first);
143 ok(table2._last == table._last, "got %p, %p\n", table2._last, table._last);
144 ok(table2._end == table._end, "got %p, %p\n", table2._end, table._end);
145
146 /* uninitialized table */
147 table._first = table._last = table._end = (void*)0x123;
148 ret = _initialize_onexit_table(&table);
149 ok(ret == 0, "got %d\n", ret);
150 ok(table._first == table._last && table._first == table._end, "got first %p, last %p, end %p\n",
151 table._first, table._last, table._end);
152 ok(table._first != (void*)0x123, "got %p\n", table._first);
153
154 table._first = (void*)0x123;
155 table._last = (void*)0x456;
156 table._end = (void*)0x123;
157 ret = _initialize_onexit_table(&table);
158 ok(ret == 0, "got %d\n", ret);
159 ok(table._first == table._last && table._first == table._end, "got first %p, last %p, end %p\n",
160 table._first, table._last, table._end);
161 ok(table._first != (void*)0x123, "got %p\n", table._first);
162
163 table._first = (void*)0x123;
164 table._last = (void*)0x456;
165 table._end = (void*)0x789;
166 ret = _initialize_onexit_table(&table);
167 ok(ret == 0, "got %d\n", ret);
168 ok(table._first == (void*)0x123, "got %p\n", table._first);
169 ok(table._last == (void*)0x456, "got %p\n", table._last);
170 ok(table._end == (void*)0x789, "got %p\n", table._end);
171
172 table._first = NULL;
173 table._last = (void*)0x456;
174 table._end = NULL;
175 ret = _initialize_onexit_table(&table);
176 ok(ret == 0, "got %d\n", ret);
177 ok(table._first == table._last && table._first == table._end, "got first %p, last %p, end %p\n",
178 table._first, table._last, table._end);
179}
180
181static int g_onexit_called;
182static int CDECL onexit_func(void)
183{
184 g_onexit_called++;
185 return 0;
186}
187
188static int CDECL onexit_func2(void)
189{
190 ok(g_onexit_called == 0, "got %d\n", g_onexit_called);
191 g_onexit_called++;
192 return 0;
193}
194
195static void test__register_onexit_function(void)
196{
197 _onexit_table_t table;
198 _PVFV *f;
199 int ret;
200
201 memset(&table, 0, sizeof(table));
202 ret = _initialize_onexit_table(&table);
203 ok(ret == 0, "got %d\n", ret);
204
205 ret = _register_onexit_function(NULL, NULL);
206 ok(ret == -1, "got %d\n", ret);
207
208 ret = _register_onexit_function(NULL, onexit_func);
209 ok(ret == -1, "got %d\n", ret);
210
211 f = table._last;
212 ret = _register_onexit_function(&table, NULL);
213 ok(ret == 0, "got %d\n", ret);
214 ok(f != table._last, "got %p, initial %p\n", table._last, f);
215
216 ret = _register_onexit_function(&table, onexit_func);
217 ok(ret == 0, "got %d\n", ret);
218
219 f = table._last;
220 ret = _register_onexit_function(&table, onexit_func);
221 ok(ret == 0, "got %d\n", ret);
222 ok(f != table._last, "got %p, initial %p\n", table._last, f);
223
224 f = table._last;
225 ret = _o__register_onexit_function(&table, NULL);
226 ok(ret == 0, "got %d\n", ret);
227 ok(f != table._last, "got %p, initial %p\n", table._last, f);
228
229 f = table._last;
230 ret = _o__register_onexit_function(&table, onexit_func);
231 ok(ret == 0, "got %d\n", ret);
232 ok(f != table._last, "got %p, initial %p\n", table._last, f);
233
234 ret = _execute_onexit_table(&table);
235 ok(ret == 0, "got %d\n", ret);
236}
237
238static void test__execute_onexit_table(void)
239{
240 _onexit_table_t table;
241 int ret;
242
243 ret = _execute_onexit_table(NULL);
244 ok(ret == -1, "got %d\n", ret);
245
246 memset(&table, 0, sizeof(table));
247 ret = _initialize_onexit_table(&table);
248 ok(ret == 0, "got %d\n", ret);
249
250 /* execute empty table */
251 ret = _execute_onexit_table(&table);
252 ok(ret == 0, "got %d\n", ret);
253
254 /* same function registered multiple times */
255 ret = _register_onexit_function(&table, onexit_func);
256 ok(ret == 0, "got %d\n", ret);
257
258 ret = _register_onexit_function(&table, NULL);
259 ok(ret == 0, "got %d\n", ret);
260
261 ret = _register_onexit_function(&table, onexit_func);
262 ok(ret == 0, "got %d\n", ret);
263
264 ret = _o__register_onexit_function(&table, onexit_func);
265 ok(ret == 0, "got %d\n", ret);
266
267 ok(table._first != table._end, "got %p, %p\n", table._first, table._end);
268 g_onexit_called = 0;
269 ret = _execute_onexit_table(&table);
270 ok(ret == 0, "got %d\n", ret);
271 ok(g_onexit_called == 3, "got %d\n", g_onexit_called);
272 ok(table._first == table._end, "got %p, %p\n", table._first, table._end);
273
274 ret = _register_onexit_function(&table, onexit_func);
275 ok(ret == 0, "got %d\n", ret);
276
277 ret = _register_onexit_function(&table, NULL);
278 ok(ret == 0, "got %d\n", ret);
279
280 ret = _register_onexit_function(&table, onexit_func);
281 ok(ret == 0, "got %d\n", ret);
282
283 ret = _o__register_onexit_function(&table, onexit_func);
284 ok(ret == 0, "got %d\n", ret);
285
286 ok(table._first != table._end, "got %p, %p\n", table._first, table._end);
287 g_onexit_called = 0;
288 ret = _o__execute_onexit_table(&table);
289 ok(ret == 0, "got %d\n", ret);
290 ok(g_onexit_called == 3, "got %d\n", g_onexit_called);
291 ok(table._first == table._end, "got %p, %p\n", table._first, table._end);
292
293 /* execute again, table is already empty */
294 g_onexit_called = 0;
295 ret = _execute_onexit_table(&table);
296 ok(ret == 0, "got %d\n", ret);
297 ok(g_onexit_called == 0, "got %d\n", g_onexit_called);
298
299 /* check call order */
300 memset(&table, 0, sizeof(table));
301 ret = _initialize_onexit_table(&table);
302 ok(ret == 0, "got %d\n", ret);
303
304 ret = _register_onexit_function(&table, onexit_func);
305 ok(ret == 0, "got %d\n", ret);
306
307 ret = _register_onexit_function(&table, onexit_func2);
308 ok(ret == 0, "got %d\n", ret);
309
310 g_onexit_called = 0;
311 ret = _execute_onexit_table(&table);
312 ok(ret == 0, "got %d\n", ret);
313 ok(g_onexit_called == 2, "got %d\n", g_onexit_called);
314}
315
316static void test___fpe_flt_rounds(void)
317{
318 unsigned int cfp = _controlfp(0, 0);
319 int ret;
320
321 if(!cfp) {
322 skip("_controlfp not supported\n");
323 return;
324 }
325
326 ok((_controlfp(_RC_NEAR, _RC_CHOP) & _RC_CHOP) == _RC_NEAR, "_controlfp(_RC_NEAR, _RC_CHOP) failed\n");
327 ret = __fpe_flt_rounds();
328 ok(ret == 1, "__fpe_flt_rounds returned %d\n", ret);
329
330 ok((_controlfp(_RC_UP, _RC_CHOP) & _RC_CHOP) == _RC_UP, "_controlfp(_RC_UP, _RC_CHOP) failed\n");
331 ret = __fpe_flt_rounds();
332 ok(ret == 2 || broken(ret == 3) /* w1064v1507 */, "__fpe_flt_rounds returned %d\n", ret);
333
334 ok((_controlfp(_RC_DOWN, _RC_CHOP) & _RC_CHOP) == _RC_DOWN, "_controlfp(_RC_DOWN, _RC_CHOP) failed\n");
335 ret = __fpe_flt_rounds();
336 ok(ret == 3 || broken(ret == 2) /* w1064v1507 */, "__fpe_flt_rounds returned %d\n", ret);
337
338 ok((_controlfp(_RC_CHOP, _RC_CHOP) & _RC_CHOP) == _RC_CHOP, "_controlfp(_RC_CHOP, _RC_CHOP) failed\n");
339 ret = __fpe_flt_rounds();
340 ok(ret == 0, "__fpe_flt_rounds returned %d\n", ret);
341
342 _controlfp(cfp, _MCW_EM | _MCW_RC | _MCW_PC);
343}
344
345static void test__control87_2(void)
346{
347#ifdef __i386__
348 unsigned int x86_cw_init, sse2_cw_init, x86_cw, sse2_cw, r;
349
350 r = __control87_2(0, 0, &x86_cw_init, &sse2_cw_init);
351 ok(r == 1, "__control87_2 returned %d\n", r);
352
353 r = __control87_2(0, _EM_INVALID, &x86_cw, NULL);
354 ok(r == 1, "__control87_2 returned %d\n", r);
355 ok(x86_cw == (x86_cw_init & ~_EM_INVALID), "x86_cw = %x, x86_cw_init = %x\n", x86_cw, x86_cw_init);
356
357 r = __control87_2(0, 0, &x86_cw, &sse2_cw);
358 ok(r == 1, "__control87_2 returned %d\n", r);
359 ok(x86_cw == (x86_cw_init & ~_EM_INVALID), "x86_cw = %x, x86_cw_init = %x\n", x86_cw, x86_cw_init);
360 ok(sse2_cw == sse2_cw_init, "sse2_cw = %x, sse2_cw_init = %x\n", sse2_cw, sse2_cw_init);
361
362 r = _control87(0, 0);
363 ok(r == (x86_cw | sse2_cw | _EM_AMBIGUOUS), "r = %x, expected %x\n",
364 r, x86_cw | sse2_cw | _EM_AMBIGUOUS);
365
366 _control87(x86_cw_init, ~0);
367#endif
368}
369
370static void __cdecl global_invalid_parameter_handler(
371 const wchar_t *expression, const wchar_t *function,
372 const wchar_t *file, unsigned line, uintptr_t arg)
373{
374 CHECK_EXPECT2(global_invalid_parameter_handler);
375}
376
377static void __cdecl thread_invalid_parameter_handler(
378 const wchar_t *expression, const wchar_t *function,
379 const wchar_t *file, unsigned line, uintptr_t arg)
380{
381 CHECK_EXPECT(thread_invalid_parameter_handler);
382}
383
384static void test_invalid_parameter_handler(void)
385{
386 _invalid_parameter_handler ret;
387
388 ret = _get_invalid_parameter_handler();
389 ok(!ret, "ret != NULL\n");
390
391 ret = _get_thread_local_invalid_parameter_handler();
392 ok(!ret, "ret != NULL\n");
393
394 ret = _set_thread_local_invalid_parameter_handler(thread_invalid_parameter_handler);
395 ok(!ret, "ret != NULL\n");
396
397 ret = _get_thread_local_invalid_parameter_handler();
398 ok(ret == thread_invalid_parameter_handler, "ret = %p\n", ret);
399
400 ret = _get_invalid_parameter_handler();
401 ok(!ret, "ret != NULL\n");
402
403 ret = _set_invalid_parameter_handler(global_invalid_parameter_handler);
404 ok(!ret, "ret != NULL\n");
405
406 ret = _get_invalid_parameter_handler();
407 ok(ret == global_invalid_parameter_handler, "ret = %p\n", ret);
408
409 ret = _get_thread_local_invalid_parameter_handler();
410 ok(ret == thread_invalid_parameter_handler, "ret = %p\n", ret);
411
412 SET_EXPECT(thread_invalid_parameter_handler);
413 _ltoa_s(0, NULL, 0, 0);
414 CHECK_CALLED(thread_invalid_parameter_handler);
415
416 ret = _set_thread_local_invalid_parameter_handler(NULL);
417 ok(ret == thread_invalid_parameter_handler, "ret = %p\n", ret);
418
419 SET_EXPECT(global_invalid_parameter_handler);
420 _ltoa_s(0, NULL, 0, 0);
421 CHECK_CALLED(global_invalid_parameter_handler);
422
423 ret = _set_invalid_parameter_handler(NULL);
424 ok(ret == global_invalid_parameter_handler, "ret = %p\n", ret);
425
426 ret = _set_invalid_parameter_handler(global_invalid_parameter_handler);
427 ok(!ret, "ret != NULL\n");
428}
429
430static void test__get_narrow_winmain_command_line(char *path)
431{
432 PROCESS_INFORMATION proc;
433 STARTUPINFOA startup;
434 char cmd[MAX_PATH+32];
435 char *ret, *cmdline, *name;
436 int len;
437
438 ret = _get_narrow_winmain_command_line();
439 cmdline = GetCommandLineA();
440 len = strlen(cmdline);
441 ok(ret>cmdline && ret<cmdline+len, "ret = %p, cmdline = %p (len = %d)\n", ret, cmdline, len);
442
443 if(!path) {
444 ok(!lstrcmpA(ret, "\"misc\" cmd"), "ret = %s\n", ret);
445 return;
446 }
447
448 for(len = strlen(path); len>0; len--)
449 if(path[len-1]=='\\' || path[len-1]=='/') break;
450 if(len) name = path+len;
451 else name = path;
452
453 sprintf(cmd, "\"\"%c\"\"\"%s\" \t \"misc\" cmd", name[0], name+1);
454 memset(&startup, 0, sizeof(startup));
455 startup.cb = sizeof(startup);
456 CreateProcessA(path, cmd, NULL, NULL, TRUE,
457 CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS,
458 NULL, NULL, &startup, &proc);
459 wait_child_process(proc.hProcess);
460 CloseHandle(proc.hProcess);
461 CloseHandle(proc.hThread);
462}
463
464static void test__sopen_dispatch(void)
465{
466 int ret, fd;
467 char *tempf;
468
469 tempf = _tempnam(".", "wne");
470
471 fd = 0;
472 ret = _sopen_dispatch(tempf, _O_CREAT, _SH_DENYWR, 0xff, &fd, 0);
473 ok(!ret, "got %d\n", ret);
474 ok(fd > 0, "got fd %d\n", fd);
475 _close(fd);
476 unlink(tempf);
477
478 SET_EXPECT(global_invalid_parameter_handler);
479 fd = 0;
480 ret = _sopen_dispatch(tempf, _O_CREAT, _SH_DENYWR, 0xff, &fd, 1);
481 ok(ret == EINVAL, "got %d\n", ret);
482 ok(fd == -1, "got fd %d\n", fd);
483 CHECK_CALLED(global_invalid_parameter_handler);
484 if (fd > 0)
485 {
486 _close(fd);
487 unlink(tempf);
488 }
489
490 free(tempf);
491}
492
493static void test__sopen_s(void)
494{
495 int ret, fd;
496 char *tempf;
497
498 tempf = _tempnam(".", "wne");
499
500 fd = 0;
501 ret = _sopen_s(&fd, tempf, _O_CREAT, _SH_DENYWR, 0);
502 ok(!ret, "got %d\n", ret);
503 ok(fd > 0, "got fd %d\n", fd);
504 _close(fd);
505 unlink(tempf);
506
507 /* _open() does not validate pmode */
508 fd = _open(tempf, _O_CREAT, 0xff);
509 ok(fd > 0, "got fd %d\n", fd);
510 _close(fd);
511 unlink(tempf);
512
513 /* _sopen_s() invokes invalid parameter handler on invalid pmode */
514 SET_EXPECT(global_invalid_parameter_handler);
515 fd = 0;
516 ret = _sopen_s(&fd, tempf, _O_CREAT, _SH_DENYWR, 0xff);
517 ok(ret == EINVAL, "got %d\n", ret);
518 ok(fd == -1, "got fd %d\n", fd);
519 CHECK_CALLED(global_invalid_parameter_handler);
520
521 free(tempf);
522}
523
524static void test_lldiv(void)
525{
526 lldiv_t r;
527
528 r = lldiv(((LONGLONG)0x111 << 32) + 0x222, (LONGLONG)1 << 32);
529 ok(r.quot == 0x111, "quot = %s\n", wine_dbgstr_longlong(r.quot));
530 ok(r.rem == 0x222, "rem = %s\n", wine_dbgstr_longlong(r.rem));
531
532 r = lldiv(((LONGLONG)0x69CF0012 << 32) + 0x0033E78A, 0x30);
533 ok(r.quot == ((LONGLONG)0x02345000 << 32) + 0x600114D2, "quot = %s\n", wine_dbgstr_longlong(r.quot));
534 ok(r.rem == 0x2A, "rem = %s\n", wine_dbgstr_longlong(r.rem));
535
536 r = lldiv(((LONGLONG)0x243A5678 << 32) + 0x9ABCDEF0, (LONGLONG)0x12 << 48);
537 ok(r.quot == 0x0203, "quot = %s\n", wine_dbgstr_longlong(r.quot));
538 ok(r.rem == ((LONGLONG)0x00045678 << 32) + 0x9ABCDEF0, "rem = %s\n", wine_dbgstr_longlong(r.rem));
539}
540
541static void test_isblank(void)
542{
543 int c, r;
544
545 for(c = 0; c <= 0xff; c++) {
546 if(c == '\t') {
547 ok(!_isctype(c, _BLANK), "tab shouldn't be blank\n");
548 ok(isblank(c), "%d should be blank\n", c);
549 r = _isblank_l(c, NULL);
550 ok(!r || broken(r == _BLANK), "tab shouldn't be blank (got %x)\n", r);
551 } else if(c == ' ') {
552 ok(_isctype(c, _BLANK), "space should be blank\n");
553 ok(isblank(c), "%d should be blank\n", c);
554 r = _isblank_l(c, NULL);
555 ok(r == _BLANK, "space should be blank (got %x)\n", r);
556 } else {
557 ok(!_isctype(c, _BLANK), "%d shouldn't be blank\n", c);
558 ok(!isblank(c), "%d shouldn't be blank\n", c);
559 ok(!_isblank_l(c, NULL), "%d shouldn't be blank\n", c);
560 }
561 }
562
563 for(c = 0; c <= 0xffff; c++) {
564 if(c == '\t' || c == ' ' || c == 0x3000 || c == 0xfeff) {
565 if(c == '\t')
566 ok(!_iswctype_l(c, _BLANK, NULL), "tab shouldn't be blank\n");
567 else
568 ok(_iswctype_l(c, _BLANK, NULL), "%d should be blank\n", c);
569 ok(iswblank(c), "%d should be blank\n", c);
570 ok(_iswblank_l(c, NULL), "%d should be blank\n", c);
571 } else {
572 ok(!_iswctype_l(c, _BLANK, NULL), "%d shouldn't be blank\n", c);
573 ok(!iswblank(c), "%d shouldn't be blank\n", c);
574 ok(!_iswblank_l(c, NULL), "%d shouldn't be blank\n", c);
575 }
576 }
577}
578
579static struct _exception exception;
580
581static int CDECL matherr_callback(struct _exception *e)
582{
583 exception = *e;
584
585 if (!strcmp(e->name, "acos") && e->arg1 == 2)
586 e->retval = -1;
587 return 0;
588}
589
590static void test_math_errors(void)
591{
592 const struct {
593 char func[16];
594 double x;
595 int error;
596 int exception;
597 } testsd[] = {
598 {"_logb", -INFINITY, -1, -1},
599 {"_logb", -1, -1, -1},
600 {"_logb", 0, ERANGE, _SING},
601 {"_logb", INFINITY, -1, -1},
602 {"acos", -INFINITY, EDOM, _DOMAIN},
603 {"acos", -2, EDOM, _DOMAIN},
604 {"acos", -1, -1, -1},
605 {"acos", 1, -1, -1},
606 {"acos", 2, EDOM, _DOMAIN},
607 {"acos", INFINITY, EDOM, _DOMAIN},
608 {"acosh", -INFINITY, EDOM, -1},
609 {"acosh", 0, EDOM, -1},
610 {"acosh", 1, -1, -1},
611 {"acosh", INFINITY, -1, -1},
612 {"asin", -INFINITY, EDOM, _DOMAIN},
613 {"asin", -2, EDOM, _DOMAIN},
614 {"asin", -1, -1, -1},
615 {"asin", 1, -1, -1},
616 {"asin", 2, EDOM, _DOMAIN},
617 {"asin", INFINITY, EDOM, _DOMAIN},
618 {"asinh", -INFINITY, -1, -1},
619 {"asinh", INFINITY, -1, -1},
620 {"atan", -INFINITY, -1, -1},
621 {"atan", 0, -1, -1},
622 {"atan", INFINITY, -1, -1},
623 {"atanh", -INFINITY, EDOM, -1},
624 {"atanh", -2, EDOM, -1},
625 {"atanh", -1, ERANGE, -1},
626 {"atanh", 1, ERANGE, -1},
627 {"atanh", 2, EDOM, -1},
628 {"atanh", INFINITY, EDOM, -1},
629 {"cos", -INFINITY, EDOM, _DOMAIN},
630 {"cos", INFINITY, EDOM, _DOMAIN},
631 {"cosh", -INFINITY, -1, -1},
632 {"cosh", 0, -1, -1},
633 {"cosh", INFINITY, -1, -1},
634 {"exp", -INFINITY, -1, -1},
635 {"exp", -1e100, -1, _UNDERFLOW},
636 {"exp", 1e100, ERANGE, _OVERFLOW},
637 {"exp", INFINITY, -1, -1},
638 {"exp2", -INFINITY, -1, -1},
639 {"exp2", -1e100, -1, -1},
640 {"exp2", 1e100, ERANGE, -1},
641 {"exp2", INFINITY, -1, -1},
642 {"expm1", -INFINITY, -1, -1},
643 {"expm1", INFINITY, -1, -1},
644 {"log", -INFINITY, EDOM, _DOMAIN},
645 {"log", -1, EDOM, _DOMAIN},
646 {"log", 0, ERANGE, _SING},
647 {"log", INFINITY, -1, -1},
648 {"log10", -INFINITY, EDOM, _DOMAIN},
649 {"log10", -1, EDOM, _DOMAIN},
650 {"log10", 0, ERANGE, _SING},
651 {"log10", INFINITY, -1, -1},
652 {"log1p", -INFINITY, EDOM, -1},
653 {"log1p", -2, EDOM, -1},
654 {"log1p", -1, ERANGE, -1},
655 {"log1p", INFINITY, -1, -1},
656 {"log2", INFINITY, -1, -1},
657 {"sin", -INFINITY, EDOM, _DOMAIN},
658 {"sin", INFINITY, EDOM, _DOMAIN},
659 {"sinh", -INFINITY, -1, -1},
660 {"sinh", 0, -1, -1},
661 {"sinh", INFINITY, -1, -1},
662 {"sqrt", -INFINITY, EDOM, _DOMAIN},
663 {"sqrt", -1, EDOM, _DOMAIN},
664 {"sqrt", 0, -1, -1},
665 {"sqrt", INFINITY, -1, -1},
666 {"tan", -INFINITY, EDOM, _DOMAIN},
667 {"tan", -M_PI_2, -1, -1},
668 {"tan", M_PI_2, -1, -1},
669 {"tan", INFINITY, EDOM, _DOMAIN},
670 {"tanh", -INFINITY, -1, -1},
671 {"tanh", 0, -1, -1},
672 {"tanh", INFINITY, -1, -1},
673 };
674 const struct {
675 char func[16];
676 double a;
677 double b;
678 int error;
679 int exception;
680 } tests2d[] = {
681 {"atan2", -INFINITY, 0, -1, -1},
682 {"atan2", 0, 0, -1, -1},
683 {"atan2", INFINITY, 0, -1, -1},
684 {"atan2", 0, -INFINITY, -1, -1},
685 {"atan2", 0, INFINITY, -1, -1},
686 {"pow", -INFINITY, -2, -1, -1},
687 {"pow", -INFINITY, -1, -1, -1},
688 {"pow", -INFINITY, 0, -1, -1},
689 {"pow", -INFINITY, 1, -1, -1},
690 {"pow", -INFINITY, 2, -1, -1},
691 {"pow", -1e100, -10, -1, _UNDERFLOW},
692 {"pow", -1e100, 10, ERANGE, _OVERFLOW},
693 {"pow", -1, 1.5, EDOM, _DOMAIN},
694 {"pow", 0, -2, ERANGE, _SING},
695 {"pow", 0, -1, ERANGE, _SING},
696 {"pow", 0.5, -INFINITY, -1, -1},
697 {"pow", 0.5, INFINITY, -1, -1},
698 {"pow", 2, -INFINITY, -1, -1},
699 {"pow", 2, -1e100, -1, _UNDERFLOW},
700 {"pow", 2, 1e100, ERANGE, _OVERFLOW},
701 {"pow", 2, INFINITY, -1, -1},
702 {"pow", 1e100, -10, -1, _UNDERFLOW},
703 {"pow", 1e100, 10, ERANGE, _OVERFLOW},
704 {"pow", INFINITY, -2, -1, -1},
705 {"pow", INFINITY, -1, -1, -1},
706 {"pow", INFINITY, 0, -1, -1},
707 {"pow", INFINITY, 1, -1, -1},
708 {"pow", INFINITY, 2, -1, -1},
709 };
710 const struct {
711 char func[16];
712 double a;
713 double b;
714 double c;
715 int error;
716 int exception;
717 } tests3d[] = {
718 /* 0 * inf --> EDOM */
719 {"fma", INFINITY, 0, 0, EDOM, -1},
720 {"fma", 0, INFINITY, 0, EDOM, -1},
721 /* inf - inf -> EDOM */
722 {"fma", INFINITY, 1, -INFINITY, EDOM, -1},
723 {"fma", -INFINITY, 1, INFINITY, EDOM, -1},
724 {"fma", 1, INFINITY, -INFINITY, EDOM, -1},
725 {"fma", 1, -INFINITY, INFINITY, EDOM, -1},
726 /* NaN */
727 {"fma", NAN, 0, 0, -1, -1},
728 {"fma", 0, NAN, 0, -1, -1},
729 {"fma", 0, 0, NAN, -1, -1},
730 /* over/underflow */
731 {"fma", __port_max_double(), __port_max_double(), __port_max_double(), -1, -1},
732 {"fma", __port_min_pos_double(), __port_min_pos_double(), 1, -1, -1},
733 };
734 const struct {
735 char func[16];
736 double a;
737 long b;
738 int error;
739 int exception;
740 } testsdl[] = {
741 {"_scalb", -INFINITY, 1, -1, -1},
742 {"_scalb", -1e100, 1, -1, -1},
743 {"_scalb", 0, 1, -1, -1},
744 {"_scalb", 1e100, 1, -1, -1},
745 {"_scalb", INFINITY, 1, -1, -1},
746 {"_scalb", 1, 1e9, ERANGE, _OVERFLOW},
747 {"ldexp", -INFINITY, 1, -1, -1},
748 {"ldexp", -1e100, 1, -1, -1},
749 {"ldexp", 0, 1, -1, -1},
750 {"ldexp", 1e100, 1, -1, -1},
751 {"ldexp", INFINITY, 1, -1, -1},
752 {"ldexp", 1, -1e9, -1, _UNDERFLOW},
753 {"ldexp", 1, 1e9, ERANGE, _OVERFLOW},
754 };
755 double (CDECL *p_funcd)(double);
756 double (CDECL *p_func2d)(double, double);
757 double (CDECL *p_func3d)(double, double, double);
758 double (CDECL *p_funcdl)(double, long);
759 HMODULE module;
760 double d;
761 int i;
762
763 __setusermatherr(matherr_callback);
764 module = GetModuleHandleW(L"ucrtbase.dll");
765
766 /* necessary so that exp(1e100)==INFINITY on glibc, we can remove this if we change our implementation */
767 fesetround(FE_TONEAREST);
768
769 for(i = 0; i < ARRAY_SIZE(testsd); i++) {
770 p_funcd = (void*)GetProcAddress(module, testsd[i].func);
771 errno = -1;
772 exception.type = -1;
773 p_funcd(testsd[i].x);
774 ok(errno == testsd[i].error,
775 "%s(%f) got errno %d\n", testsd[i].func, testsd[i].x, errno);
776 ok(exception.type == testsd[i].exception,
777 "%s(%f) got exception type %d\n", testsd[i].func, testsd[i].x, exception.type);
778 if(exception.type == -1) continue;
779 ok(exception.arg1 == testsd[i].x,
780 "%s(%f) got exception arg1 %f\n", testsd[i].func, testsd[i].x, exception.arg1);
781 }
782
783 for(i = 0; i < ARRAY_SIZE(tests2d); i++) {
784 p_func2d = (void*)GetProcAddress(module, tests2d[i].func);
785 errno = -1;
786 exception.type = -1;
787 p_func2d(tests2d[i].a, tests2d[i].b);
788 ok(errno == tests2d[i].error,
789 "%s(%f, %f) got errno %d\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, errno);
790 ok(exception.type == tests2d[i].exception,
791 "%s(%f, %f) got exception type %d\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.type);
792 if(exception.type == -1) continue;
793 ok(exception.arg1 == tests2d[i].a,
794 "%s(%f, %f) got exception arg1 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg1);
795 ok(exception.arg2 == tests2d[i].b,
796 "%s(%f, %f) got exception arg2 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg2);
797 }
798
799 for(i = 0; i < ARRAY_SIZE(tests3d); i++) {
800 p_func3d = (void*)GetProcAddress(module, tests3d[i].func);
801 errno = -1;
802 exception.type = -1;
803 p_func3d(tests3d[i].a, tests3d[i].b, tests3d[i].c);
804 ok(errno == tests3d[i].error || errno == -1, /* native is not setting errno if FMA3 is supported */
805 "%s(%f, %f, %f) got errno %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, errno);
806 ok(exception.type == tests3d[i].exception,
807 "%s(%f, %f, %f) got exception type %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.type);
808 if(exception.type == -1) continue;
809 ok(exception.arg1 == tests3d[i].a,
810 "%s(%f, %f, %f) got exception arg1 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg1);
811 ok(exception.arg2 == tests3d[i].b,
812 "%s(%f, %f, %f) got exception arg2 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg2);
813 }
814
815 for(i = 0; i < ARRAY_SIZE(testsdl); i++) {
816 p_funcdl = (void*)GetProcAddress(module, testsdl[i].func);
817 errno = -1;
818 exception.type = -1;
819 p_funcdl(testsdl[i].a, testsdl[i].b);
820 ok(errno == testsdl[i].error,
821 "%s(%f, %ld) got errno %d\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, errno);
822 ok(exception.type == testsdl[i].exception,
823 "%s(%f, %ld) got exception type %d\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.type);
824 if(exception.type == -1) continue;
825 ok(exception.arg1 == testsdl[i].a,
826 "%s(%f, %ld) got exception arg1 %f\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.arg1);
827 ok(exception.arg2 == testsdl[i].b,
828 "%s(%f, %ld) got exception arg2 %f\n", testsdl[i].func, testsdl[i].a, testsdl[i].b, exception.arg2);
829 }
830
831 d = acos(2.0);
832 ok(d == -1.0, "failed to change log10 return value: %e\n", d);
833}
834
835static void test_asctime(void)
836{
837 const struct tm epoch = { 0, 0, 0, 1, 0, 70, 4, 0, 0 };
838 char *ret;
839
840 ret = asctime(&epoch);
841 ok(!strcmp(ret, "Thu Jan 1 00:00:00 1970\n"), "asctime returned %s\n", ret);
842}
843
844static void test_strftime(void)
845{
846 const struct {
847 const char *format;
848 const char *ret;
849 struct tm tm;
850 BOOL todo_value;
851 BOOL todo_handler;
852 } tests[] = {
853 {"%C", "", { 0, 0, 0, 1, 0, -2000, 4, 0, 0 }},
854 {"%C", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
855 {"%C", "00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
856 {"%C", "18", { 0, 0, 0, 1, 0, -1, 4, 0, 0 }},
857 {"%C", "19", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
858 {"%C", "99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
859 {"%C", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
860 {"%d", "", { 0, 0, 0, 0, 0, 70, 4, 0, 0 }},
861 {"%d", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
862 {"%d", "31", { 0, 0, 0, 31, 0, 70, 4, 0, 0 }},
863 {"%d", "", { 0, 0, 0, 32, 0, 70, 4, 0, 0 }},
864 {"%D", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
865 {"%D", "01/01/00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
866 {"%D", "01/01/99", { 0, 0, 0, 1, 0, -1, 4, 0, 0 }},
867 {"%D", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
868 {"%D", "01/01/99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
869 {"%D", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
870 {"%#D", "1/1/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
871 {"%e", "", { 0, 0, 0, 0, 0, 70, 4, 0, 0 }},
872 {"%e", " 1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
873 {"%e", "31", { 0, 0, 0, 31, 0, 70, 4, 0, 0 }},
874 {"%e", "", { 0, 0, 0, 32, 0, 70, 4, 0, 0 }},
875 {"%#e", "1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
876 {"%F", "1970-01-01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
877 {"%#F", "1970-1-1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
878 {"%R", "00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
879 {"%#R", "0:0", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
880 {"%T", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
881 {"%#T", "0:0:0", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
882 {"%u", "", { 0, 0, 0, 1, 0, 117, -1, 0, 0 }},
883 {"%u", "7", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
884 {"%u", "1", { 0, 0, 0, 1, 0, 117, 1, 0, 0 }},
885 {"%u", "6", { 0, 0, 0, 1, 0, 117, 6, 0, 0 }},
886 {"%u", "", { 0, 0, 0, 1, 0, 117, 7, 0, 0 }},
887 {"%h", "Jan", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
888 {"%I", "", { 0, 0, -1, 1, 0, 70, 4, 0, 0 }},
889 {"%I", "12", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
890 {"%I", "01", { 0, 0, 1, 1, 0, 70, 4, 0, 0 }},
891 {"%I", "11", { 0, 0, 11, 1, 0, 70, 4, 0, 0 }},
892 {"%I", "12", { 0, 0, 12, 1, 0, 70, 4, 0, 0 }},
893 {"%I", "01", { 0, 0, 13, 1, 0, 70, 4, 0, 0 }},
894 {"%I", "11", { 0, 0, 23, 1, 0, 70, 4, 0, 0 }},
895 {"%I", "", { 0, 0, 24, 1, 0, 70, 4, 0, 0 }},
896 {"%n", "\n", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
897 {"%r", "12:00:00 AM", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
898 {"%r", "02:00:00 PM", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
899 {"%#r", "12:0:0 AM", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
900 {"%#r", "2:0:0 PM", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
901 {"%t", "\t", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
902 {"%g", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
903 {"%g", "", { 0, 0, 0, 1, 0, -1901, 3, 364, 0 }},
904 {"%g", "00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
905 {"%g", "70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
906 {"%g", "71", { 0, 0, 0, 2, 0, 72, 0, 1, 0 }},
907 {"%g", "72", { 0, 0, 0, 3, 0, 72, 1, 2, 0 }},
908 {"%g", "16", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
909 {"%g", "99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
910 {"%g", "00", { 0, 0, 0, 1, 0, 8099, 3, 364, 0 }},
911 {"%g", "", { 0, 0, 0, 1, 0, 8100, 0, 0, 0 }},
912 {"%g", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
913 {"%G", "1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
914 {"%G", "1971", { 0, 0, 0, 2, 0, 72, 0, 1, 0 }},
915 {"%G", "1972", { 0, 0, 0, 3, 0, 72, 1, 2, 0 }},
916 {"%G", "2016", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
917 {"%V", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
918 {"%V", "52", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
919 {"%V", "53", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
920 {"%y", "", { 0, 0, 0, 0, 0, -1901, 0, 0, 0 }},
921 {"%y", "00", { 0, 0, 0, 0, 0, -1900, 0, 0, 0 }},
922 {"%y", "99", { 0, 0, 0, 0, 0, 8099, 0, 0, 0 }},
923 {"%y", "", { 0, 0, 0, 0, 0, 8100, 0, 0, 0 }},
924 {"%c", "Thu Jan 1 00:00:00 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
925 {"%c", "Thu Feb 30 00:00:00 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
926 {"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
927 {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
928 {"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
929 {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
930 {"%#x", "Thursday, January 01, 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
931 {"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
932 {"%#x", "", { 0, 0, 0, 30, 1, 70, 7, 0, 0 }},
933 {"%#x", "", { 0, 0, 0, 30, 12, 70, 4, 0, 0 }},
934 {"%X", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
935 {"%X", "14:00:00", { 0, 0, 14, 1, 0, 70, 4, 0, 0 }},
936 {"%X", "23:59:60", { 60, 59, 23, 1, 0, 70, 4, 0, 0 }},
937 };
938
939 const struct {
940 const char *format;
941 const char *ret;
942 const wchar_t *short_date;
943 const wchar_t *date;
944 const wchar_t *time;
945 struct tm tm;
946 BOOL todo;
947 } tests_td[] = {
948 { "%c", "x z", L"x", L"y", L"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
949 { "%#c", "y z", L"x", L"y", L"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
950 { "%X", "M1", 0, 0, L"MMM", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
951 { "%X", "1", 0, 0, L"h", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
952 { "%X", "01", 0, 0, L"hh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
953 { "%X", "h01", 0, 0, L"hhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
954 { "%X", "hh01", 0, 0, L"hhhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
955 { "%X", "1", 0, 0, L"H", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
956 { "%X", "01", 0, 0, L"HH", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
957 { "%X", "H13", 0, 0, L"HHH", { 0, 0, 13, 1, 0, 70, 0, 0, 0 }},
958 { "%X", "0", 0, 0, L"m", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
959 { "%X", "00", 0, 0, L"mm", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
960 { "%X", "m00", 0, 0, L"mmm", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
961 { "%X", "0", 0, 0, L"s", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
962 { "%X", "00", 0, 0, L"ss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
963 { "%X", "s00", 0, 0, L"sss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
964 { "%X", "T", 0, 0, L"t", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
965 { "%X", "TAM", 0, 0, L"tt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
966 { "%X", "TAM", 0, 0, L"ttttttttt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
967 { "%X", "TAM", 0, 0, L"a", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
968 { "%X", "TAM", 0, 0, L"aaaaa", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
969 { "%X", "TAM", 0, 0, L"A", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
970 { "%X", "TAM", 0, 0, L"AAAAA", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
971 { "%x", "1", L"d", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
972 { "%x", "01", L"dd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
973 { "%x", "D1", L"ddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
974 { "%x", "Day1", L"dddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
975 { "%x", "dDay1", L"ddddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
976 { "%x", "1", L"M", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
977 { "%x", "01", L"MM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
978 { "%x", "M1", L"MMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
979 { "%x", "Mon1", L"MMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
980 { "%x", "MMon1", L"MMMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
981 { "%x", "y", L"y", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
982 { "%x", "70", L"yy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
983 { "%x", "y70", L"yyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
984 { "%x", "1970", L"yyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
985 { "%x", "y1970", L"yyyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
986 { "%x", "ggggggggggg", L"ggggggggggg", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
987 { "%#x", "1", 0, L"d", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
988 { "%#x", "01", 0, L"dd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
989 { "%#x", "D1", 0, L"ddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
990 { "%#x", "Day1", 0, L"dddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
991 { "%#x", "dDay1", 0, L"ddddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
992 { "%#x", "1", 0, L"M", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
993 { "%#x", "01", 0, L"MM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
994 { "%#x", "M1", 0, L"MMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
995 { "%#x", "Mon1", 0, L"MMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
996 { "%#x", "MMon1", 0, L"MMMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
997 { "%#x", "y", 0, L"y", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
998 { "%#x", "70", 0, L"yy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
999 { "%#x", "y70", 0, L"yyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
1000 { "%#x", "1970", 0, L"yyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
1001 { "%#x", "y1970", 0, L"yyyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
1002 { "%r", "z", L"x", L"y", L"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
1003 };
1004
1005 const struct {
1006 int year;
1007 int yday;
1008 const char *ret[7];
1009 } tests_yweek[] = {
1010 { 100, 0, { "99 52", "00 01", "00 01", "00 01", "00 01", "99 53", "99 52" }},
1011 { 100, 1, { "99 52", "00 01", "00 01", "00 01", "00 01", "00 01", "99 53" }},
1012 { 100, 2, { "99 53", "00 01", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1013 { 100, 3, { "00 01", "00 01", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1014 { 100, 4, { "00 01", "00 02", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1015 { 100, 5, { "00 01", "00 02", "00 02", "00 01", "00 01", "00 01", "00 01" }},
1016 { 100, 6, { "00 01", "00 02", "00 02", "00 02", "00 01", "00 01", "00 01" }},
1017 { 100, 358, { "00 51", "00 52", "00 52", "00 52", "00 52", "00 52", "00 51" }},
1018 { 100, 359, { "00 51", "00 52", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1019 { 100, 360, { "00 52", "00 52", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1020 { 100, 361, { "00 52", "00 53", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1021 { 100, 362, { "00 52", "00 53", "00 53", "00 52", "00 52", "00 52", "00 52" }},
1022 { 100, 363, { "00 52", "01 01", "00 53", "00 53", "00 52", "00 52", "00 52" }},
1023 { 100, 364, { "00 52", "01 01", "01 01", "00 53", "00 53", "00 52", "00 52" }},
1024 { 100, 365, { "00 52", "01 01", "01 01", "01 01", "00 53", "00 53", "00 52" }},
1025 { 101, 0, { "00 52", "01 01", "01 01", "01 01", "01 01", "00 53", "00 53" }},
1026 { 101, 1, { "00 53", "01 01", "01 01", "01 01", "01 01", "01 01", "00 53" }},
1027 { 101, 2, { "00 53", "01 01", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1028 { 101, 3, { "01 01", "01 01", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1029 { 101, 4, { "01 01", "01 02", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1030 { 101, 5, { "01 01", "01 02", "01 02", "01 01", "01 01", "01 01", "01 01" }},
1031 { 101, 6, { "01 01", "01 02", "01 02", "01 02", "01 01", "01 01", "01 01" }},
1032 { 101, 358, { "01 51", "01 52", "01 52", "01 52", "01 52", "01 52", "01 51" }},
1033 { 101, 359, { "01 51", "01 52", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1034 { 101, 360, { "01 52", "01 52", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1035 { 101, 361, { "01 52", "01 53", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1036 { 101, 362, { "01 52", "02 01", "01 53", "01 52", "01 52", "01 52", "01 52" }},
1037 { 101, 363, { "01 52", "02 01", "02 01", "01 53", "01 52", "01 52", "01 52" }},
1038 { 101, 364, { "01 52", "02 01", "02 01", "02 01", "01 53", "01 52", "01 52" }},
1039 };
1040
1041 __lc_time_data time_data = {
1042 { "d1", "d2", "d3", "d4", "d5", "d6", "d7" },
1043 { "day1", "day2", "day3", "day4", "day5", "day6", "day7" },
1044 { "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10", "m11", "m12" },
1045 { "mon1", "mon2", "mon3", "mon4", "mon5", "mon6", "mon7", "mon8", "mon9", "mon10", "mon11", "mon12" },
1046 "tam", "tpm", 0, 0, 0, 1, 0,
1047 { L"D1", L"D2", L"D3", L"D4", L"D5", L"D6", L"D7" },
1048 { L"Day1", L"Day2", L"Day3", L"Day4", L"Day5", L"Day6", L"Day7" },
1049 { L"M1", L"M2", L"M3", L"M4", L"M5", L"M6", L"M7", L"M8", L"M9", L"M10", L"M11", L"M12" },
1050 { L"Mon1", L"Mon2", L"Mon3", L"Mon4", L"Mon5", L"Mon6", L"Mon7", L"Mon8", L"Mon9", L"Mon10", L"Mon11", L"Mon12" },
1051 L"TAM", L"TPM"
1052 };
1053
1054 const struct tm epoch = { 0, 0, 0, 1, 0, 70, 4, 0, 0 };
1055 struct tm tm_yweek = { 0, 0, 0, 1, 0, 70, 0, 0, 0 };
1056 char buf[256];
1057 int i, ret=0;
1058
1059 for (i=0; i<ARRAY_SIZE(tests); i++)
1060 {
1061 todo_wine_if(tests[i].todo_handler) {
1062 if (!tests[i].ret[0])
1063 SET_EXPECT(global_invalid_parameter_handler);
1064 ret = strftime(buf, sizeof(buf), tests[i].format, &tests[i].tm);
1065 if (!tests[i].ret[0])
1066 CHECK_CALLED(global_invalid_parameter_handler);
1067 }
1068
1069 todo_wine_if(tests[i].todo_value) {
1070 ok(ret == strlen(tests[i].ret), "%d) ret = %d\n", i, ret);
1071 ok(!strcmp(buf, tests[i].ret), "%d) buf = \"%s\", expected \"%s\"\n",
1072 i, buf, tests[i].ret);
1073 }
1074 }
1075
1076 ret = strftime(buf, sizeof(buf), "%z", &epoch);
1077 ok(ret == 5, "expected 5, got %d\n", ret);
1078 ok((buf[0] == '+' || buf[0] == '-') &&
1079 isdigit(buf[1]) && isdigit(buf[2]) &&
1080 isdigit(buf[3]) && isdigit(buf[4]), "got %s\n", buf);
1081
1082 for (i=0; i<ARRAY_SIZE(tests_td); i++)
1083 {
1084 time_data.short_dateW = tests_td[i].short_date;
1085 time_data.dateW = tests_td[i].date;
1086 time_data.timeW = tests_td[i].time;
1087 ret = _Strftime(buf, sizeof(buf), tests_td[i].format, &tests_td[i].tm, &time_data);
1088 ok(ret == strlen(buf), "%d) ret = %d\n", i, ret);
1089 todo_wine_if(tests_td[i].todo) {
1090 ok(!strcmp(buf, tests_td[i].ret), "%d) buf = \"%s\", expected \"%s\"\n",
1091 i, buf, tests_td[i].ret);
1092 }
1093 }
1094
1095 for (i=0; i<ARRAY_SIZE(tests_yweek); i++)
1096 {
1097 int j;
1098 tm_yweek.tm_year = tests_yweek[i].year;
1099 tm_yweek.tm_yday = tests_yweek[i].yday;
1100 for (j=0; j<7; j++)
1101 {
1102 tm_yweek.tm_wday = j;
1103 strftime(buf, sizeof(buf), "%g %V", &tm_yweek);
1104 ok(!strcmp(buf, tests_yweek[i].ret[j]), "%d,%d) buf = \"%s\", expected \"%s\"\n",
1105 i, j, buf, tests_yweek[i].ret[j]);
1106 }
1107 }
1108
1109 if(!setlocale(LC_ALL, "fr-FR")) {
1110 win_skip("fr-FR locale not available\n");
1111 return;
1112 }
1113 ret = strftime(buf, sizeof(buf), "%c", &epoch);
1114 ok(ret == 19, "ret = %d\n", ret);
1115 ok(!strcmp(buf, "01/01/1970 00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "01/01/1970 00:00:00");
1116 ret = strftime(buf, sizeof(buf), "%r", &epoch);
1117 ok(ret == 8, "ret = %d\n", ret);
1118 ok(!strcmp(buf, "00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf, "00:00:00");
1119 setlocale(LC_ALL, "C");
1120
1121 if(!setlocale(LC_TIME, "Japanese_Japan.932")) {
1122 win_skip("Japanese_Japan.932 locale not available\n");
1123 return;
1124 }
1125 ret = strftime(buf, sizeof(buf), "%a", &epoch);
1126 ok(ret == 2 || broken(ret == 1), "ret = %d\n", ret);
1127 ok(!strcmp(buf, "\x96\xd8"), "buf = %s, expected \"\\x96\\xd8\"\n", wine_dbgstr_an(buf, 2));
1128 setlocale(LC_ALL, "C");
1129}
1130
1131static LONG* get_failures_counter(HANDLE *map)
1132{
1133 *map = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1134 0, sizeof(LONG), "winetest_failures_counter");
1135 return MapViewOfFile(*map, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LONG));
1136}
1137
1138static void free_failures_counter(LONG *mem, HANDLE map)
1139{
1140 UnmapViewOfFile(mem);
1141 CloseHandle(map);
1142}
1143
1144static void set_failures_counter(LONG add)
1145{
1146 HANDLE failures_map;
1147 LONG *failures;
1148
1149 failures = get_failures_counter(&failures_map);
1150 *failures = add;
1151 free_failures_counter(failures, failures_map);
1152}
1153
1154static void test_exit(const char *argv0)
1155{
1156 PROCESS_INFORMATION proc;
1157 STARTUPINFOA startup = {0};
1158 char path[MAX_PATH];
1159 HANDLE failures_map, exit_event, quick_exit_event;
1160 LONG *failures;
1161 DWORD ret;
1162
1163 exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event");
1164 quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event");
1165
1166 failures = get_failures_counter(&failures_map);
1167 sprintf(path, "%s misc exit", argv0);
1168 startup.cb = sizeof(startup);
1169 CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &proc);
1170 ret = WaitForSingleObject(proc.hProcess, INFINITE);
1171 ok(ret == WAIT_OBJECT_0, "child process wait failed\n");
1172 GetExitCodeProcess(proc.hProcess, &ret);
1173 ok(ret == 1, "child process exited with code %ld\n", ret);
1174 CloseHandle(proc.hProcess);
1175 CloseHandle(proc.hThread);
1176 ok(!*failures, "%ld tests failed in child process\n", *failures);
1177 free_failures_counter(failures, failures_map);
1178
1179
1180 ret = WaitForSingleObject(exit_event, 0);
1181 ok(ret == WAIT_OBJECT_0, "exit_event was not set (%lx)\n", ret);
1182 ret = WaitForSingleObject(quick_exit_event, 0);
1183 ok(ret == WAIT_TIMEOUT, "quick_exit_event should not have be set (%lx)\n", ret);
1184
1185 CloseHandle(exit_event);
1186 CloseHandle(quick_exit_event);
1187}
1188
1189static int atexit_called;
1190
1191static void CDECL at_exit_func1(void)
1192{
1193 HANDLE exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event");
1194
1195 ok(exit_event != NULL, "CreateEvent failed: %ld\n", GetLastError());
1196 ok(atexit_called == 1, "atexit_called = %d\n", atexit_called);
1197 atexit_called++;
1198 SetEvent(exit_event);
1199 CloseHandle(exit_event);
1200 set_failures_counter(winetest_get_failures());
1201}
1202
1203static void CDECL at_exit_func2(void)
1204{
1205 ok(!atexit_called, "atexit_called = %d\n", atexit_called);
1206 atexit_called++;
1207 set_failures_counter(winetest_get_failures());
1208}
1209
1210static int atquick_exit_called;
1211
1212static void CDECL at_quick_exit_func1(void)
1213{
1214 HANDLE quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event");
1215
1216 ok(quick_exit_event != NULL, "CreateEvent failed: %ld\n", GetLastError());
1217 ok(atquick_exit_called == 1, "atquick_exit_called = %d\n", atquick_exit_called);
1218 atquick_exit_called++;
1219 SetEvent(quick_exit_event);
1220 CloseHandle(quick_exit_event);
1221 set_failures_counter(winetest_get_failures());
1222}
1223
1224static void CDECL at_quick_exit_func2(void)
1225{
1226 ok(!atquick_exit_called, "atquick_exit_called = %d\n", atquick_exit_called);
1227 atquick_exit_called++;
1228 set_failures_counter(winetest_get_failures());
1229}
1230
1231static void test_call_exit(void)
1232{
1233 ok(!_crt_atexit(at_exit_func1), "_crt_atexit failed\n");
1234 ok(!_crt_atexit(at_exit_func2), "_crt_atexit failed\n");
1235
1236 ok(!_crt_at_quick_exit(at_quick_exit_func1), "_crt_at_quick_exit failed\n");
1237 ok(!_crt_at_quick_exit(at_quick_exit_func2), "_crt_at_quick_exit failed\n");
1238
1239 set_failures_counter(winetest_get_failures());
1240 exit(1);
1241}
1242
1243static void test_call_quick_exit(void)
1244{
1245 ok(!_crt_atexit(at_exit_func1), "_crt_atexit failed\n");
1246 ok(!_crt_atexit(at_exit_func2), "_crt_atexit failed\n");
1247
1248 ok(!_crt_at_quick_exit(at_quick_exit_func1), "_crt_at_quick_exit failed\n");
1249 ok(!_crt_at_quick_exit(at_quick_exit_func2), "_crt_at_quick_exit failed\n");
1250
1251 set_failures_counter(winetest_get_failures());
1252 quick_exit(2);
1253}
1254
1255static void test_quick_exit(const char *argv0)
1256{
1257 PROCESS_INFORMATION proc;
1258 STARTUPINFOA startup = {0};
1259 char path[MAX_PATH];
1260 HANDLE failures_map, exit_event, quick_exit_event;
1261 LONG *failures;
1262 DWORD ret;
1263
1264 exit_event = CreateEventA(NULL, FALSE, FALSE, "exit_event");
1265 quick_exit_event = CreateEventA(NULL, FALSE, FALSE, "quick_exit_event");
1266
1267 failures = get_failures_counter(&failures_map);
1268 sprintf(path, "%s misc quick_exit", argv0);
1269 startup.cb = sizeof(startup);
1270 CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &proc);
1271 ret = WaitForSingleObject(proc.hProcess, INFINITE);
1272 ok(ret == WAIT_OBJECT_0, "child process wait failed\n");
1273 GetExitCodeProcess(proc.hProcess, &ret);
1274 ok(ret == 2, "child process exited with code %ld\n", ret);
1275 CloseHandle(proc.hProcess);
1276 CloseHandle(proc.hThread);
1277 ok(!*failures, "%ld tests failed in child process\n", *failures);
1278 free_failures_counter(failures, failures_map);
1279
1280 ret = WaitForSingleObject(quick_exit_event, 0);
1281 ok(ret == WAIT_OBJECT_0, "quick_exit_event was not set (%lx)\n", ret);
1282 ret = WaitForSingleObject(exit_event, 0);
1283 ok(ret == WAIT_TIMEOUT, "exit_event should not have be set (%lx)\n", ret);
1284
1285 CloseHandle(exit_event);
1286 CloseHandle(quick_exit_event);
1287}
1288
1289static void test__stat32(void)
1290{
1291 static const char test_file[] = "\\stat_file.tst";
1292 static const char test_dir[] = "\\stat_dir.tst";
1293
1294 char path[2*MAX_PATH];
1295 struct _stat32 buf;
1296 int fd, ret;
1297 DWORD len;
1298
1299 len = GetTempPathA(MAX_PATH, path);
1300 ok(len, "GetTempPathA failed\n");
1301
1302 ret = _stat32("c:", &buf);
1303 ok(ret == -1, "_stat32('c:') returned %d\n", ret);
1304 ret = _stat32("c:\\", &buf);
1305 ok(!ret, "_stat32('c:\\') returned %d\n", ret);
1306
1307 memcpy(path+len, test_file, sizeof(test_file));
1308 if((fd = open(path, O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE)) >= 0)
1309 {
1310 ret = _stat32(path, &buf);
1311 ok(!ret, "_stat32('%s') returned %d\n", path, ret);
1312 strcat(path, "\\");
1313 ret = _stat32(path, &buf);
1314 ok(ret, "_stat32('%s') returned %d\n", path, ret);
1315 close(fd);
1316 remove(path);
1317 }
1318
1319 memcpy(path+len, test_dir, sizeof(test_dir));
1320 if(!mkdir(path))
1321 {
1322 ret = _stat32(path, &buf);
1323 ok(!ret, "_stat32('%s') returned %d\n", path, ret);
1324 strcat(path, "\\");
1325 ret = _stat32(path, &buf);
1326 ok(!ret, "_stat32('%s') returned %d\n", path, ret);
1327 rmdir(path);
1328 }
1329}
1330
1331static void test__o_malloc(void)
1332{
1333 void *m;
1334 size_t s;
1335
1336 m = _o_malloc(1);
1337 ok(m != NULL, "p__o_malloc(1) returned NULL\n");
1338
1339 s = _msize(m);
1340 ok(s == 1, "_msize returned %d\n", (int)s);
1341
1342 free(m);
1343}
1344
1345static void test_clock(void)
1346{
1347 static const int thresh = 100, max_load_delay = 1000;
1348 int c, expect_min;
1349 FILETIME cur;
1350
1351 GetSystemTimeAsFileTime(&cur);
1352 c = clock();
1353
1354 expect_min = (((LONGLONG)cur.dwHighDateTime << 32) + cur.dwLowDateTime - crt_init_end) / 10000;
1355 ok(c >= expect_min - thresh && c < expect_min + max_load_delay, "clock() = %d, expected range [%d, %d]\n",
1356 c, expect_min - thresh, expect_min + max_load_delay);
1357}
1358
1359static void __cdecl se_translator(unsigned int u, EXCEPTION_POINTERS *ep)
1360{
1361}
1362
1363static void test_thread_storage(void)
1364{
1365 void **current_exception;
1366 void *processing_throw;
1367
1368 _set_se_translator(se_translator);
1369 current_exception = __current_exception();
1370 processing_throw = __processing_throw();
1371
1372 ok(current_exception+2 == processing_throw,
1373 "current_exception = %p, processing_throw = %p\n",
1374 current_exception, processing_throw);
1375 ok(current_exception[-2] == se_translator,
1376 "can't find se_translator in thread storage\n");
1377}
1378
1379static unsigned long fenv_encode(unsigned int e)
1380{
1381 ok(!(e & ~FE_ALL_EXCEPT), "incorrect argument: %x\n", e);
1382
1383#if defined(__i386__)
1384 return e<<24 | e<<16 | e;
1385#elif defined(__x86_64__)
1386 return e<<24 | e;
1387#else
1388 return e;
1389#endif
1390}
1391
1392static void test_fenv(void)
1393{
1394 static const int tests[] = {
1395 0,
1396 FE_INEXACT,
1397 FE_UNDERFLOW,
1398 FE_OVERFLOW,
1399 FE_DIVBYZERO,
1400 FE_INVALID,
1401 FE_ALL_EXCEPT,
1402 };
1403 static const struct {
1404 fexcept_t except;
1405 unsigned int flag;
1406 unsigned int get;
1407 fexcept_t expect;
1408 } tests2[] = {
1409 /* except flag get expect */
1410 { 0, 0, 0, 0 },
1411 { FE_ALL_EXCEPT, FE_INEXACT, 0, 0 },
1412 { FE_ALL_EXCEPT, FE_INEXACT, FE_ALL_EXCEPT, FE_INEXACT },
1413 { FE_ALL_EXCEPT, FE_INEXACT, FE_INEXACT, FE_INEXACT },
1414 { FE_ALL_EXCEPT, FE_INEXACT, FE_OVERFLOW, 0 },
1415 { FE_ALL_EXCEPT, FE_ALL_EXCEPT, FE_ALL_EXCEPT, FE_ALL_EXCEPT },
1416 { FE_ALL_EXCEPT, FE_ALL_EXCEPT, FE_INEXACT, FE_INEXACT },
1417 { FE_ALL_EXCEPT, FE_ALL_EXCEPT, 0, 0 },
1418 { FE_ALL_EXCEPT, FE_ALL_EXCEPT, ~0, FE_ALL_EXCEPT },
1419 { FE_ALL_EXCEPT, FE_ALL_EXCEPT, ~FE_ALL_EXCEPT, 0 },
1420 { FE_INEXACT, FE_ALL_EXCEPT, FE_ALL_EXCEPT, FE_INEXACT },
1421 { FE_INEXACT, FE_UNDERFLOW, FE_ALL_EXCEPT, 0 },
1422 { FE_UNDERFLOW, FE_INEXACT, FE_ALL_EXCEPT, 0 },
1423 { FE_INEXACT|FE_UNDERFLOW, FE_UNDERFLOW, FE_ALL_EXCEPT, FE_UNDERFLOW },
1424 { FE_UNDERFLOW, FE_INEXACT|FE_UNDERFLOW, FE_ALL_EXCEPT, FE_UNDERFLOW },
1425 };
1426 fenv_t env, env2;
1427 fexcept_t except;
1428 int i, ret, flags;
1429
1430 _clearfp();
1431
1432 ret = fegetenv(&env);
1433 ok(!ret, "fegetenv returned %x\n", ret);
1434#if defined(__i386__) || defined(__x86_64__)
1435 if (env._Fe_ctl >> 24 != (env._Fe_ctl & 0xff))
1436 {
1437 win_skip("fenv_t format not supported (too old ucrtbase)\n");
1438 return;
1439 }
1440#endif
1441 fesetround(FE_UPWARD);
1442 ok(!env._Fe_stat, "env._Fe_stat = %lx\n", env._Fe_stat);
1443 ret = fegetenv(&env2);
1444 ok(!ret, "fegetenv returned %x\n", ret);
1445 ok(env._Fe_ctl != env2._Fe_ctl, "fesetround didn't change _Fe_ctl (%lx).\n", env._Fe_ctl);
1446 ret = fesetenv(&env);
1447 ok(!ret, "fesetenv returned %x\n", ret);
1448 ret = fegetround();
1449 ok(ret == FE_TONEAREST, "Got unexpected round mode %#x.\n", ret);
1450
1451 except = fenv_encode(FE_ALL_EXCEPT);
1452 ret = fesetexceptflag(&except, FE_INEXACT|FE_UNDERFLOW);
1453 ok(!ret, "fesetexceptflag returned %x\n", ret);
1454 except = fetestexcept(FE_ALL_EXCEPT);
1455 ok(except == (FE_INEXACT|FE_UNDERFLOW), "expected %x, got %lx\n", FE_INEXACT|FE_UNDERFLOW, except);
1456
1457 ret = feclearexcept(~FE_ALL_EXCEPT);
1458 ok(!ret, "feclearexceptflag returned %x\n", ret);
1459 except = fetestexcept(FE_ALL_EXCEPT);
1460 ok(except == (FE_INEXACT|FE_UNDERFLOW), "expected %x, got %lx\n", FE_INEXACT|FE_UNDERFLOW, except);
1461
1462 /* no crash, but no-op */
1463 ret = fesetexceptflag(NULL, 0);
1464 ok(!ret, "fesetexceptflag returned %x\n", ret);
1465 except = fetestexcept(FE_ALL_EXCEPT);
1466 ok(except == (FE_INEXACT|FE_UNDERFLOW), "expected %x, got %lx\n", FE_INEXACT|FE_UNDERFLOW, except);
1467
1468 /* zero clears all */
1469 except = 0;
1470 ret = fesetexceptflag(&except, FE_ALL_EXCEPT);
1471 ok(!ret, "fesetexceptflag returned %x\n", ret);
1472 except = fetestexcept(FE_ALL_EXCEPT);
1473 ok(!except, "expected 0, got %lx\n", except);
1474
1475 ret = fetestexcept(FE_ALL_EXCEPT);
1476 ok(!ret, "fetestexcept returned %x\n", ret);
1477
1478 flags = 0;
1479 /* adding bits with flags */
1480 for(i=0; i<ARRAY_SIZE(tests); i++) {
1481 except = fenv_encode(FE_ALL_EXCEPT);
1482 ret = fesetexceptflag(&except, tests[i]);
1483 ok(!ret, "Test %d: fesetexceptflag returned %x\n", i, ret);
1484
1485 ret = fetestexcept(tests[i]);
1486 ok(ret == tests[i], "Test %d: expected %x, got %x\n", i, tests[i], ret);
1487
1488 flags |= tests[i];
1489 ret = fetestexcept(FE_ALL_EXCEPT);
1490 ok(ret == flags, "Test %d: expected %x, got %x\n", i, flags, ret);
1491
1492 except = ~0;
1493 ret = fegetexceptflag(&except, ~0);
1494 ok(!ret, "Test %d: fegetexceptflag returned %x.\n", i, ret);
1495 ok(except == fenv_encode(flags),
1496 "Test %d: expected %lx, got %lx\n", i, fenv_encode(flags), except);
1497
1498 except = ~0;
1499 ret = fegetexceptflag(&except, tests[i]);
1500 ok(!ret, "Test %d: fegetexceptflag returned %x.\n", i, ret);
1501 ok(except == fenv_encode(tests[i]),
1502 "Test %d: expected %lx, got %lx\n", i, fenv_encode(tests[i]), except);
1503 }
1504
1505 for(i=0; i<ARRAY_SIZE(tests); i++) {
1506 ret = feclearexcept(tests[i]);
1507 ok(!ret, "Test %d: feclearexceptflag returned %x\n", i, ret);
1508
1509 flags &= ~tests[i];
1510 except = fetestexcept(tests[i]);
1511 ok(!except, "Test %d: expected %x, got %lx\n", i, flags, except);
1512 }
1513
1514 except = fetestexcept(FE_ALL_EXCEPT);
1515 ok(!except, "expected 0, got %lx\n", except);
1516
1517 /* setting bits with except */
1518 for(i=0; i<ARRAY_SIZE(tests); i++) {
1519 except = fenv_encode(tests[i]);
1520 ret = fesetexceptflag(&except, FE_ALL_EXCEPT);
1521 ok(!ret, "Test %d: fesetexceptflag returned %x\n", i, ret);
1522
1523 ret = fetestexcept(tests[i]);
1524 ok(ret == tests[i], "Test %d: expected %x, got %x\n", i, tests[i], ret);
1525
1526 ret = fetestexcept(FE_ALL_EXCEPT);
1527 ok(ret == tests[i], "Test %d: expected %x, got %x\n", i, tests[i], ret);
1528 }
1529
1530 for(i=0; i<ARRAY_SIZE(tests2); i++) {
1531 _clearfp();
1532
1533 except = fenv_encode(tests2[i].except);
1534 ret = fesetexceptflag(&except, tests2[i].flag);
1535 ok(!ret, "Test %d: fesetexceptflag returned %x\n", i, ret);
1536
1537 ret = fetestexcept(tests2[i].get);
1538 ok(ret == tests2[i].expect, "Test %d: expected %lx, got %x\n", i, tests2[i].expect, ret);
1539 }
1540
1541 ret = feclearexcept(FE_ALL_EXCEPT);
1542 ok(!ret, "feclearexceptflag returned %x\n", ret);
1543 except = fetestexcept(FE_ALL_EXCEPT);
1544 ok(!except, "expected 0, got %lx\n", except);
1545}
1546
1547static void test_fopen_exclusive( void )
1548{
1549 char path[MAX_PATH*2];
1550 DWORD len;
1551 FILE *fp;
1552
1553 len = GetTempPathA(MAX_PATH, path);
1554 ok(len, "GetTempPathA failed\n");
1555 strcat(path, "\\fileexcl.tst");
1556
1557 SET_EXPECT(global_invalid_parameter_handler);
1558 fp = fopen(path, "wx");
1559 if(called_global_invalid_parameter_handler)
1560 {
1561 win_skip("skipping fopen x mode tests.\n");
1562 return;
1563 }
1564 expect_global_invalid_parameter_handler = FALSE;
1565 ok(fp != NULL, "creating file with mode wx failed\n");
1566 fclose(fp);
1567
1568 fp = fopen(path, "wx");
1569 ok(!fp, "overwrote existing file with mode wx\n");
1570 unlink(path);
1571
1572 fp = fopen(path, "w+x");
1573 ok(fp != NULL, "creating file with mode w+x failed\n");
1574 fclose(fp);
1575
1576 fp = fopen(path, "w+x");
1577 ok(!fp, "overwrote existing file with mode w+x\n");
1578
1579 SET_EXPECT(global_invalid_parameter_handler);
1580 fp = fopen(path, "rx");
1581 CHECK_CALLED(global_invalid_parameter_handler);
1582 ok(!fp, "opening file with mode rx succeeded\n");
1583 unlink(path);
1584
1585 SET_EXPECT(global_invalid_parameter_handler);
1586 fp = fopen(path, "xw");
1587 CHECK_CALLED(global_invalid_parameter_handler);
1588 ok(!fp, "creating file with mode xw succeeded\n");
1589
1590 fp = fopen(path, "wbx");
1591 ok(fp != NULL, "creating file with mode wbx failed\n");
1592 fclose(fp);
1593 unlink(path);
1594}
1595
1596#if defined(__i386__)
1597#include "pshpack1.h"
1598struct rewind_thunk {
1599 BYTE push_esp[4]; /* push [esp+0x4] */
1600 BYTE call_rewind; /* call */
1601 DWORD rewind_addr; /* relative addr of rewind */
1602 BYTE pop_eax; /* pop eax */
1603 BYTE ret; /* ret */
1604};
1605#include "poppack.h"
1606
1607static FILE * (CDECL *test_rewind_wrapper)(FILE *fp);
1608
1609static void test_rewind_i386_abi(void)
1610{
1611 FILE *fp_in, *fp_out;
1612
1613 struct rewind_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1614
1615 thunk->push_esp[0] = 0xff;
1616 thunk->push_esp[1] = 0x74;
1617 thunk->push_esp[2] = 0x24;
1618 thunk->push_esp[3] = 0x04;
1619
1620 thunk->call_rewind = 0xe8;
1621 thunk->rewind_addr = (BYTE *) rewind - (BYTE *) (&thunk->rewind_addr + 1);
1622
1623 thunk->pop_eax = 0x58;
1624 thunk->ret = 0xc3;
1625
1626 test_rewind_wrapper = (void *) thunk;
1627
1628 fp_in = fopen("rewind_abi.tst", "wb");
1629 fp_out = test_rewind_wrapper(fp_in);
1630 ok(fp_in == fp_out, "rewind modified the first argument in the stack\n");
1631
1632 fclose(fp_in);
1633 unlink("rewind_abi.tst");
1634}
1635#endif
1636
1637static void test_gmtime64(void)
1638{
1639 struct tm *ptm, tm;
1640 __time64_t t;
1641 int ret;
1642
1643 t = -1;
1644 memset(&tm, 0xcc, sizeof(tm));
1645 ptm = _gmtime64(&t);
1646 ok(!!ptm, "got NULL.\n");
1647 ret = _gmtime64_s(&tm, &t);
1648 ok(!ret, "got %d.\n", ret);
1649 ok(tm.tm_year == 69 && tm.tm_hour == 23 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
1650 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1651
1652 t = -43200;
1653 memset(&tm, 0xcc, sizeof(tm));
1654 ptm = _gmtime64(&t);
1655 ok(!!ptm, "got NULL.\n");
1656 ret = _gmtime64_s(&tm, &t);
1657 ok(!ret, "got %d.\n", ret);
1658 ok(tm.tm_year == 69 && tm.tm_hour == 12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
1659 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1660 ptm = _gmtime32((__time32_t *)&t);
1661 ok(!!ptm, "got NULL.\n");
1662 memset(&tm, 0xcc, sizeof(tm));
1663 ret = _gmtime32_s(&tm, (__time32_t *)&t);
1664 ok(!ret, "got %d.\n", ret);
1665 todo_wine_if(tm.tm_year == 69 && tm.tm_hour == 12)
1666 ok(tm.tm_year == 70 && tm.tm_hour == -12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n",
1667 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1668
1669 t = -43201;
1670 ptm = _gmtime64(&t);
1671 ok(!ptm, "got non-NULL.\n");
1672 memset(&tm, 0xcc, sizeof(tm));
1673 ret = _gmtime64_s(&tm, &t);
1674 ok(ret == EINVAL, "got %d.\n", ret);
1675 ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
1676 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1677 ptm = _gmtime32((__time32_t *)&t);
1678 ok(!ptm, "got NULL.\n");
1679 memset(&tm, 0xcc, sizeof(tm));
1680 ret = _gmtime32_s(&tm, (__time32_t *)&t);
1681 ok(ret == EINVAL, "got %d.\n", ret);
1682 ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
1683 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1684
1685 t = _MAX__TIME64_T + 1605600;
1686 memset(&tm, 0xcc, sizeof(tm));
1687 ptm = _gmtime64(&t);
1688 ok(!!ptm || broken(!ptm) /* before Win10 1909 */, "got NULL.\n");
1689 if (!ptm)
1690 {
1691 win_skip("Old gmtime64 limits, skipping tests.\n");
1692 return;
1693 }
1694 ret = _gmtime64_s(&tm, &t);
1695 ok(!ret, "got %d.\n", ret);
1696 ok(tm.tm_year == 1101 && tm.tm_hour == 21 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n",
1697 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1698
1699 t = _MAX__TIME64_T + 1605601;
1700 ptm = _gmtime64(&t);
1701 ok(!ptm, "got non-NULL.\n");
1702 memset(&tm, 0xcc, sizeof(tm));
1703 ret = _gmtime64_s(&tm, &t);
1704 ok(ret == EINVAL, "got %d.\n", ret);
1705 ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n",
1706 tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec);
1707}
1708
1709static void test__get_heap_handle(void)
1710{
1711 ok((HANDLE)_get_heap_handle() == GetProcessHeap(), "Expected _get_heap_handle() to return GetProcessHeap()\n");
1712}
1713
1714START_TEST(misc)
1715{
1716 int arg_c;
1717 char** arg_v;
1718 FILETIME cur;
1719
1720 GetSystemTimeAsFileTime(&cur);
1721 crt_init_end = ((LONGLONG)cur.dwHighDateTime << 32) + cur.dwLowDateTime;
1722
1723 arg_c = winetest_get_mainargs(&arg_v);
1724 if(arg_c == 3) {
1725 if(!strcmp(arg_v[2], "cmd"))
1726 test__get_narrow_winmain_command_line(NULL);
1727 else if(!strcmp(arg_v[2], "exit"))
1728 test_call_exit();
1729 else if(!strcmp(arg_v[2], "quick_exit"))
1730 test_call_quick_exit();
1731 return;
1732 }
1733
1734 test_invalid_parameter_handler();
1735 test__initialize_onexit_table();
1736 test__register_onexit_function();
1737 test__execute_onexit_table();
1738 test___fpe_flt_rounds();
1739 test__control87_2();
1740 test__get_narrow_winmain_command_line(arg_v[0]);
1741 test__sopen_dispatch();
1742 test__sopen_s();
1743 test_lldiv();
1744 test_isblank();
1745 test_math_errors();
1746 test_asctime();
1747 test_strftime();
1748 test_exit(arg_v[0]);
1749 test_quick_exit(arg_v[0]);
1750 test__stat32();
1751 test__o_malloc();
1752 test_clock();
1753 test_thread_storage();
1754 test_fenv();
1755 test_fopen_exclusive();
1756#if defined(__i386__)
1757 test_rewind_i386_abi();
1758#endif
1759 test_gmtime64();
1760 test__get_heap_handle();
1761}