diff --git a/rostests/winetests/msvcrt/CMakeLists.txt b/rostests/winetests/msvcrt/CMakeLists.txt index 875f4859532..5e0d8480412 100644 --- a/rostests/winetests/msvcrt/CMakeLists.txt +++ b/rostests/winetests/msvcrt/CMakeLists.txt @@ -1,8 +1,5 @@ -add_definitions( - -D__ROS_LONG64__ - -D_CRT_NONSTDC_NO_DEPRECATE - -D__msvcrt_ulong=ULONG) +add_definitions(-D__msvcrt_ulong=ULONG) list(APPEND SOURCE cpp.c @@ -23,12 +20,14 @@ list(APPEND SOURCE add_executable(msvcrt_winetest ${SOURCE}) +set_module_type(msvcrt_winetest win32cui) +add_importlibs(msvcrt_winetest msvcrt kernel32) + if(MSVC) target_link_libraries(msvcrt_winetest oldnames) + add_importlibs(msvcrt_winetest ntdll) else() add_target_compile_flags(msvcrt_winetest "-Wno-format") endif() -set_module_type(msvcrt_winetest win32cui) -add_importlibs(msvcrt_winetest msvcrt kernel32 ntdll) add_cd_file(TARGET msvcrt_winetest DESTINATION reactos/bin FOR all) diff --git a/rostests/winetests/msvcrt/cpp.c b/rostests/winetests/msvcrt/cpp.c index 8baf9b66d0e..c331db1bc4a 100644 --- a/rostests/winetests/msvcrt/cpp.c +++ b/rostests/winetests/msvcrt/cpp.c @@ -238,6 +238,55 @@ static BOOL InitFunctionPtrs(void) } else { +#ifdef __arm__ + SETNOFAIL(poperator_new, "??_U@YAPAXI@Z"); + SETNOFAIL(poperator_delete, "??_V@YAXPAX@Z"); + + SET(pexception_ctor, "??0exception@std@@QAA@ABQBD@Z"); + SET(pexception_copy_ctor, "??0exception@std@@QAA@ABV01@@Z"); + SET(pexception_default_ctor, "??0exception@std@@QAA@XZ"); + SET(pexception_dtor, "??1exception@std@@UAA@XZ"); + SET(pexception_opequals, "??4exception@std@@QAAAAV01@ABV01@@Z"); + SET(pexception_what, "?what@exception@std@@UBAPBDXZ"); + SET(pexception_vector_dtor, "??_Eexception@@UAEPAXI@Z");/**/ + SET(pexception_scalar_dtor, "??_Gexception@@UAEPAXI@Z");/**/ + + SET(pbad_typeid_ctor, "??0bad_typeid@std@@QAA@PBD@Z"); + SETNOFAIL(pbad_typeid_ctor_closure, "??_Fbad_typeid@std@@QAAXXZ"); + SET(pbad_typeid_copy_ctor, "??0bad_typeid@std@@QAA@ABV01@@Z"); + SET(pbad_typeid_dtor, "??1bad_typeid@std@@UAA@XZ"); + SET(pbad_typeid_opequals, "??4bad_typeid@std@@QAAAAV01@ABV01@@Z"); + SET(pbad_typeid_what, "?what@exception@std@@UBAPBDXZ"); + SET(pbad_typeid_vector_dtor, "??_Ebad_cast@@UAEPAXI@Z"); + SET(pbad_typeid_scalar_dtor, "??_Gbad_cast@@UAEPAXI@Z"); + + SETNOFAIL(pbad_cast_ctor, "??0bad_cast@@QAE@ABQBD@Z"); + if (!pbad_cast_ctor) + SET(pbad_cast_ctor, "??0bad_cast@std@@AAA@PBQBD@Z"); + SETNOFAIL(pbad_cast_ctor2, "??0bad_cast@std@@QAA@PBD@Z"); + SETNOFAIL(pbad_cast_ctor_closure, "??_Fbad_cast@std@@QAAXXZ"); + /* FIXME: No ARM equivalent for "??0bad_cast@@QAE@ABV0@@Z" */ + SET(pbad_cast_dtor, "??1bad_cast@std@@UAA@XZ"); + SET(pbad_cast_opequals, "??4bad_cast@std@@QAAAAV01@ABV01@@Z"); + SET(pbad_cast_what, "?what@exception@std@@UBAPBDXZ"); + SET(pbad_cast_vector_dtor, "??_Ebad_cast@@UAEPAXI@Z"); + SET(pbad_cast_scalar_dtor, "??_Gbad_cast@@UAEPAXI@Z"); + + SET(p__non_rtti_object_ctor, "??0__non_rtti_object@std@@QAA@PBD@Z"); + SET(p__non_rtti_object_copy_ctor, "??0__non_rtti_object@std@@QAA@ABV01@@Z"); + SET(p__non_rtti_object_dtor, "??1__non_rtti_object@std@@UAA@XZ"); + SET(p__non_rtti_object_opequals, "??4__non_rtti_object@std@@QAAAAV01@ABV01@@Z"); + SET(p__non_rtti_object_what, "?what@exception@std@@UBAPBDXZ"); + SET(p__non_rtti_object_vector_dtor, "??_E__non_rtti_object@@UAEPAXI@Z"); + SET(p__non_rtti_object_scalar_dtor, "??_G__non_rtti_object@@UAEPAXI@Z"); + + SET(ptype_info_dtor, "??1type_info@@UAA@XZ"); + SET(ptype_info_raw_name, "?raw_name@type_info@@QBAPBDXZ"); + SET(ptype_info_name, "?name@type_info@@QBEPBDXZ"); + SET(ptype_info_before, "?before@type_info@@QBA_NABV1@@Z"); + SET(ptype_info_opequals_equals, "??8type_info@@QBA_NABV0@@Z"); + SET(ptype_info_opnot_equals, "??9type_info@@QBA_NABV0@@Z"); +#else SETNOFAIL(poperator_new, "??_U@YAPAXI@Z"); SETNOFAIL(poperator_delete, "??_V@YAXPAX@Z"); @@ -285,6 +334,7 @@ static BOOL InitFunctionPtrs(void) SET(ptype_info_before, "?before@type_info@@QBEHABV1@@Z"); SET(ptype_info_opequals_equals, "??8type_info@@QBEHABV0@@Z"); SET(ptype_info_opnot_equals, "??9type_info@@QBEHABV0@@Z"); +#endif /* __arm__ */ } if (!poperator_new) @@ -901,6 +951,12 @@ static void test_rtti(void) { {RTTI_REF(child_class_rtti, base_descriptor[0]), RTTI_REF(child_class_rtti, base_descriptor[1])} }, {0, 0, 2, RTTI_REF(child_class_rtti, base_array)}, {1, 0, 0, RTTI_REF(child_class_rtti, type_info[1]), RTTI_REF(child_class_rtti, object_hierarchy), RTTI_REF(child_class_rtti, object_locator)} + }, virtual_base_class_rtti = { + { {NULL, NULL, "simple_class"}, {NULL, NULL, "child_class"} }, + { {RTTI_REF(virtual_base_class_rtti, type_info[1]), 0, {0x10, sizeof(void*), sizeof(int)}, 0}, {RTTI_REF(virtual_base_class_rtti, type_info[0]), 0, {8, -1, 0}, 0} }, + { {RTTI_REF(virtual_base_class_rtti, base_descriptor[0]), RTTI_REF(virtual_base_class_rtti, base_descriptor[1])} }, + {0, 0, 2, RTTI_REF(virtual_base_class_rtti, base_array)}, + {1, 0, 0, RTTI_REF(virtual_base_class_rtti, type_info[1]), RTTI_REF(virtual_base_class_rtti, object_hierarchy), RTTI_REF(virtual_base_class_rtti, object_locator)} }; static struct rtti_data simple_class_sig0_rtti, child_class_sig0_rtti; @@ -912,6 +968,9 @@ static void test_rtti(void) void *simple_class_sig0 = &simple_class_sig0_vtbl[1]; void *child_class_sig0_vtbl[2] = {&child_class_sig0_rtti.object_locator}; void *child_class_sig0 = &child_class_sig0_vtbl[1]; + void *virtual_base_class_vtbl[2] = {&virtual_base_class_rtti.object_locator}; + int virtual_base_class_vbtbl[2] = {0, 0x100}; + void *virtual_base_class[2] = {&virtual_base_class_vtbl[1], virtual_base_class_vbtbl}; static const char* e_name = "name"; type_info *ti,*bti; @@ -958,7 +1017,7 @@ static void test_rtti(void) call_func1(pexception_dtor, &e); call_func1(pbad_typeid_dtor, &b); - memcpy(&simple_class_sig0_rtti, &simple_class_rtti, sizeof(struct rtti_data)); + simple_class_sig0_rtti = simple_class_rtti; simple_class_sig0_rtti.object_locator.signature = 0; simple_class_sig0_rtti.base_descriptor[0].type_descriptor = RTTI_REF_SIG0(simple_class_sig0_rtti, type_info[0], base); simple_class_sig0_rtti.base_array.bases[0] = RTTI_REF_SIG0(simple_class_sig0_rtti, base_descriptor[0], base); @@ -966,7 +1025,7 @@ static void test_rtti(void) simple_class_sig0_rtti.object_locator.type_descriptor = RTTI_REF_SIG0(simple_class_sig0_rtti, type_info[0], base); simple_class_sig0_rtti.object_locator.type_hierarchy = RTTI_REF_SIG0(simple_class_sig0_rtti, object_hierarchy, base); - memcpy(&child_class_sig0_rtti, &child_class_rtti, sizeof(struct rtti_data)); + child_class_sig0_rtti = child_class_rtti; child_class_sig0_rtti.object_locator.signature = 0; child_class_sig0_rtti.base_descriptor[0].type_descriptor = RTTI_REF_SIG0(child_class_sig0_rtti, type_info[1], base); child_class_sig0_rtti.base_descriptor[1].type_descriptor = RTTI_REF_SIG0(child_class_sig0_rtti, type_info[0], base); @@ -1026,6 +1085,9 @@ static void test_rtti(void) casted = p__RTDynamicCast(&child_class, 0, &child_class_rtti.type_info[0], &child_class_rtti.type_info[1], 0); ok(casted == (char*)&child_class+4, "failed cast to child class (%p %p)\n", casted, &child_class); + + casted = p__RTDynamicCast(&virtual_base_class, 0, &virtual_base_class_rtti.type_info[0], &virtual_base_class_rtti.type_info[1], 0); + ok(casted == (char*)&virtual_base_class+0x110+sizeof(void*), "failed cast to child class (%p %p)\n", casted, &virtual_base_class); } struct _demangle { @@ -1247,7 +1309,20 @@ static void test_demangle(void) /* 122 */ {"?_R2@?BN@???$_Fabs@N@std@@YANAEBV?$complex@N@1@PEAH@Z@4NB", "double const `double __cdecl std::_Fabs(class std::complex const & __ptr64,int * __ptr64)'::`29'::_R2", "?_R2@?BN@???$_Fabs@N@std@@YANAEBV?$complex@N@1@PEAH@Z@4NB"}, - +/* 123 */ {"?vtordisp_thunk@std@@$4PPPPPPPM@3EAA_NXZ", + "[thunk]:public: virtual bool __cdecl std::vtordisp_thunk`vtordisp{4294967292,4}' (void) __ptr64", + "[thunk]:public: virtual bool __cdecl std::vtordisp_thunk`vtordisp{-4,4}' (void) __ptr64"}, +/* 124 */ {"??_9CView@@$BBII@AE", + "[thunk]: __thiscall CView::`vcall'{392,{flat}}' }'", + "[thunk]: __thiscall CView::`vcall'{392,{flat}}' "}, +/* 125 */ {"?_dispatch@_impl_Engine@SalomeApp@@$R4CE@BA@PPPPPPPM@7AE_NAAVomniCallHandle@@@Z", + "[thunk]:public: virtual bool __thiscall SalomeApp::_impl_Engine::_dispatch`vtordispex{36,16,4294967292,8}' (class omniCallHandle &)", + "?_dispatch@_impl_Engine@SalomeApp@@$R4CE@BA@PPPPPPPM@7AE_NAAVomniCallHandle@@@Z"}, +/* 126 */ {"?_Doraise@bad_cast@std@@MEBAXXZ", "protected: virtual void __cdecl std::bad_cast::_Doraise(void)", NULL, 0x60}, +/* 127 */ {"??Xstd@@YAAEAV?$complex@M@0@AEAV10@AEBV10@@Z", "class std::complex & ptr64 cdecl std::operator*=(class std::complex & ptr64,class std::complex const & ptr64)", NULL, 1}, +/* 128 */ {"??Xstd@@YAAEAV?$complex@M@0@AEAV10@AEBV10@@Z", + "class std::complex & std::operator*=(class std::complex &,class std::complex const &)", + "??Xstd@@YAAEAV?$complex@M@0@AEAV10@AEBV10@@Z", 2}, }; int i, num_test = (sizeof(test)/sizeof(test[0])); char* name; diff --git a/rostests/winetests/msvcrt/data.c b/rostests/winetests/msvcrt/data.c index c20be18df3e..efd7d1af1cf 100644 --- a/rostests/winetests/msvcrt/data.c +++ b/rostests/winetests/msvcrt/data.c @@ -30,6 +30,11 @@ #include #include #include +#include + +void __cdecl __getmainargs(int *, char ***, char ***, int, int *); +static int* (__cdecl *p___p___argc)(void); +static char*** (__cdecl *p___p___argv)(void); typedef void (__cdecl *_INITTERMFUN)(void); static void (__cdecl *p_initterm)(_INITTERMFUN *start, _INITTERMFUN *end); @@ -71,7 +76,7 @@ static void test_initterm(void) static void test_initvar( HMODULE hmsvcrt ) { - OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO) }; + OSVERSIONINFOA osvi = { sizeof(OSVERSIONINFOA) }; int *pp_winver = (int*)GetProcAddress(hmsvcrt, "_winver"); int *pp_winmajor = (int*)GetProcAddress(hmsvcrt, "_winmajor"); int *pp_winminor = (int*)GetProcAddress(hmsvcrt, "_winminor"); @@ -86,7 +91,7 @@ static void test_initvar( HMODULE hmsvcrt ) winver = *pp_winver; winminor = *pp_winminor; winmajor = *pp_winmajor; - GetVersionEx( &osvi); + GetVersionExA( &osvi); ok( winminor == osvi.dwMinorVersion, "Wrong value for _winminor %02x expected %02x\n", winminor, osvi.dwMinorVersion); ok( winmajor == osvi.dwMajorVersion, "Wrong value for _winmajor %02x expected %02x\n", @@ -124,9 +129,110 @@ static void test_get_pgmptr(void) ok( pgm != NULL, "_get_pgmptr returned a NULL pointer\n" ); } +static void test___getmainargs(void) +{ + int argc, new_argc, mode; + char **argv, **new_argv, **envp; + char tmppath[MAX_PATH], filepath[MAX_PATH]; + FILE *f; + + ok(GetTempPathA(MAX_PATH, tmppath) != 0, "GetTempPath failed\n"); + + mode = 0; + __getmainargs(&argc, &argv, &envp, 0, &mode); + ok(argc == 4, "argc = %d\n", argc); + ok(!strcmp(argv[1], "data"), "argv[1] = %s\n", argv[1]); + sprintf(filepath, "%s*\\*", tmppath); + ok(!strcmp(argv[2], filepath), "argv[2] = %s\n", argv[2]); + sprintf(filepath, "%swine_test/*", tmppath); + ok(!strcmp(argv[3], filepath), "argv[3] = %s\n", argv[3]); + ok(!argv[4], "argv[4] != NULL\n"); + + if(p___p___argc && p___p___argv) { + new_argc = *p___p___argc(); + new_argv = *p___p___argv(); + ok(new_argc == 4, "*__p___argc() = %d\n", new_argc); + ok(new_argv == argv, "*__p___argv() = %p, epxected %p\n", new_argv, argv); + }else { + win_skip("__p___argc or __p___argv is not available\n"); + } + + mode = 0; + __getmainargs(&argc, &argv, &envp, 1, &mode); + ok(argc == 5, "argc = %d\n", argc); + ok(!strcmp(argv[1], "data"), "argv[1] = %s\n", argv[1]); + sprintf(filepath, "%s*\\*", tmppath); + ok(!strcmp(argv[2], filepath), "argv[2] = %s\n", argv[2]); + sprintf(filepath, "%swine_test/a", tmppath); + if(argv[3][strlen(argv[3])-1] == 'a') { + ok(!strcmp(argv[3], filepath), "argv[3] = %s\n", argv[3]); + sprintf(filepath, "%swine_test/test", tmppath); + ok(!strcmp(argv[4], filepath), "argv[4] = %s\n", argv[4]); + }else { + ok(!strcmp(argv[4], filepath), "argv[4] = %s\n", argv[4]); + sprintf(filepath, "%swine_test/test", tmppath); + ok(!strcmp(argv[3], filepath), "argv[3] = %s\n", argv[3]); + } + ok(!argv[5], "argv[5] != NULL\n"); + + if(p___p___argc && p___p___argv) { + new_argc = *p___p___argc(); + new_argv = *p___p___argv(); + ok(new_argc == argc, "*__p___argc() = %d, expected %d\n", new_argc, argc); + ok(new_argv == argv, "*__p___argv() = %p, epxected %p\n", new_argv, argv); + } + + sprintf(filepath, "%swine_test/b", tmppath); + f = fopen(filepath, "w"); + ok(f != NULL, "fopen(%s) failed: %d\n", filepath, errno); + fclose(f); + mode = 0; + __getmainargs(&new_argc, &new_argv, &envp, 1, &mode); + ok(new_argc == argc+1, "new_argc = %d, expected %d\n", new_argc, argc+1); + _unlink(filepath); +} + +static void test___getmainargs_parent(char *name) +{ + char cmdline[3*MAX_PATH]; + char tmppath[MAX_PATH], filepath[MAX_PATH]; + STARTUPINFOA startup; + PROCESS_INFORMATION proc; + FILE *f; + int ret; + + ok(GetTempPathA(MAX_PATH, tmppath) != 0, "GetTempPath failed\n"); + sprintf(cmdline, "%s data %s*\\* %swine_test/*", name, tmppath, tmppath); + + sprintf(filepath, "%swine_test", tmppath); + ret = _mkdir(filepath); + ok(!ret, "_mkdir failed: %d\n", errno); + sprintf(filepath, "%swine_test\\a", tmppath); + f = fopen(filepath, "w"); + ok(f != NULL, "fopen(%s) failed: %d\n", filepath, errno); + fclose(f); + sprintf(filepath, "%swine_test\\test", tmppath); + f = fopen(filepath, "w"); + ok(f != NULL, "fopen(%s) failed: %d\n", filepath, errno); + fclose(f); + + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS, NULL, NULL, &startup, &proc); + winetest_wait_child_process(proc.hProcess); + + _unlink(filepath); + sprintf(filepath, "%swine_test\\a", tmppath); + _unlink(filepath); + sprintf(filepath, "%swine_test", tmppath); + _rmdir(filepath); +} + START_TEST(data) { HMODULE hmsvcrt; + int arg_c; + char** arg_v; hmsvcrt = GetModuleHandleA("msvcrt.dll"); if (!hmsvcrt) @@ -135,8 +241,18 @@ START_TEST(data) { p_initterm=(void*)GetProcAddress(hmsvcrt, "_initterm"); p_get_pgmptr=(void*)GetProcAddress(hmsvcrt, "_get_pgmptr"); + p___p___argc=(void*)GetProcAddress(hmsvcrt, "__p___argc"); + p___p___argv=(void*)GetProcAddress(hmsvcrt, "__p___argv"); } + + arg_c = winetest_get_mainargs(&arg_v); + if(arg_c >= 3) { + test___getmainargs(); + return; + } + test_initterm(); test_initvar(hmsvcrt); test_get_pgmptr(); + test___getmainargs_parent(arg_v[0]); } diff --git a/rostests/winetests/msvcrt/dir.c b/rostests/winetests/msvcrt/dir.c index 83c533b5e52..aa273ea85e0 100644 --- a/rostests/winetests/msvcrt/dir.c +++ b/rostests/winetests/msvcrt/dir.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -345,28 +346,28 @@ static void test_fullpath(void) BOOL rc,free1,free2; free1=free2=TRUE; - GetCurrentDirectory(MAX_PATH, prevpath); - GetTempPath(MAX_PATH,tmppath); + GetCurrentDirectoryA(MAX_PATH, prevpath); + GetTempPathA(MAX_PATH,tmppath); strcpy(level1,tmppath); strcat(level1,"msvcrt-test\\"); - rc = CreateDirectory(level1,NULL); + rc = CreateDirectoryA(level1,NULL); if (!rc && GetLastError()==ERROR_ALREADY_EXISTS) free1=FALSE; strcpy(level2,level1); strcat(level2,"nextlevel\\"); - rc = CreateDirectory(level2,NULL); + rc = CreateDirectoryA(level2,NULL); if (!rc && GetLastError()==ERROR_ALREADY_EXISTS) free2=FALSE; - SetCurrentDirectory(level2); + SetCurrentDirectoryA(level2); ok(_fullpath(full,"test", MAX_PATH)!=NULL,"_fullpath failed\n"); strcpy(teststring,level2); strcat(teststring,"test"); ok(strcmp(full,teststring)==0,"Invalid Path returned %s\n",full); ok(_fullpath(full,"\\test", MAX_PATH)!=NULL,"_fullpath failed\n"); - strncpy(teststring,level2,3); + memcpy(teststring,level2,3); teststring[3]=0; strcat(teststring,"test"); ok(strcmp(full,teststring)==0,"Invalid Path returned %s\n",full); @@ -383,11 +384,36 @@ static void test_fullpath(void) ok(strcmp(freeme,teststring)==0,"Invalid Path returned %s\n",freeme); free(freeme); - SetCurrentDirectory(prevpath); + SetCurrentDirectoryA(prevpath); if (free2) - RemoveDirectory(level2); + RemoveDirectoryA(level2); if (free1) - RemoveDirectory(level1); + RemoveDirectoryA(level1); +} + +static void test_splitpath(void) +{ + const char* path = "c:\\\x83\x5c\x83\x74\x83\x67.bin"; + char drive[3], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH]; + int prev_cp = _getmbcp(); + + /* SBCS codepage */ + _setmbcp(1252); + _splitpath(path, drive, dir, fname, ext); + ok(!strcmp(drive, "c:"), "got %s\n", drive); + ok(!strcmp(dir, "\\\x83\x5c"), "got %s\n", dir); + ok(!strcmp(fname, "\x83\x74\x83\x67"), "got %s\n", fname); + ok(!strcmp(ext, ".bin"), "got %s\n", ext); + + /* MBCS (Japanese) codepage */ + _setmbcp(932); + _splitpath(path, drive, dir, fname, ext); + ok(!strcmp(drive, "c:"), "got %s\n", drive); + ok(!strcmp(dir, "\\"), "got %s\n", dir); + ok(!strcmp(fname, "\x83\x5c\x83\x74\x83\x67"), "got %s\n", fname); + ok(!strcmp(ext, ".bin"), "got %s\n", ext); + + _setmbcp(prev_cp); } START_TEST(dir) @@ -397,4 +423,5 @@ START_TEST(dir) test_fullpath(); test_makepath(); test_makepath_s(); + test_splitpath(); } diff --git a/rostests/winetests/msvcrt/file.c b/rostests/winetests/msvcrt/file.c index e450b725147..f6a1624d820 100644 --- a/rostests/winetests/msvcrt/file.c +++ b/rostests/winetests/msvcrt/file.c @@ -33,18 +33,44 @@ #include #include #include +#include + +#define MSVCRT_FD_BLOCK_SIZE 32 +typedef struct { + HANDLE handle; + unsigned char wxflag; + char lookahead[3]; + int exflag; + CRITICAL_SECTION crit; +} ioinfo; +static ioinfo **__pioinfo; static HANDLE proc_handles[2]; static int (__cdecl *p_fopen_s)(FILE**, const char*, const char*); static int (__cdecl *p__wfopen_s)(FILE**, const wchar_t*, const wchar_t*); +static const char* get_base_name(const char *path) +{ + const char *ret = path+strlen(path)-1; + + while(ret >= path) { + if(*ret=='\\' || *ret=='/') + break; + ret--; + } + return ret+1; +} + static void init(void) { HMODULE hmod = GetModuleHandleA("msvcrt.dll"); + setlocale(LC_CTYPE, "C"); + p_fopen_s = (void*)GetProcAddress(hmod, "fopen_s"); p__wfopen_s = (void*)GetProcAddress(hmod, "_wfopen_s"); + __pioinfo = (void*)GetProcAddress(hmod, "__pioinfo"); } static void test_filbuf( void ) @@ -443,11 +469,11 @@ static void test_filemodeT(void) FILE* f; size_t bytesWritten; size_t bytesRead; - WIN32_FIND_DATA findData; + WIN32_FIND_DATAA findData; HANDLE h; - GetTempPath (MAX_PATH, temppath); - GetTempFileName (temppath, "", 0, tempfile); + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); f = fopen(tempfile, "w+bDT"); bytesWritten = fwrite(DATA, 1, sizeof(DATA), f); @@ -458,7 +484,7 @@ static void test_filemodeT(void) ok (bytesRead == bytesWritten && bytesRead == sizeof(DATA), "fopen file mode 'T' wrongly interpreted as 't'\n" ); - h = FindFirstFile(tempfile, &findData); + h = FindFirstFileA(tempfile, &findData); ok (h == INVALID_HANDLE_VALUE, "file wasn't deleted when closed.\n" ); @@ -708,7 +734,7 @@ static void test_fgetwc( void ) ok(l==BUFSIZ-2, "ftell expected %d got %d\n", BUFSIZ-2, l); fgetws(wtextW,LLEN,tempfh); l=ftell(tempfh); - ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %d\n", BUFSIZ-2+lstrlen(mytext), l); + ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %d\n", BUFSIZ-2+lstrlenA(mytext), l); mytextW = AtoW (mytext); aptr = mytextW; wptr = wtextW; @@ -792,6 +818,190 @@ static void test_fgetwc( void ) free(tempf); } +static void test_fgetwc_locale(const char* text, const char* locale, int codepage) +{ + char temppath[MAX_PATH], tempfile[MAX_PATH]; + FILE *tempfh; + static const WCHAR wchar_text[] = { 0xfeff, 0xff1f, '!' }; + WCHAR wtextW[BUFSIZ]; + int ret = 0, i; + wint_t ch; + + if (!setlocale(LC_CTYPE, locale)) + { + win_skip("%s locale not available\n", locale); + return; + } + + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); + + tempfh = fopen(tempfile, "wb"); + ok(tempfh != NULL, "can't open tempfile\n"); + fwrite(text, 1, strlen(text), tempfh); + fclose(tempfh); + + if (codepage != 0) + { + /* mbstowcs rejects invalid multibyte sequence, + so we use MultiByteToWideChar here. */ + ret = MultiByteToWideChar(codepage, 0, text, -1, + wtextW, sizeof(wtextW)/sizeof(wtextW[0])); + ok(ret > 0, "MultiByteToWideChar failed\n"); + } + else + { + /* C locale */ + const char *p; + for (p = text; *p != '\0'; p++) + wtextW[ret++] = (unsigned char)*p; + wtextW[ret++] = 0; + } + + tempfh = fopen(tempfile, "rt"); + ok(tempfh != NULL, "can't open tempfile\n"); + + for (i = 0; i < ret-1; i++) + { + ch = fgetwc(tempfh); + ok(ch == wtextW[i], "got %04hx, expected %04hx (cp%d[%d])\n", ch, wtextW[i], codepage, i); + } + ch = fgetwc(tempfh); + ok(ch == WEOF, "got %04hx, expected WEOF (cp%d)\n", ch, codepage); + fclose(tempfh); + + tempfh = fopen(tempfile, "wb"); + ok(tempfh != NULL, "can't open tempfile\n"); + fwrite(wchar_text, 1, sizeof(wchar_text), tempfh); + fclose(tempfh); + + tempfh = fopen(tempfile, "rb"); + ok(tempfh != NULL, "can't open tempfile\n"); + for (i = 0; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++) + { + ch = fgetwc(tempfh); + ok(ch == wchar_text[i], "got %04hx, expected %04x (cp%d[%d])\n", ch, wchar_text[i], codepage, i); + } + ch = fgetwc(tempfh); + ok(ch == WEOF, "got %04hx, expected WEOF (cp%d)\n", ch, codepage); + fclose(tempfh); + unlink(tempfile); +} + +static void test_fgetwc_unicode(void) +{ + char temppath[MAX_PATH], tempfile[MAX_PATH]; + FILE *tempfh; + static const WCHAR wchar_text[] = { 0xfeff, 0xff1f, '!' }; + char utf8_text[BUFSIZ]; + int ret, i; + wint_t ch; + + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); + + if (!p_fopen_s) + { + win_skip("fopen_s not available\n"); + return; + } + + tempfh = fopen(tempfile, "wb"); + ok(tempfh != NULL, "can't open tempfile\n"); + fwrite(wchar_text, 1, sizeof(wchar_text), tempfh); + fclose(tempfh); + + tempfh = fopen(tempfile, "rt,ccs=unicode"); + ok(tempfh != NULL, "can't open tempfile\n"); + for (i = 1; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++) + { + ch = fgetwc(tempfh); + ok(ch == wchar_text[i], + "got %04hx, expected %04x (unicode[%d])\n", ch, wchar_text[i], i-1); + } + ch = fgetwc(tempfh); + ok(ch == WEOF, "got %04hx, expected WEOF (unicode)\n", ch); + fclose(tempfh); + + tempfh = fopen(tempfile, "wb"); + ok(tempfh != NULL, "can't open tempfile\n"); + ret = WideCharToMultiByte(CP_UTF8, 0, wchar_text, sizeof(wchar_text)/sizeof(wchar_text[0]), + utf8_text, sizeof(utf8_text), NULL, NULL); + ok(ret > 0, "utf-8 conversion failed\n"); + fwrite(utf8_text, sizeof(char), ret, tempfh); + fclose(tempfh); + + tempfh = fopen(tempfile, "rt, ccs=UTF-8"); + ok(tempfh != NULL, "can't open tempfile\n"); + for (i = 1; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++) + { + ch = fgetwc(tempfh); + ok(ch == wchar_text[i], + "got %04hx, expected %04x (utf8[%d])\n", ch, wchar_text[i], i-1); + } + ch = fgetwc(tempfh); + ok(ch == WEOF, "got %04hx, expected WEOF (utf8)\n", ch); + fclose(tempfh); + unlink(temppath); +} + +static void test_fputwc(void) +{ + char temppath[MAX_PATH]; + char tempfile[MAX_PATH]; + FILE *f; + char buf[1024]; + int ret; + + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); + + f = fopen(tempfile, "w"); + ret = fputwc('a', f); + ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret); + ret = fputwc('\n', f); + ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret); + fclose(f); + + f = fopen(tempfile, "rb"); + ret = fread(buf, 1, sizeof(buf), f); + ok(ret == 3, "fread returned %d, expected 3\n", ret); + ok(!memcmp(buf, "a\r\n", 3), "incorrect file data\n"); + fclose(f); + + if(p_fopen_s) { + f = fopen(tempfile, "w,ccs=unicode"); + ret = fputwc('a', f); + ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret); + ret = fputwc('\n', f); + ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret); + fclose(f); + + f = fopen(tempfile, "rb"); + ret = fread(buf, 1, sizeof(buf), f); + ok(ret == 8, "fread returned %d, expected 8\n", ret); + ok(!memcmp(buf, "\xff\xfe\x61\x00\r\x00\n\x00", 8), "incorrect file data\n"); + fclose(f); + + f = fopen(tempfile, "w,ccs=utf-8"); + ret = fputwc('a', f); + ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret); + ret = fputwc('\n', f); + ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret); + fclose(f); + + f = fopen(tempfile, "rb"); + ret = fread(buf, 1, sizeof(buf), f); + ok(ret == 6, "fread returned %d, expected 6\n", ret); + ok(!memcmp(buf, "\xef\xbb\xbf\x61\r\n", 6), "incorrect file data\n"); + fclose(f); + }else { + win_skip("fputwc tests on unicode files\n"); + } + + _unlink(tempfile); +} + static void test_ctrlz( void ) { char* tempf; @@ -956,6 +1166,11 @@ static void test_file_write_read( void ) _lseek(tempfd, -2, FILE_END); ret = _read(tempfd,btext,LLEN); ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret); + _lseek(tempfd, -2, FILE_END); + ret = _read(tempfd,btext,1); + ok(ret == 1 && *btext == '\n', "_read returned %d, buf: %d\n", ret, *btext); + ret = read(tempfd,btext,1); + ok(ret == 0, "_read returned %d, expected 0\n", ret); _lseek(tempfd, -3, FILE_END); ret = _read(tempfd,btext,1); ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret); @@ -975,7 +1190,7 @@ static void test_file_write_read( void ) free(tempf); tempf=_tempnam(".","wne"); - tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0); + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR, _S_IWRITE); ok( tempfd != -1, "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */ ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext), @@ -1011,6 +1226,95 @@ static void test_file_write_read( void ) ok(i == strlen(mytext)-1, "_read_i %d\n", i); _close(tempfd); + /* test read/write in unicode mode */ + if(p_fopen_s) + { + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _write(tempfd, "a", 1); + ok(ret == -1, "_write returned %d, expected -1\n", ret); + ret = _write(tempfd, "a\x00\n\x00\xff\xff", 6); + ok(ret == 6, "_write returned %d, expected 6\n", ret); + _close(tempfd); + + tempfd = _open(tempf, _O_RDONLY|_O_BINARY, 0); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _read(tempfd, btext, sizeof(btext)); + ok(ret == 10, "_read returned %d, expected 10\n", ret); + ok(!memcmp(btext, "\xff\xfe\x61\x00\r\x00\n\x00\xff\xff", 10), "btext is incorrect\n"); + _close(tempfd); + + tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + errno = 0xdeadbeef; + ret = _read(tempfd, btext, 3); + ok(ret == -1, "_read returned %d, expected -1\n", ret); + ok(errno == 22, "errno = %d\n", errno); + ret = _read(tempfd, btext, sizeof(btext)); + ok(ret == 6, "_read returned %d, expected 6\n", ret); + ok(!memcmp(btext, "\x61\x00\n\x00\xff\xff", 6), "btext is incorrect\n"); + _close(tempfd); + + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_U8TEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + errno = 0xdeadbeef; + ret = _write(tempfd, "a", 1); + ok(ret == -1, "_write returned %d, expected -1\n", ret); + ok(errno == 22, "errno = %d\n", errno); + ret = _write(tempfd, "a\x00\n\x00\x62\x00", 6); + ok(ret == 6, "_write returned %d, expected 6\n", ret); + _close(tempfd); + + tempfd = _open(tempf, _O_RDONLY|_O_BINARY, 0); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _read(tempfd, btext, sizeof(btext)); + ok(ret == 7, "_read returned %d, expected 7\n", ret); + ok(!memcmp(btext, "\xef\xbb\xbf\x61\r\n\x62", 7), "btext is incorrect\n"); + _close(tempfd); + + tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _read(tempfd, btext, sizeof(btext)); + ok(ret == 6, "_read returned %d, expected 6\n", ret); + ok(!memcmp(btext, "\x61\x00\n\x00\x62\x00", 6), "btext is incorrect\n"); + + /* when buffer is small read sometimes fails in native implementation */ + lseek(tempfd, 3 /* skip bom */, SEEK_SET); + ret = _read(tempfd, btext, 4); + todo_wine ok(ret == -1, "_read returned %d, expected -1\n", ret); + + lseek(tempfd, 6, SEEK_SET); + ret = _read(tempfd, btext, 2); + ok(ret == 2, "_read returned %d, expected 2\n", ret); + ok(!memcmp(btext, "\x62\x00", 2), "btext is incorrect\n"); + _close(tempfd); + + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _write(tempfd, "\xef\xbb\xbf\x61\xc4\x85\x62\xc5\xbc\r\r\n", 12); + ok(ret == 12, "_write returned %d, expected 9\n", ret); + _close(tempfd); + + tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + ret = _read(tempfd, btext, sizeof(btext)); + ok(ret == 12, "_read returned %d, expected 12\n", ret); + ok(!memcmp(btext, "\x61\x00\x05\x01\x62\x00\x7c\x01\x0d\x00\x0a\x00", 12), "btext is incorrect\n"); + + /* test invalid utf8 sequence */ + lseek(tempfd, 5, SEEK_SET); + ret = _read(tempfd, btext, sizeof(btext)); + todo_wine ok(ret == 10, "_read returned %d, expected 10\n", ret); + /* invalid char should be replaced by U+FFFD in MultiByteToWideChar */ + todo_wine ok(!memcmp(btext, "\xfd\xff", 2), "invalid UTF8 character was not replaced by U+FFFD\n"); + ok(!memcmp(btext+ret-8, "\x62\x00\x7c\x01\x0d\x00\x0a\x00", 8), "btext is incorrect\n"); + _close(tempfd); + } + else + { + win_skip("unicode mode tests on file\n"); + } + ret =_chmod (tempf, _S_IREAD | _S_IWRITE); ok( ret == 0, "Can't chmod '%s' to read-write: %d\n", tempf, errno); @@ -1042,7 +1346,7 @@ static void test_file_inherit_child_no(const char* fd_s) "Wrong write result in child process on %d (%s)\n", fd, strerror(errno)); } -static void create_io_inherit_block( STARTUPINFO *startup, unsigned int count, const HANDLE *handles ) +static void create_io_inherit_block( STARTUPINFOA *startup, unsigned int count, const HANDLE *handles ) { static BYTE block[1024]; BYTE *wxflag_ptr; @@ -1072,7 +1376,7 @@ static const char *read_file( HANDLE file ) return buffer; } -static void test_stdout_handle( STARTUPINFO *startup, char *cmdline, HANDLE hstdout, BOOL expect_stdout, +static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hstdout, BOOL expect_stdout, const char *descr ) { const char *data; @@ -1112,7 +1416,7 @@ static void test_stdout_handle( STARTUPINFO *startup, char *cmdline, HANDLE hstd } CloseHandle( hErrorFile ); - DeleteFile( "fdopen.err" ); + DeleteFileA( "fdopen.err" ); } static void test_file_inherit( const char* selfname ) @@ -1121,13 +1425,13 @@ static void test_file_inherit( const char* selfname ) const char* arg_v[5]; char buffer[16]; char cmdline[MAX_PATH]; - STARTUPINFO startup; + STARTUPINFOA startup; SECURITY_ATTRIBUTES sa; HANDLE handles[3]; fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE); ok(fd != -1, "Couldn't create test file\n"); - arg_v[0] = selfname; + arg_v[0] = get_base_name(selfname); arg_v[1] = "tests/file.c"; arg_v[2] = "inherit"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); @@ -1141,7 +1445,6 @@ static void test_file_inherit( const char* selfname ) fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE); ok(fd != -1, "Couldn't create test file\n"); - arg_v[0] = selfname; arg_v[1] = "tests/file.c"; arg_v[2] = "inherit_no"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); @@ -1159,7 +1462,7 @@ static void test_file_inherit( const char* selfname ) sprintf(cmdline, "%s file inherit 1", selfname); /* init an empty Reserved2, which should not be recognized as inherit-block */ - ZeroMemory(&startup, sizeof(STARTUPINFO)); + ZeroMemory(&startup, sizeof(startup)); startup.cb = sizeof(startup); create_io_inherit_block( &startup, 0, NULL ); test_stdout_handle( &startup, cmdline, 0, FALSE, "empty block" ); @@ -1172,7 +1475,7 @@ static void test_file_inherit( const char* selfname ) create_io_inherit_block( &startup, 3, handles ); test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid block" ); CloseHandle( handles[1] ); - DeleteFile("fdopen.tst"); + DeleteFileA("fdopen.tst"); /* test inherit block starting with unsigned zero */ handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, @@ -1181,7 +1484,7 @@ static void test_file_inherit( const char* selfname ) *(unsigned int *)startup.lpReserved2 = 0; test_stdout_handle( &startup, cmdline, handles[1], FALSE, "zero count block" ); CloseHandle( handles[1] ); - DeleteFile("fdopen.tst"); + DeleteFileA("fdopen.tst"); /* test inherit block with smaller size */ handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, @@ -1190,7 +1493,7 @@ static void test_file_inherit( const char* selfname ) startup.cbReserved2 -= 3; test_stdout_handle( &startup, cmdline, handles[1], TRUE, "small size block" ); CloseHandle( handles[1] ); - DeleteFile("fdopen.tst"); + DeleteFileA("fdopen.tst"); /* test inherit block with even smaller size */ handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, @@ -1199,7 +1502,7 @@ static void test_file_inherit( const char* selfname ) startup.cbReserved2 = sizeof(unsigned int) + sizeof(HANDLE) + sizeof(char); test_stdout_handle( &startup, cmdline, handles[1], FALSE, "smaller size block" ); CloseHandle( handles[1] ); - DeleteFile("fdopen.tst"); + DeleteFileA("fdopen.tst"); /* test inherit block with larger size */ handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, @@ -1208,7 +1511,7 @@ static void test_file_inherit( const char* selfname ) startup.cbReserved2 += 7; test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block" ); CloseHandle( handles[1] ); - DeleteFile("fdopen.tst"); + DeleteFileA("fdopen.tst"); } static void test_tmpnam( void ) @@ -1320,6 +1623,7 @@ static void test_fopen_s( void ) { const char name[] = "empty1"; char buff[16]; + unsigned char *ubuff = (unsigned char*)buff; FILE *file; int ret; int len; @@ -1348,6 +1652,69 @@ static void test_fopen_s( void ) ret = fclose(file); ok(ret != EOF, "File failed to close\n"); + ret = p_fopen_s(&file, name, "w, ccs=UNIcode"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + ret = fwrite("a", 1, 2, file); + ok(ret == 2, "fwrite returned %d\n", ret); + fclose(file); + + ret = p_fopen_s(&file, name, "r"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 2, file); + ok(len == 2, "len = %d\n", len); + ok(ubuff[0]==0xff && ubuff[1]==0xfe, "buff[0]=%02x, buff[1]=%02x\n", + ubuff[0], ubuff[1]); + fclose(file); + + ret = p_fopen_s(&file, name, "r,ccs=unicode"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 2, file); + ok(len == 2, "len = %d\n", len); + ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n", + ubuff[0], ubuff[1]); + fclose(file); + + ret = p_fopen_s(&file, name, "r,ccs=utf-16le"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 2, file); + ok(len == 2, "len = %d\n", len); + ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n", + ubuff[0], ubuff[1]); + fclose(file); + + ret = p_fopen_s(&file, name, "r,ccs=utf-8"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 2, file); + ok(len == 2, "len = %d\n", len); + ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n", + ubuff[0], ubuff[1]); + fclose(file); + + ret = p_fopen_s(&file, name, "w,ccs=utf-16le"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + fclose(file); + + ret = p_fopen_s(&file, name, "r"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 3, file); + ok(len == 2, "len = %d\n", len); + ok(ubuff[0]==0xff && ubuff[1]==0xfe, "buff[0]=%02x, buff[1]=%02x\n", + ubuff[0], ubuff[1]); + fclose(file); + + ret = p_fopen_s(&file, name, "w,ccs=utf-8"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + fclose(file); + + ret = p_fopen_s(&file, name, "r"); + ok(ret == 0, "fopen_s failed with %d\n", ret); + len = fread(buff, 1, 4, file); + ok(len == 3, "len = %d\n", len); + ok(ubuff[0]==0xef && ubuff[1]==0xbb && ubuff[2]==0xbf, + "buff[0]=%02x, buff[1]=%02x, buff[2]=%02x\n", + ubuff[0], ubuff[1], ubuff[2]); + fclose(file); + ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name); } @@ -1392,6 +1759,61 @@ static void test__wfopen_s( void ) ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name); } +static void test_setmode(void) +{ + const char name[] = "empty1"; + int fd, ret; + + if(!p_fopen_s) { + win_skip("unicode file modes are not available, skipping setmode tests\n"); + return; + } + + fd = _open(name, _O_CREAT|_O_WRONLY, _S_IWRITE); + ok(fd != -1, "failed to open file\n"); + + errno = 0xdeadbeef; + ret = _setmode(fd, 0xffffffff); + ok(ret == -1, "_setmode returned %x, expected -1\n", ret); + ok(errno == EINVAL, "errno = %d\n", errno); + + errno = 0xdeadbeef; + ret = _setmode(fd, 0); + ok(ret == -1, "_setmode returned %x, expected -1\n", ret); + ok(errno == EINVAL, "errno = %d\n", errno); + + errno = 0xdeadbeef; + ret = _setmode(fd, _O_BINARY|_O_TEXT); + ok(ret == -1, "_setmode returned %x, expected -1\n", ret); + ok(errno == EINVAL, "errno = %d\n", errno); + + errno = 0xdeadbeef; + ret = _setmode(fd, _O_WTEXT|_O_U16TEXT); + ok(ret == -1, "_setmode returned %x, expected -1\n", ret); + ok(errno == EINVAL, "errno = %d\n", errno); + + ret = _setmode(fd, _O_BINARY); + ok(ret == _O_TEXT, "_setmode returned %x, expected _O_TEXT\n", ret); + + ret = _setmode(fd, _O_WTEXT); + ok(ret == _O_BINARY, "_setmode returned %x, expected _O_BINARY\n", ret); + + ret = _setmode(fd, _O_TEXT); + ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret); + + ret = _setmode(fd, _O_U16TEXT); + ok(ret == _O_TEXT, "_setmode returned %x, expected _O_TEXT\n", ret); + + ret = _setmode(fd, _O_U8TEXT); + ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret); + + ret = _setmode(fd, _O_TEXT); + ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret); + + _close(fd); + _unlink(name); +} + static void test_get_osfhandle(void) { int fd; @@ -1444,6 +1866,11 @@ static void test_stat(void) ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size); + errno = 0xdeadbeef; + ret = stat("stat.tst\\", &buf); + ok(ret == -1, "stat returned %d\n", ret); + ok(errno == ENOENT, "errno = %d\n", errno); + close(fd); remove("stat.tst"); } @@ -1483,6 +1910,35 @@ static void test_stat(void) } else skip("pipe failed with errno %d\n", errno); + + /* Tests for directory */ + if(mkdir("stat.tst") == 0) + { + ret = stat("stat.tst ", &buf); + ok(!ret, "stat(directory) failed: errno=%d\n", errno); + ok((buf.st_mode & _S_IFMT) == _S_IFDIR, "bad format = %06o\n", buf.st_mode); + ok((buf.st_mode & 0777) == 0777, "bad st_mode = %06o\n", buf.st_mode); + ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); + + errno = 0xdeadbeef; + ret = stat("stat.tst\\ ", &buf); + ok(ret == -1, "stat returned %d\n", ret); + ok(errno == ENOENT, "errno = %d\n", errno); + rmdir( "stat.tst" ); + } + else + skip("mkdir failed with errno %d\n", errno); + + errno = 0xdeadbeef; + ret = stat("c:", &buf); + ok(ret == -1, "stat returned %d\n", ret); + ok(errno == ENOENT, "errno = %d\n", errno); + + ret = stat("c:/", &buf); + ok(!ret, "stat returned %d\n", ret); + ok(buf.st_dev == 2, "st_dev = %d\n", buf.st_dev); + ok(buf.st_rdev == 2, "st_rdev = %d\n", buf.st_rdev); } static const char* pipe_string="Hello world"; @@ -1538,7 +1994,7 @@ static void test_pipes(const char* selfname) return; } - arg_v[0] = selfname; + arg_v[0] = get_base_name(selfname); arg_v[1] = "tests/file.c"; arg_v[2] = "pipes"; arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]); @@ -1568,7 +2024,6 @@ static void test_pipes(const char* selfname) return; } - arg_v[0] = selfname; arg_v[1] = "tests/file.c"; arg_v[2] = "pipes"; arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]); @@ -1601,6 +2056,56 @@ static void test_pipes(const char* selfname) i=fclose(file); ok(!i, "unable to close the pipe: %d\n", errno); + + /* test \r handling when it's the last character read */ + if (_pipe(pipes, 1024, O_BINARY) < 0) + { + ok(0, "pipe failed with errno %d\n", errno); + return; + } + r = write(pipes[1], "\r\n\rab\r\n", 7); + ok(r == 7, "write returned %d, errno = %d\n", r, errno); + setmode(pipes[0], O_TEXT); + r = read(pipes[0], buf, 1); + ok(r == 1, "read returned %d, expected 1\n", r); + ok(buf[0] == '\n', "buf[0] = %x, expected '\\n'\n", buf[0]); + r = read(pipes[0], buf, 1); + ok(r == 1, "read returned %d, expected 1\n", r); + ok(buf[0] == '\r', "buf[0] = %x, expected '\\r'\n", buf[0]); + r = read(pipes[0], buf, 1); + ok(r == 1, "read returned %d, expected 1\n", r); + ok(buf[0] == 'a', "buf[0] = %x, expected 'a'\n", buf[0]); + r = read(pipes[0], buf, 2); + ok(r == 2, "read returned %d, expected 1\n", r); + ok(buf[0] == 'b', "buf[0] = %x, expected 'b'\n", buf[0]); + ok(buf[1] == '\n', "buf[1] = %x, expected '\\n'\n", buf[1]); + + if (p_fopen_s) + { + /* test utf16 read with insufficient data */ + r = write(pipes[1], "a\0b", 3); + ok(r == 3, "write returned %d, errno = %d\n", r, errno); + buf[2] = 'z'; + buf[3] = 'z'; + setmode(pipes[0], _O_WTEXT); + r = read(pipes[0], buf, 4); + ok(r == 2, "read returned %d, expected 2\n", r); + ok(!memcmp(buf, "a\0bz", 4), "read returned incorrect data\n"); + r = write(pipes[1], "\0", 1); + ok(r == 1, "write returned %d, errno = %d\n", r, errno); + buf[0] = 'z'; + buf[1] = 'z'; + r = read(pipes[0], buf, 2); + ok(r == 0, "read returned %d, expected 0\n", r); + ok(!memcmp(buf, "\0z", 2), "read returned incorrect data\n"); + } + else + { + win_skip("unicode mode tests on pipe\n"); + } + + close(pipes[1]); + close(pipes[0]); } static void test_unlink(void) @@ -1621,6 +2126,99 @@ static void test_dup2(void) ok(-1 == _dup2(0, -1), "expected _dup2 to fail when second arg is negative\n" ); } +static void test_stdin(void) +{ + HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE); + int stdin_dup, fd; + HANDLE h; + DWORD r; + + stdin_dup = _dup(STDIN_FILENO); + ok(stdin_dup != -1, "_dup(STDIN_FILENO) failed\n"); + + ok(stdinh == (HANDLE)_get_osfhandle(STDIN_FILENO), + "GetStdHandle(STD_INPUT_HANDLE) != _get_osfhandle(STDIN_FILENO)\n"); + + r = SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE); + ok(r == TRUE, "SetStdHandle returned %x, expected TRUE\n", r); + h = GetStdHandle(STD_INPUT_HANDLE); + ok(h == INVALID_HANDLE_VALUE, "h = %p\n", h); + + close(STDIN_FILENO); + h = GetStdHandle(STD_INPUT_HANDLE); + ok(h == NULL, "h != NULL\n"); + + fd = open("stdin.tst", O_WRONLY | O_CREAT, _S_IREAD |_S_IWRITE); + ok(fd != -1, "open failed\n"); + ok(fd == STDIN_FILENO, "fd = %d, expected STDIN_FILENO\n", fd); + h = GetStdHandle(STD_INPUT_HANDLE); + ok(h != NULL, "h == NULL\n"); + close(fd); + unlink("stdin.tst"); + + r = _dup2(stdin_dup, STDIN_FILENO); + ok(r != -1, "_dup2 failed\n"); + h = GetStdHandle(STD_INPUT_HANDLE); + ok(h != NULL, "h == NULL\n"); +} + +static void test_mktemp(void) +{ + char buf[16]; + + strcpy(buf, "a"); + ok(!_mktemp(buf), "_mktemp(\"a\") != NULL\n"); + + strcpy(buf, "testXXXXX"); + ok(!_mktemp(buf), "_mktemp(\"testXXXXX\") != NULL\n"); + + strcpy(buf, "testXXXXXX"); + ok(_mktemp(buf) != NULL, "_mktemp(\"testXXXXXX\") == NULL\n"); + + strcpy(buf, "testXXXXXXa"); + ok(!_mktemp(buf), "_mktemp(\"testXXXXXXa\") != NULL\n"); + + strcpy(buf, "**XXXXXX"); + ok(_mktemp(buf) != NULL, "_mktemp(\"**XXXXXX\") == NULL\n"); +} + +static void test__open_osfhandle(void) +{ + ioinfo *info; + HANDLE h, tmp; + int fd; + + errno = 0xdeadbeef; + fd = _open_osfhandle((intptr_t)INVALID_HANDLE_VALUE, 0); + ok(fd == -1, "_open_osfhandle returned %d\n", fd); + ok(errno == EBADF, "errno = %d\n", errno); + + h = CreateFileA("open_osfhandle.tst", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + fd = _open_osfhandle((intptr_t)h, 0); + ok(fd > 0, "_open_osfhandle returned %d (%d)\n", fd, errno); + info = &__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][fd%MSVCRT_FD_BLOCK_SIZE]; + ok(info->handle == h, "info->handle = %p, expected %p\n", info->handle, h); + ok(info->wxflag == 1, "info->wxflag = %x, expected 1\n", info->wxflag); + close(fd); + ok(info->handle == INVALID_HANDLE_VALUE, "info->handle = %p, expected INVALID_HANDLE_VALUE\n", info->handle); + ok(info->wxflag == 0, "info->wxflag = %x, expected 0\n", info->wxflag); + DeleteFileA("open_osfhandle.tst"); + + errno = 0xdeadbeef; + fd = _open_osfhandle((intptr_t)h, 0); + ok(fd == -1, "_open_osfhandle returned %d\n", fd); + ok(errno == EBADF, "errno = %d\n", errno); + + ok(CreatePipe(&h, &tmp, NULL, 0), "CreatePipe failed\n"); + fd = _open_osfhandle((intptr_t)h, 0); + ok(fd > 0, "_open_osfhandle returned %d (%d)\n", fd, errno); + info = &__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][fd%MSVCRT_FD_BLOCK_SIZE]; + ok(info->handle == h, "info->handle = %p, expected %p\n", info->handle, h); + ok(info->wxflag == 9, "info->wxflag = %x, expected 9\n", info->wxflag); + close(fd); + CloseHandle(tmp); +} + START_TEST(file) { int arg_c; @@ -1656,6 +2254,7 @@ START_TEST(file) test_fopen_fclose_fcloseall(); test_fopen_s(); test__wfopen_s(); + test_setmode(); test_fileops(); test_asciimode(); test_asciimode2(); @@ -1668,12 +2267,23 @@ START_TEST(file) test_flsbuf(); test_fflush(); test_fgetwc(); + /* \x83\xa9 is double byte character, \xe0\x7f is not (undefined). */ + test_fgetwc_locale("AB\x83\xa9\xe0\x7f", "Japanese_Japan.932", 932); + /* \x83 is U+0192 */ + test_fgetwc_locale("AB\x83\xa9", "English", 1252); + /* \x83 is U+0083 */ + test_fgetwc_locale("AB\x83\xa9", "C", 0); + test_fgetwc_unicode(); + test_fputwc(); test_ctrlz(); test_file_put_get(); test_tmpnam(); test_get_osfhandle(); test_setmaxstdio(); test_pipes(arg_v[0]); + test_stdin(); + test_mktemp(); + test__open_osfhandle(); /* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order diff --git a/rostests/winetests/msvcrt/heap.c b/rostests/winetests/msvcrt/heap.c index 3587e0e56f5..309e194d035 100644 --- a/rostests/winetests/msvcrt/heap.c +++ b/rostests/winetests/msvcrt/heap.c @@ -233,7 +233,7 @@ static void test_aligned_offset_realloc(unsigned int size1, unsigned int size2, static void test_aligned(void) { - HMODULE msvcrt = GetModuleHandle("msvcrt.dll"); + HMODULE msvcrt = GetModuleHandleA("msvcrt.dll"); if (msvcrt == NULL) return; diff --git a/rostests/winetests/msvcrt/locale.c b/rostests/winetests/msvcrt/locale.c index 6b09cdf26d0..dfb21460b33 100644 --- a/rostests/winetests/msvcrt/locale.c +++ b/rostests/winetests/msvcrt/locale.c @@ -49,9 +49,6 @@ static void test_setlocale(void) ret = setlocale(20, "C"); ok(ret == NULL, "ret = %s\n", ret); - ret = setlocale(LC_ALL, ""); - ok(ret != NULL, "ret == NULL\n"); - ret = setlocale(LC_ALL, "C"); ok(!strcmp(ret, "C"), "ret = %s\n", ret); @@ -116,12 +113,14 @@ static void test_setlocale(void) ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") + || !strcmp(ret, "Chinese (Simplified)_China.936") || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "chinese-simplified"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") + || !strcmp(ret, "Chinese (Simplified)_China.936") || broken(!strcmp(ret, "Chinese_People's Republic of China.936")) || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret); @@ -135,6 +134,7 @@ static void test_setlocale(void) ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") + || !strcmp(ret, "Chinese (Simplified)_China.936") || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "cht"); @@ -143,6 +143,18 @@ static void test_setlocale(void) ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950") || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret); + ret = setlocale(LC_ALL, "Chinese_China.936"); +todo_wine + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + if(ret) + { +todo_wine + ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") + || !strcmp(ret, "Chinese (Simplified)_China.936") + || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret); + trace("ret is %s\n", ret); + } + ret = setlocale(LC_ALL, "csy"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) @@ -575,6 +587,27 @@ static void test_setlocale(void) ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); + + ret = setlocale(LC_ALL, "English_United States.ACP"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + if(ret) { + strcpy(buf, "English_United States."); + GetLocaleInfoA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), + LOCALE_IDEFAULTANSICODEPAGE, buf+strlen(buf), 80); + ok(!strcmp(ret, buf), "ret = %s, expected %s\n", ret, buf); + } + + ret = setlocale(LC_ALL, "English_United States.OCP"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + if(ret) { + strcpy(buf, "English_United States."); + GetLocaleInfoA(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), + LOCALE_IDEFAULTCODEPAGE, buf+strlen(buf), 80); + ok(!strcmp(ret, buf), "ret = %s, expected %s\n", ret, buf); + } + + ret = setlocale(LC_ALL, "English_United States.UTF8"); + ok(ret == NULL, "ret != NULL\n"); } static void test_crtGetStringTypeW(void) @@ -632,6 +665,7 @@ static void test__Gettnames(void) char data[1]; } *ret; int size; + char buf[64]; if(!setlocale(LC_ALL, "english")) return; @@ -688,7 +722,10 @@ static void test__Gettnames(void) ok(!strcmp(ret->str[39], "PM"), "ret->str[39] = %s\n", ret->str[39]); ok(!strcmp(ret->str[40], "M/d/yyyy") || broken(!strcmp(ret->str[40], "M/d/yy"))/*NT*/, "ret->str[40] = %s\n", ret->str[40]); - ok(!strcmp(ret->str[41], "dddd, MMMM dd, yyyy"), "ret->str[41] = %s\n", ret->str[41]); + size = GetLocaleInfoA(MAKELCID(LANG_ENGLISH, SORT_DEFAULT), + LOCALE_SLONGDATE|LOCALE_NOUSEROVERRIDE, buf, sizeof(buf)); + ok(size, "GetLocaleInfo failed: %x\n", GetLastError()); + ok(!strcmp(ret->str[41], buf), "ret->str[41] = %s, expected %s\n", ret->str[41], buf); free(ret); if(!setlocale(LC_TIME, "german")) @@ -745,10 +782,8 @@ static void test__Gettnames(void) static void test___mb_cur_max_func(void) { int mb_cur_max; - CPINFO cp; setlocale(LC_ALL, "C"); - GetCPInfo(CP_ACP, &cp); /* for newer Windows */ if(!p___mb_cur_max_func) @@ -772,13 +807,7 @@ static void test___mb_cur_max_func(void) win_skip("Skipping __p___mb_cur_max tests\n"); else { mb_cur_max = *p__p___mb_cur_max(); - if (cp.MaxCharSize != 1) { - todo_wine ok(mb_cur_max == cp.MaxCharSize, "mb_cur_max = %d, expected %d\n", - mb_cur_max, cp.MaxCharSize); - } - else { - ok(mb_cur_max == 1, "mb_cur_max = %d, expected 1\n", mb_cur_max); - } + ok(mb_cur_max == 1, "mb_cur_max = %d, expected 1\n", mb_cur_max); /* some old Windows don't set chinese */ if (!setlocale(LC_ALL, "chinese")) diff --git a/rostests/winetests/msvcrt/misc.c b/rostests/winetests/msvcrt/misc.c index a2bf0cb8345..26225f34ce1 100644 --- a/rostests/winetests/msvcrt/misc.c +++ b/rostests/winetests/msvcrt/misc.c @@ -20,6 +20,7 @@ #include "wine/test.h" #include +#include #include "msvcrt.h" static int (__cdecl *prand_s)(unsigned int *); @@ -309,10 +310,54 @@ static void test__set_errno(void) ok(errno == 0xdeadbeef, "Expected errno to be 0xdeadbeef, got %d\n", errno); } +static void test__popen_child(void) +{ + /* don't execute any tests here */ + /* ExitProcess is used to set return code of _pclose */ + printf("child output\n"); + ExitProcess(0x37); +} + +static void test__popen(const char *name) +{ + FILE *pipe; + char buf[1024]; + int ret; + + sprintf(buf, "%s misc popen", name); + pipe = _popen(buf, "r"); + ok(pipe != NULL, "_popen failed with error: %d\n", errno); + + fgets(buf, sizeof(buf), pipe); + ok(!strcmp(buf, "child output\n"), "buf = %s\n", buf); + + ret = _pclose(pipe); + ok(ret == 0x37, "_pclose returned %x, expected 0x37\n", ret); + + errno = 0xdeadbeef; + ret = _pclose((FILE*)0xdeadbeef); + ok(ret == -1, "_pclose returned %x, expected -1\n", ret); + if(p_set_errno) + ok(errno == EBADF, "errno = %d\n", errno); +} + START_TEST(misc) { + int arg_c; + char** arg_v; + init(); + arg_c = winetest_get_mainargs(&arg_v); + if(arg_c >= 3) { + if(!strcmp(arg_v[2], "popen")) + test__popen_child(); + else + ok(0, "invalid argument '%s'\n", arg_v[2]); + + return; + } + test_rand_s(); test_I10_OUTPUT(); test_strerror_s(); @@ -320,4 +365,5 @@ START_TEST(misc) test__get_errno(); test__set_doserrno(); test__set_errno(); + test__popen(arg_v[0]); } diff --git a/rostests/winetests/msvcrt/msvcrt_test.dsp b/rostests/winetests/msvcrt/msvcrt_test.dsp deleted file mode 100644 index 1e27830971b..00000000000 --- a/rostests/winetests/msvcrt/msvcrt_test.dsp +++ /dev/null @@ -1,107 +0,0 @@ -# Microsoft Developer Studio Project File - Name="msvcrt_test" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=msvcrt_test - Win32 Wine Headers -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "msvcrt_test.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "msvcrt_test.mak" CFG="msvcrt_test - Win32 Wine Headers" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "msvcrt_test - Win32 MSVC Headers" (based on "Win32 (x86) Console Application") -!MESSAGE "msvcrt_test - Win32 Wine Headers" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe -!IF "$(CFG)" == "msvcrt_test - Win32 MSVC Headers" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Output\Win32_MSVC_Headers" -# PROP BASE Intermediate_Dir "Output\Win32_MSVC_Headers" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Output\Win32_MSVC_Headers" -# PROP Intermediate_Dir "Output\Win32_MSVC_Headers" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WINVER=0x0501" /D "_WIN32_WINNT=0x0501" /D "_WIN32_IE=0x0600" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ..\..\..\Output\\Win32_MSVC_Headers /D "WINVER=0x0501" /D "_WIN32_WINNT=0x0501" /D "_WIN32_IE=0x0600" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_MSVCRT_TEST_" /D "__WINE_USE_NATIVE_HEADERS" /D __WINETEST_OUTPUT_DIR=\"Output\\Win32_MSVC_Headers\" /D "__i386__" /D "_X86_" /D inline=__inline /FR /FD /GZ /c -# ADD BASE RSC /l 0x41d /d "_DEBUG" -# ADD RSC /l 0x41d /i "..\..\..\Output\\Win32_MSVC_Headers" /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ELSEIF "$(CFG)" == "msvcrt_test - Win32 Wine Headers" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Output\Win32_Wine_Headers" -# PROP BASE Intermediate_Dir "Output\Win32_Wine_Headers" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Output\Win32_Wine_Headers" -# PROP Intermediate_Dir "Output\Win32_Wine_Headers" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WINVER=0x0501" /D "_WIN32_WINNT=0x0501" /D "_WIN32_IE=0x0600" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ..\..\..\Output\\Win32_Wine_Headers /I ..\..\..\include /D "WINVER=0x0501" /D "_WIN32_WINNT=0x0501" /D "_WIN32_IE=0x0600" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_MSVCRT_TEST_" /D __WINETEST_OUTPUT_DIR=\"Output\\Win32_Wine_Headers\" /D "__i386__" /D "_X86_" /D inline=__inline /FR /FD /GZ /c -# ADD BASE RSC /l 0x41d /d "_DEBUG" -# ADD RSC /l 0x41d /i "..\..\..\Output\\Win32_Wine_Headers" /i "..\..\..\include" /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "msvcrt_test - Win32 MSVC Headers" -# Name "msvcrt_test - Win32 Wine Headers" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\cpp.c -# End Source File -# Begin Source File - -SOURCE=.\\ -# End Source File -# Begin Source File - -SOURCE=.\testlist.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/rostests/winetests/msvcrt/printf.c b/rostests/winetests/msvcrt/printf.c index 1507a0185d1..829b2e0501b 100644 --- a/rostests/winetests/msvcrt/printf.c +++ b/rostests/winetests/msvcrt/printf.c @@ -27,6 +27,7 @@ #include #include +#include #include "windef.h" #include "winbase.h" @@ -44,6 +45,7 @@ static int (__cdecl *p__ecvt_s)(char *buffer, size_t length, double number, static int (__cdecl *p__fcvt_s)(char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign); static unsigned int (__cdecl *p__get_output_format)(void); +static unsigned int (__cdecl *p__set_output_format)(unsigned int); static int (__cdecl *p__vsprintf_p)(char*, size_t, const char*, __ms_va_list); static int (__cdecl *p_vswprintf)(wchar_t *str, const wchar_t *format, __ms_va_list valist); static int (__cdecl *p__vswprintf)(wchar_t *str, const wchar_t *format, __ms_va_list valist); @@ -66,6 +68,7 @@ static void init( void ) p__ecvt_s = (void *)GetProcAddress(hmod, "_ecvt_s"); p__fcvt_s = (void *)GetProcAddress(hmod, "_fcvt_s"); p__get_output_format = (void *)GetProcAddress(hmod, "_get_output_format"); + p__set_output_format = (void *)GetProcAddress(hmod, "_set_output_format"); p__vsprintf_p = (void*)GetProcAddress(hmod, "_vsprintf_p"); p_vswprintf = (void*)GetProcAddress(hmod, "vswprintf"); p__vswprintf = (void*)GetProcAddress(hmod, "_vswprintf"); @@ -79,7 +82,7 @@ static void test_sprintf( void ) { char buffer[100]; const char *format; - double pnumber=789456123; + double pnumber=789456123, inf, nan; int x, r; WCHAR wide[] = { 'w','i','d','e',0}; @@ -326,18 +329,52 @@ static void test_sprintf( void ) format = "%#012x"; r = sprintf(buffer,format,1); ok(!strcmp(buffer,"0x0000000001"),"Hexadecimal zero-padded \"%s\"\n",buffer); + ok( r==12, "return count wrong\n"); + + r = sprintf(buffer,format,0); + ok(!strcmp(buffer,"000000000000"),"Hexadecimal zero-padded \"%s\"\n",buffer); + ok( r==12, "return count wrong\n"); format = "%#04.8x"; r = sprintf(buffer,format,1); ok(!strcmp(buffer,"0x00000001"), "Hexadecimal zero-padded precision \"%s\"\n",buffer); + ok( r==10, "return count wrong\n"); + + r = sprintf(buffer,format,0); + ok(!strcmp(buffer,"00000000"), "Hexadecimal zero-padded precision \"%s\"\n",buffer); + ok( r==8, "return count wrong\n"); format = "%#-08.2x"; r = sprintf(buffer,format,1); ok(!strcmp(buffer,"0x01 "), "Hexadecimal zero-padded not left-adjusted \"%s\"\n",buffer); + ok( r==8, "return count wrong\n"); + + r = sprintf(buffer,format,0); + ok(!strcmp(buffer,"00 "), "Hexadecimal zero-padded not left-adjusted \"%s\"\n",buffer); + ok( r==8, "return count wrong\n"); + + format = "%#.0x"; + r = sprintf(buffer,format,1); + ok(!strcmp(buffer,"0x1"), "Hexadecimal zero-padded zero-precision \"%s\"\n",buffer); + ok( r==3, "return count wrong\n"); + + r = sprintf(buffer,format,0); + ok(!strcmp(buffer,""), "Hexadecimal zero-padded zero-precision \"%s\"\n",buffer); + ok( r==0, "return count wrong\n"); format = "%#08o"; r = sprintf(buffer,format,1); ok(!strcmp(buffer,"00000001"), "Octal zero-padded \"%s\"\n",buffer); + ok( r==8, "return count wrong\n"); + + format = "%#o"; + r = sprintf(buffer,format,1); + ok(!strcmp(buffer,"01"), "Octal zero-padded \"%s\"\n",buffer); + ok( r==2, "return count wrong\n"); + + r = sprintf(buffer,format,0); + ok(!strcmp(buffer,"0"), "Octal zero-padded \"%s\"\n",buffer); + ok( r==1, "return count wrong\n"); if (sizeof(void *) == 8) { @@ -515,6 +552,26 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"8.6000e+000"), "failed\n"); ok( r==11, "return count wrong\n"); + format = "% 2.4e"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer," 8.6000e+000"), "failed: %s\n", buffer); + ok( r==12, "return count wrong\n"); + + format = "% 014.4e"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer," 008.6000e+000"), "failed: %s\n", buffer); + ok( r==14, "return count wrong\n"); + + format = "% 2.4e"; + r = sprintf(buffer, format,-8.6); + ok(!strcmp(buffer,"-8.6000e+000"), "failed: %s\n", buffer); + ok( r==12, "return count wrong\n"); + + format = "%+2.4e"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer,"+8.6000e+000"), "failed: %s\n", buffer); + ok( r==12, "return count wrong\n"); + format = "%2.4g"; r = sprintf(buffer, format,8.6); ok(!strcmp(buffer,"8.6"), "failed\n"); @@ -617,6 +674,41 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"123"), "failed: \"%s\"\n", buffer); r = sprintf(buffer, format, 0x12345); ok(!strcmp(buffer,"2345"), "failed \"%s\"\n", buffer); + + nan = 0.0; + inf = 1.0/nan; + nan = sqrt(-1); + format = "%lf"; + r = sprintf(buffer, format, nan); + ok(r==9, "r = %d\n", r); + ok(!strcmp(buffer, "-1.#IND00"), "failed: \"%s\"\n", buffer); + r = sprintf(buffer, format, inf); + ok(r==8, "r = %d\n", r); + ok(!strcmp(buffer, "1.#INF00"), "failed: \"%s\"\n", buffer); + + format = "%le"; + r = sprintf(buffer, format, nan); + ok(r==14, "r = %d\n", r); + ok(!strcmp(buffer, "-1.#IND00e+000"), "failed: \"%s\"\n", buffer); + r = sprintf(buffer, format, inf); + ok(r==13, "r = %d\n", r); + ok(!strcmp(buffer, "1.#INF00e+000"), "failed: \"%s\"\n", buffer); + + format = "%lg"; + r = sprintf(buffer, format, nan); + ok(r==7, "r = %d\n", r); + ok(!strcmp(buffer, "-1.#IND"), "failed: \"%s\"\n", buffer); + r = sprintf(buffer, format, inf); + ok(r==6, "r = %d\n", r); + ok(!strcmp(buffer, "1.#INF"), "failed: \"%s\"\n", buffer); + + format = "%010.2lf"; + r = sprintf(buffer, format, nan); + ok(r==10, "r = %d\n", r); + ok(!strcmp(buffer, "-000001.#J"), "failed: \"%s\"\n", buffer); + r = sprintf(buffer, format, inf); + ok(r==10, "r = %d\n", r); + ok(!strcmp(buffer, "0000001.#J"), "failed: \"%s\"\n", buffer); } static void test_swprintf( void ) @@ -671,7 +763,9 @@ static void test_snprintf (void) static void test_fprintf(void) { - static char file_name[] = "fprintf.tst"; + static const char file_name[] = "fprintf.tst"; + static const WCHAR utf16_test[] = {'u','n','i','c','o','d','e','\n',0}; + FILE *fp = fopen(file_name, "wb"); char buf[1024]; int ret; @@ -686,6 +780,11 @@ static void test_fprintf(void) ret = ftell(fp); ok(ret == 26, "ftell returned %d\n", ret); + ret = fwprintf(fp, utf16_test); + ok(ret == 8, "ret = %d\n", ret); + ret = ftell(fp); + ok(ret == 42, "ftell returned %d\n", ret); + fclose(fp); fp = fopen(file_name, "rb"); @@ -700,6 +799,51 @@ static void test_fprintf(void) ok(ret == 26, "ret = %d\n", ret); ok(!memcmp(buf, "contains\0null\n", 14), "buf = %s\n", buf); + memset(buf, 0, sizeof(buf)); + fgets(buf, sizeof(buf), fp); + ret = ftell(fp); + ok(ret == 41, "ret = %d\n", ret); + ok(!memcmp(buf, utf16_test, sizeof(utf16_test)), + "buf = %s\n", wine_dbgstr_w((WCHAR*)buf)); + + fclose(fp); + + fp = fopen(file_name, "wt"); + + ret = fprintf(fp, "simple test\n"); + ok(ret == 12, "ret = %d\n", ret); + ret = ftell(fp); + ok(ret == 13, "ftell returned %d\n", ret); + + ret = fprintf(fp, "contains%cnull\n", '\0'); + ok(ret == 14, "ret = %d\n", ret); + ret = ftell(fp); + ok(ret == 28, "ftell returned %d\n", ret); + + ret = fwprintf(fp, utf16_test); + ok(ret == 8, "ret = %d\n", ret); + ret = ftell(fp); + ok(ret == 37, "ftell returned %d\n", ret); + + fclose(fp); + + fp = fopen(file_name, "rb"); + ret = fscanf(fp, "%[^\n] ", buf); + ok(ret == 1, "ret = %d\n", ret); + ret = ftell(fp); + ok(ret == 13, "ftell returned %d\n", ret); + ok(!strcmp(buf, "simple test\r"), "buf = %s\n", buf); + + fgets(buf, sizeof(buf), fp); + ret = ftell(fp); + ok(ret == 28, "ret = %d\n", ret); + ok(!memcmp(buf, "contains\0null\r\n", 15), "buf = %s\n", buf); + + fgets(buf, sizeof(buf), fp); + ret = ftell(fp); + ok(ret == 37, "ret = %d\n", ret); + ok(!strcmp(buf, "unicode\r\n"), "buf = %s\n", buf); + fclose(fp); unlink(file_name); } @@ -1244,15 +1388,34 @@ static void test_vsprintf_p(void) static void test__get_output_format(void) { unsigned int ret; + char buf[64]; + int c; - if (!p__get_output_format) + if (!p__get_output_format || !p__set_output_format) { - win_skip("_get_output_format not available\n"); + win_skip("_get_output_format or _set_output_format is not available\n"); return; } ret = p__get_output_format(); ok(ret == 0, "got %d\n", ret); + + c = sprintf(buf, "%E", 1.23); + ok(c == 13, "c = %d\n", c); + ok(!strcmp(buf, "1.230000E+000"), "buf = %s\n", buf); + + ret = p__set_output_format(_TWO_DIGIT_EXPONENT); + ok(ret == 0, "got %d\n", ret); + + c = sprintf(buf, "%E", 1.23); + ok(c == 12, "c = %d\n", c); + ok(!strcmp(buf, "1.230000E+00"), "buf = %s\n", buf); + + ret = p__get_output_format(); + ok(ret == _TWO_DIGIT_EXPONENT, "got %d\n", ret); + + ret = p__set_output_format(_TWO_DIGIT_EXPONENT); + ok(ret == _TWO_DIGIT_EXPONENT, "got %d\n", ret); } START_TEST(printf) diff --git a/rostests/winetests/msvcrt/scanf.c b/rostests/winetests/msvcrt/scanf.c index b09e7dfd2d9..97b8074bc02 100644 --- a/rostests/winetests/msvcrt/scanf.c +++ b/rostests/winetests/msvcrt/scanf.c @@ -131,6 +131,13 @@ static void test_sscanf( void ) ok( ret == 1, "Error with format \"%s\"\n","%*[a-cd-dg-e]%c"); ok( buffer[0] == 'h', "Error with \"abcefgdh\" \"%c\"\n", buffer[0]); + buffer1[0] = 'b'; + ret = sscanf("a","%s%s", buffer, buffer1); + ok( ret == 1, "expected 1, got %u\n", ret); + ok( buffer[0] == 'a', "buffer[0] = '%c'\n", buffer[0]); + ok( buffer[1] == '\0', "buffer[1] = '%c'\n", buffer[1]); + ok( buffer1[0] == 'b', "buffer1[0] = '%c'\n", buffer1[0]); + /* check digits */ ret = sprintf(buffer,"%d:%d:%d",hour,min,sec); ok( ret == 8, "expected 8, got %u\n", ret); diff --git a/rostests/winetests/msvcrt/signal.c b/rostests/winetests/msvcrt/signal.c index d33498bd537..ad6ea6ecf90 100644 --- a/rostests/winetests/msvcrt/signal.c +++ b/rostests/winetests/msvcrt/signal.c @@ -26,6 +26,13 @@ static int test_value = 0; static void __cdecl sighandler(int signum) { + void **ret = __pxcptinfoptrs(); + + ok(ret != NULL, "ret = NULL\n"); + if(signum == SIGABRT) + ok(*ret == (void*)0xdeadbeef, "*ret = %p\n", *ret); + else if(signum == SIGSEGV) + ok(*ret == NULL, "*ret = %p\n", *ret); ++test_value; } @@ -42,7 +49,32 @@ static void test_signal(void) ok(test_value == 1, "SIGBREAK handler not invoked\n"); } +static void test___pxcptinfoptrs(void) +{ + void **ret = __pxcptinfoptrs(); + int res; + + ok(ret != NULL, "ret == NULL\n"); + ok(*ret == NULL, "*ret != NULL\n"); + + test_value = 0; + + *ret = (void*)0xdeadbeef; + signal(SIGSEGV, sighandler); + res = raise(SIGSEGV); + ok(res == 0, "failed to raise SIGSEGV\n"); + ok(*ret == (void*)0xdeadbeef, "*ret = %p\n", *ret); + + signal(SIGABRT, sighandler); + res = raise(SIGABRT); + ok(res == 0, "failed to raise SIGBREAK\n"); + ok(*ret == (void*)0xdeadbeef, "*ret = %p\n", *ret); + + ok(test_value == 2, "test_value = %d\n", test_value); +} + START_TEST(signal) { test_signal(); + test___pxcptinfoptrs(); } diff --git a/rostests/winetests/msvcrt/string.c b/rostests/winetests/msvcrt/string.c index d606ebb444c..7d820e1c7df 100644 --- a/rostests/winetests/msvcrt/string.c +++ b/rostests/winetests/msvcrt/string.c @@ -19,8 +19,6 @@ */ #include "wine/test.h" -#include "winbase.h" -#include "winnls.h" #include #include #include @@ -30,6 +28,12 @@ #include #include #include +#include + +/* make it use a definition from string.h */ +#undef strncpy +#include "winbase.h" +#include "winnls.h" static char *buf_to_string(const unsigned char *bin, int len, int nr) { @@ -70,6 +74,8 @@ static int (__cdecl *p_wcsupr_s)(wchar_t *str, size_t size); static size_t (__cdecl *p_strnlen)(const char *, size_t); static __int64 (__cdecl *p_strtoi64)(const char *, char **, int); static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int); +static __int64 (__cdecl *p_wcstoi64)(const wchar_t *, wchar_t **, int); +static unsigned __int64 (__cdecl *p_wcstoui64)(const wchar_t *, wchar_t **, int); static int (__cdecl *pwcstombs_s)(size_t*,char*,size_t,const wchar_t*,size_t); static int (__cdecl *pmbstowcs_s)(size_t*,wchar_t*,size_t,const char*,size_t); static size_t (__cdecl *p_mbsrtowcs)(wchar_t*, const char**, size_t, mbstate_t*); @@ -89,6 +95,7 @@ static size_t (__cdecl *p_wcrtomb)(char*, wchar_t, mbstate_t*); static int (__cdecl *p_tolower)(int); static size_t (__cdecl *p_mbrlen)(const char*, size_t, mbstate_t*); static size_t (__cdecl *p_mbrtowc)(wchar_t*, const char*, size_t, mbstate_t*); +static int (__cdecl *p__atodbl_l)(_CRT_DOUBLE*,char*,_locale_t); #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y) #define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y) @@ -428,9 +435,7 @@ static void test_mbcp(void) expect_eq(_ismbblead(0x84), 1, int, "%d"); expect_eq(_ismbblead(0xd3), 1, int, "%d"); expect_eq(_ismbblead(0xd7), 0, int, "%d"); - todo_wine { - expect_eq(_ismbblead(0xd8), 1, int, "%d"); - } + expect_eq(_ismbblead(0xd8), 1, int, "%d"); expect_eq(_ismbblead(0xd9), 1, int, "%d"); expect_eq(_ismbbtrail(0x30), 0, int, "%d"); @@ -806,23 +811,33 @@ static void test_wcscpy_s(void) return; } + if (p_set_invalid_parameter_handler) + ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, + "Invalid parameter handler was already set\n"); + /* Test NULL Dest */ + errno = EBADF; ret = p_wcscpy_s(NULL, 18, szLongText); ok(ret == EINVAL, "p_wcscpy_s expect EINVAL got %d\n", ret); + ok(errno == EINVAL, "expected errno EINVAL got %d\n", errno); /* Test NULL Source */ + errno = EBADF; szDest[0] = 'A'; ret = p_wcscpy_s(szDest, 18, NULL); ok(ret == EINVAL, "expected EINVAL got %d\n", ret); - ok(szDest[0] == 0, "szDest[0] not 0\n"); + ok(errno == EINVAL, "expected errno EINVAL got %d\n", errno); + ok(szDest[0] == 0, "szDest[0] not 0, got %c\n", szDest[0]); /* Test invalid size */ + errno = EBADF; szDest[0] = 'A'; ret = p_wcscpy_s(szDest, 0, szLongText); /* Later versions changed the return value for this case to EINVAL, * and don't modify the result if the dest size is 0. */ ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(errno == ERANGE || errno == EINVAL, "expected errno ERANGE/EINVAL got %d\n", errno); ok(szDest[0] == 0 || ret == EINVAL, "szDest[0] not 0\n"); /* Copy same buffer size */ @@ -831,14 +846,20 @@ static void test_wcscpy_s(void) ok(lstrcmpW(szDest, szLongText) == 0, "szDest != szLongText\n"); /* Copy smaller buffer size */ + errno = EBADF; szDest[0] = 'A'; ret = p_wcscpy_s(szDestShort, 8, szLongText); ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(errno == ERANGE || errno == EINVAL, "expected errno ERANGE/EINVAL got %d\n", errno); ok(szDestShort[0] == 0, "szDestShort[0] not 0\n"); if(!p_wcsncpy_s) { win_skip("wcsncpy_s not found\n"); + + if (p_set_invalid_parameter_handler) + ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler, + "Cannot reset invalid parameter handler\n"); return; } @@ -884,6 +905,10 @@ static void test_wcscpy_s(void) ok(ret == STRUNCATE, "expected ERROR_SUCCESS got %d\n", ret); ok(szDestShort[0]=='1' && szDestShort[1]=='1' && szDestShort[2]=='1' && szDestShort[3]=='1', "szDestShort = %s\n", wine_dbgstr_w(szDestShort)); + + if (p_set_invalid_parameter_handler) + ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler, + "Cannot reset invalid parameter handler\n"); } static void test__wcsupr_s(void) @@ -1319,6 +1344,26 @@ static void test_strtol(void) ul = strtoul("9223372036854775807L", &e, 0); ok(ul==4294967295ul, "wrong value %u\n", ul); ok(errno == ERANGE, "wrong errno %d\n", errno); + + errno = 0; + ul = strtoul("-2", NULL, 0); + ok(ul == -2, "wrong value %u\n", ul); + ok(errno == 0, "wrong errno %d\n", errno); + + errno = 0; + ul = strtoul("-4294967294", NULL, 0); + ok(ul == 2, "wrong value %u\n", ul); + ok(errno == 0, "wrong errno %d\n", errno); + + errno = 0; + ul = strtoul("-4294967295", NULL, 0); + ok(ul==1, "wrong value %u\n", ul); + ok(errno == 0, "wrong errno %d\n", errno); + + errno = 0; + ul = strtoul("-4294967296", NULL, 0); + ok(ul == 1, "wrong value %u\n", ul); + ok(errno == ERANGE, "wrong errno %d\n", errno); } static void test_strnlen(void) @@ -1590,6 +1635,14 @@ static void test_mbstowcs(void) wOut[4] = '!'; wOut[5] = '\0'; mOut[4] = '!'; mOut[5] = '\0'; + if(pmbstowcs_s) { + /* crashes on some systems */ + errno = 0xdeadbeef; + ret = mbstowcs(wOut, NULL, 4); + ok(ret == -1, "mbstowcs did not return -1\n"); + ok(errno == EINVAL, "errno = %d\n", errno); + } + ret = mbstowcs(NULL, mSimple, 0); ok(ret == 4, "mbstowcs did not return 4\n"); @@ -1840,6 +1893,11 @@ static void test__itoa_s(void) ok(!strcmp(buffer, "-12345678"), "Expected output buffer string to be \"-12345678\", got \"%s\"\n", buffer); + + itoa(100, buffer, 100); + ok(!strcmp(buffer, "10"), + "Expected output buffer string to be \"10\", got \"%s\"\n", buffer); + if (p_set_invalid_parameter_handler) ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler, "Cannot reset invalid parameter handler\n"); @@ -2189,6 +2247,24 @@ static void test__mbslwr_s(void) buffer); } +static void test__mbstok(void) +{ + const unsigned char delim[] = "t"; + + char str[] = "!.!test"; + unsigned char *ret; + + strtok(str, "!"); + + ret = _mbstok(NULL, delim); + /* most versions of msvcrt use the same buffer for strtok and _mbstok */ + ok(!ret || broken((char*)ret==str+4), + "_mbstok(NULL, \"t\") = %p, expected NULL (%p)\n", ret, str); + + ret = _mbstok(NULL, delim); + ok(!ret, "_mbstok(NULL, \"t\") = %p, expected NULL\n", ret); +} + static void test__ultoa_s(void) { errno_t ret; @@ -2336,36 +2412,66 @@ static void test_wctomb(void) ret = p_wcrtomb((char*)dst, 0xffff, NULL); ok(ret == -1, "wcrtomb did not return -1\n"); - ok(dst[0] == 0x3f, "dst[0] = %x, expected 0x20\n", dst[0]); + ok(dst[0] == 0x3f, "dst[0] = %x, expected 0x3f\n", dst[0]); setlocale(LC_ALL, "C"); } static void test_tolower(void) { - int ret; + char ch, lch; + int ret, len; + /* test C locale when locale was never changed */ ret = p_tolower(0x41); ok(ret == 0x61, "ret = %x\n", ret); ret = p_tolower(0xF4); ok(ret == 0xF4, "ret = %x\n", ret); + errno = 0xdeadbeef; ret = p_tolower((char)0xF4); - ok(ret==0xF4/*Vista+*/ || ret==(char)0xF4, "ret = %x\n", ret); + todo_wine ok(ret == (char)0xF4, "ret = %x\n", ret); + todo_wine ok(errno == 0xdeadbeef, "errno = %d\n", errno); - /* is it using different locale (CP_ACP) for negative values?? */ - /* current implementation matches msvcr90 behaviour */ + errno = 0xdeadbeef; ret = p_tolower((char)0xD0); - todo_wine ok(ret==0xF0/*Vista+*/ || ret==(char)0xD0, "ret = %x\n", ret); - - ret = p_tolower(0xD0); - ok(ret == 0xD0, "ret = %x\n", ret); + todo_wine ok(ret == (char)0xD0, "ret = %x\n", ret); + todo_wine ok(errno == 0xdeadbeef, "errno = %d\n", errno); + /* test C locale after setting locale */ if(!setlocale(LC_ALL, "us")) { win_skip("skipping tolower tests that depends on locale\n"); return; } + setlocale(LC_ALL, "C"); + + ch = 0xF4; + errno = 0xdeadbeef; + ret = p_tolower(ch); + len = LCMapStringA(0, LCMAP_LOWERCASE, &ch, 1, &lch, 1); + if(len) + ok(ret==(unsigned char)lch || broken(ret==ch)/*WinXP-*/, "ret = %x\n", ret); + else + ok(ret == ch, "ret = %x\n", ret); + if(!len || ret==(unsigned char)lch) + ok(errno == EILSEQ, "errno = %d\n", errno); + + ch = 0xD0; + errno = 0xdeadbeef; + ret = p_tolower(ch); + len = LCMapStringA(0, LCMAP_LOWERCASE, &ch, 1, &lch, 1); + if(len) + ok(ret==(unsigned char)lch || broken(ret==ch)/*WinXP-*/, "ret = %x\n", ret); + else + ok(ret == ch, "ret = %x\n", ret); + if(!len || ret==(unsigned char)lch) + ok(errno == EILSEQ, "errno = %d\n", errno); + + ret = p_tolower(0xD0); + ok(ret == 0xD0, "ret = %x\n", ret); + + ok(setlocale(LC_ALL, "us") != NULL, "setlocale failed\n"); ret = p_tolower((char)0xD0); ok(ret == 0xF0, "ret = %x\n", ret); @@ -2376,6 +2482,194 @@ static void test_tolower(void) setlocale(LC_ALL, "C"); } +static void test__atodbl(void) +{ + _CRT_DOUBLE d; + char num[32]; + int ret; + + if(!p__atodbl_l) { + /* Old versions of msvcrt use different values for _OVERFLOW and _UNDERFLOW + * Because of this lets skip _atodbl tests when _atodbl_l is not available */ + win_skip("_atodbl_l is not available\n"); + return; + } + + num[0] = 0; + ret = p__atodbl_l(&d, num, NULL); + ok(ret == 0, "_atodbl_l(&d, \"\", NULL) returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + ret = _atodbl(&d, num); + ok(ret == 0, "_atodbl(&d, \"\") returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + + strcpy(num, "t"); + ret = p__atodbl_l(&d, num, NULL); + ok(ret == 0, "_atodbl_l(&d, \"t\", NULL) returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + ret = _atodbl(&d, num); + ok(ret == 0, "_atodbl(&d, \"t\") returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + + strcpy(num, "0"); + ret = p__atodbl_l(&d, num, NULL); + ok(ret == 0, "_atodbl_l(&d, \"0\", NULL) returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + ret = _atodbl(&d, num); + ok(ret == 0, "_atodbl(&d, \"0\") returned %d, expected 0\n", ret); + ok(d.x == 0, "d.x = %lf, expected 0\n", d.x); + + strcpy(num, "123"); + ret = p__atodbl_l(&d, num, NULL); + ok(ret == 0, "_atodbl_l(&d, \"123\", NULL) returned %d, expected 0\n", ret); + ok(d.x == 123, "d.x = %lf, expected 123\n", d.x); + ret = _atodbl(&d, num); + ok(ret == 0, "_atodbl(&d, \"123\") returned %d, expected 0\n", ret); + ok(d.x == 123, "d.x = %lf, expected 123\n", d.x); + + strcpy(num, "1e-309"); + ret = p__atodbl_l(&d, num, NULL); + ok(ret == _UNDERFLOW, "_atodbl_l(&d, \"1e-309\", NULL) returned %d, expected _UNDERFLOW\n", ret); + ok(d.x!=0 && almost_equal(d.x, 0), "d.x = %le, expected 0\n", d.x); + ret = _atodbl(&d, num); + ok(ret == _UNDERFLOW, "_atodbl(&d, \"1e-309\") returned %d, expected _UNDERFLOW\n", ret); + ok(d.x!=0 && almost_equal(d.x, 0), "d.x = %le, expected 0\n", d.x); + + strcpy(num, "1e309"); + ret = p__atodbl_l(&d, num, NULL); + ok(ret == _OVERFLOW, "_atodbl_l(&d, \"1e309\", NULL) returned %d, expected _OVERFLOW\n", ret); + ret = _atodbl(&d, num); + ok(ret == _OVERFLOW, "_atodbl(&d, \"1e309\") returned %d, expected _OVERFLOW\n", ret); +} + +static void test__stricmp(void) +{ + int ret; + + ret = _stricmp("test", "test"); + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("a", "z"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("z", "a"); + ok(ret > 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5", "\xb9"); + ok(ret < 0, "_stricmp returned %d\n", ret); + + if(!setlocale(LC_ALL, "polish")) { + win_skip("stricmp tests\n"); + return; + } + + ret = _stricmp("test", "test"); + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("a", "z"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("z", "a"); + ok(ret > 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5", "\xb9"); + ok(ret == 0, "_stricmp returned %d\n", ret); + + setlocale(LC_ALL, "C"); +} + +static void test__wcstoi64(void) +{ + static const WCHAR digit[] = { '9', 0 }; + static const WCHAR stock[] = { 0x3231, 0 }; /* PARENTHESIZED IDEOGRAPH STOCK */ + static const WCHAR tamil[] = { 0x0bef, 0 }; /* TAMIL DIGIT NINE */ + static const WCHAR thai[] = { 0x0e59, 0 }; /* THAI DIGIT NINE */ + static const WCHAR fullwidth[] = { 0xff19, 0 }; /* FULLWIDTH DIGIT NINE */ + static const WCHAR hex[] = { 0xff19, 'f', 0x0e59, 0xff46, 0 }; + + __int64 res; + unsigned __int64 ures; + WCHAR *endpos; + + if (!p_wcstoi64 || !p_wcstoui64) { + win_skip("_wcstoi64 or _wcstoui64 not found\n"); + return; + } + + res = p_wcstoi64(digit, NULL, 10); + ok(res == 9, "res != 9\n"); + res = p_wcstoi64(stock, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == stock, "Incorrect endpos (%p-%p)\n", stock, endpos); + res = p_wcstoi64(tamil, &endpos, 10); + ok(res == 0, "res != 0\n"); + ok(endpos == tamil, "Incorrect endpos (%p-%p)\n", tamil, endpos); + res = p_wcstoi64(thai, NULL, 10); + todo_wine ok(res == 9, "res != 9\n"); + res = p_wcstoi64(fullwidth, NULL, 10); + todo_wine ok(res == 9, "res != 9\n"); + res = p_wcstoi64(hex, NULL, 16); + todo_wine ok(res == 0x9f9, "res != 0x9f9\n"); + + ures = p_wcstoui64(digit, NULL, 10); + ok(ures == 9, "ures != 9\n"); + ures = p_wcstoui64(stock, &endpos, 10); + ok(ures == 0, "ures != 0\n"); + ok(endpos == stock, "Incorrect endpos (%p-%p)\n", stock, endpos); + ures = p_wcstoui64(tamil, &endpos, 10); + ok(ures == 0, "ures != 0\n"); + ok(endpos == tamil, "Incorrect endpos (%p-%p)\n", tamil, endpos); + ures = p_wcstoui64(thai, NULL, 10); + todo_wine ok(ures == 9, "ures != 9\n"); + ures = p_wcstoui64(fullwidth, NULL, 10); + todo_wine ok(ures == 9, "ures != 9\n"); + ures = p_wcstoui64(hex, NULL, 16); + todo_wine ok(ures == 0x9f9, "ures != 0x9f9\n"); + + return; +} + +static void test_atoi(void) +{ + int r; + + r = atoi("0"); + ok(r == 0, "atoi(0) = %d\n", r); + + r = atoi("-1"); + ok(r == -1, "atoi(-1) = %d\n", r); + + r = atoi("1"); + ok(r == 1, "atoi(1) = %d\n", r); + + r = atoi("4294967296"); + ok(r == 0, "atoi(4294967296) = %d\n", r); +} + +static void test_strncpy(void) +{ +#define TEST_STRNCPY_LEN 10 + char *ret; + char dst[TEST_STRNCPY_LEN + 1]; + char not_null_terminated[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; + + /* strlen(src) > TEST_STRNCPY_LEN */ + ret = strncpy(dst, "01234567890123456789", TEST_STRNCPY_LEN); + ok(ret == dst, "ret != dst\n"); + ok(!strncmp(dst, "0123456789", TEST_STRNCPY_LEN), "dst != 0123456789\n"); + + /* without null-terminated */ + ret = strncpy(dst, not_null_terminated, TEST_STRNCPY_LEN); + ok(ret == dst, "ret != dst\n"); + ok(!strncmp(dst, "0123456789", TEST_STRNCPY_LEN), "dst != 0123456789\n"); + + /* strlen(src) < TEST_STRNCPY_LEN */ + strcpy(dst, "0123456789"); + ret = strncpy(dst, "012345", TEST_STRNCPY_LEN); + ok(ret == dst, "ret != dst\n"); + ok(!strcmp(dst, "012345"), "dst != 012345\n"); + ok(dst[TEST_STRNCPY_LEN - 1] == '\0', "dst[TEST_STRNCPY_LEN - 1] != 0\n"); + + /* strlen(src) == TEST_STRNCPY_LEN */ + ret = strncpy(dst, "0123456789", TEST_STRNCPY_LEN); + ok(ret == dst, "ret != dst\n"); + ok(!strncmp(dst, "0123456789", TEST_STRNCPY_LEN), "dst != 0123456789\n"); +} + START_TEST(string) { char mem[100]; @@ -2403,6 +2697,8 @@ START_TEST(string) p_strnlen = (void *)GetProcAddress( hMsvcrt,"strnlen" ); p_strtoi64 = (void *)GetProcAddress(hMsvcrt, "_strtoi64"); p_strtoui64 = (void *)GetProcAddress(hMsvcrt, "_strtoui64"); + p_wcstoi64 = (void *)GetProcAddress(hMsvcrt, "_wcstoi64"); + p_wcstoui64 = (void *)GetProcAddress(hMsvcrt, "_wcstoui64"); pmbstowcs_s = (void *)GetProcAddress(hMsvcrt, "mbstowcs_s"); pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s"); pwcsrtombs = (void *)GetProcAddress(hMsvcrt, "wcsrtombs"); @@ -2420,6 +2716,7 @@ START_TEST(string) p_mbrlen = (void*)GetProcAddress(hMsvcrt, "mbrlen"); p_mbrtowc = (void*)GetProcAddress(hMsvcrt, "mbrtowc"); p_mbsrtowcs = (void*)GetProcAddress(hMsvcrt, "mbsrtowcs"); + p__atodbl_l = (void*)GetProcAddress(hMsvcrt, "_atodbl_l"); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -2429,15 +2726,12 @@ START_TEST(string) ok(pmemcmp(mem+5,xilstring, nLen) == 0, "Got result %s\n",mem+5); - /* Test _swab function */ + /* run tolower tests first */ + test_tolower(); test_swab(); - - /* Test ismbblead*/ test_mbcp(); - /* test _mbsspn */ test_mbsspn(); test_mbsspnp(); - /* test _strdup */ test_strdup(); test_strcpy_s(); test_memcpy_s(); @@ -2450,6 +2744,7 @@ START_TEST(string) test_mbctombb(); test_ismbclegal(); test_strtok(); + test__mbstok(); test_wcscpy_s(); test__wcsupr_s(); test_strtol(); @@ -2468,5 +2763,9 @@ START_TEST(string) test__mbslwr_s(); test_wctob(); test_wctomb(); - test_tolower(); + test__atodbl(); + test__stricmp(); + test__wcstoi64(); + test_atoi(); + test_strncpy(); } diff --git a/rostests/winetests/msvcrt/testlist.c b/rostests/winetests/msvcrt/testlist.c index a4d020fe124..7a62c633441 100644 --- a/rostests/winetests/msvcrt/testlist.c +++ b/rostests/winetests/msvcrt/testlist.c @@ -1,10 +1,7 @@ /* Automatically generated file; DO NOT EDIT!! */ -#define WIN32_LEAN_AND_MEAN -#include - #define STANDALONE -#include "wine/test.h" +#include extern void func_cpp(void); extern void func_data(void); diff --git a/rostests/winetests/msvcrt/time.c b/rostests/winetests/msvcrt/time.c index c6e2a9cd31a..71e58bac69c 100644 --- a/rostests/winetests/msvcrt/time.c +++ b/rostests/winetests/msvcrt/time.c @@ -46,13 +46,15 @@ static errno_t (__cdecl *p_localtime32_s)(struct tm*, __time32_t*); static errno_t (__cdecl *p_localtime64_s)(struct tm*, __time64_t*); static int* (__cdecl *p__daylight)(void); static int* (__cdecl *p___p__daylight)(void); +static long* (__cdecl *p___p__dstbias)(void); +static long* (__cdecl *p___p__timezone)(void); static size_t (__cdecl *p_strftime)(char *, size_t, const char *, const struct tm *); static size_t (__cdecl *p_wcsftime)(wchar_t *, size_t, const wchar_t *, const struct tm *); static char* (__cdecl *p_asctime)(const struct tm *); static void init(void) { - HMODULE hmod = LoadLibrary("msvcrt.dll"); + HMODULE hmod = LoadLibraryA("msvcrt.dll"); p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32"); p_gmtime = (void*)GetProcAddress(hmod, "gmtime"); @@ -64,6 +66,8 @@ static void init(void) p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s"); p__daylight = (void*)GetProcAddress(hmod, "__daylight"); p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight"); + p___p__dstbias = (void*)GetProcAddress(hmod, "__p__dstbias"); + p___p__timezone = (void*)GetProcAddress(hmod, "__p__timezone"); p_strftime = (void*)GetProcAddress(hmod, "strftime"); p_wcsftime = (void*)GetProcAddress(hmod, "wcsftime"); p_asctime = (void*)GetProcAddress(hmod, "asctime"); @@ -105,7 +109,7 @@ static void test_gmtime(void) gmt = -1; gmt_tm = p_gmtime32(&gmt); - ok(gmt_tm == NULL, "gmt_tm != NULL\n"); + ok(gmt_tm==NULL || broken(gmt_tm->tm_year==70 && gmt_tm->tm_sec<0), "gmt_tm != NULL\n"); gmt = valid = 0; gmt_tm = p_gmtime32(&gmt); @@ -177,9 +181,12 @@ static void test_gmtime(void) errno = 0; gmt = -1; err = p_gmtime32_s(&gmt_tm_s, &gmt); - ok(err == EINVAL, "err = %d\n", err); - ok(errno == EINVAL, "errno = %d\n", errno); - ok(gmt_tm_s.tm_year == -1, "tm_year = %d\n", gmt_tm_s.tm_year); + ok(gmt_tm_s.tm_year == -1 || broken(gmt_tm_s.tm_year == 70 && gmt_tm_s.tm_sec < 0), + "tm_year = %d, tm_sec = %d\n", gmt_tm_s.tm_year, gmt_tm_s.tm_sec); + if(gmt_tm_s.tm_year == -1) { + ok(err==EINVAL, "err = %d\n", err); + ok(errno==EINVAL, "errno = %d\n", errno); + } } static void test_mktime(void) @@ -804,10 +811,68 @@ static void test_asctime(void) ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); } +static void test__tzset(void) +{ + char TZ_env[256]; + int ret; + + if(!p___p__daylight || !p___p__timezone || !p___p__dstbias) { + win_skip("__p__daylight, __p__timezone or __p__dstbias is not available\n"); + return; + } + + _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); + + ret = *p___p__daylight(); + ok(ret == 1, "*__p__daylight() = %d\n", ret); + ret = *p___p__timezone(); + ok(ret == 28800, "*__p__timezone() = %d\n", ret); + ret = *p___p__dstbias(); + ok(ret == -3600, "*__p__dstbias() = %d\n", ret); + + _putenv("TZ=xxx+1yyy"); + _tzset(); + ret = *p___p__daylight(); + ok(ret == 121, "*__p__daylight() = %d\n", ret); + ret = *p___p__timezone(); + ok(ret == 3600, "*__p__timezone() = %d\n", ret); + ret = *p___p__dstbias(); + ok(ret == -3600, "*__p__dstbias() = %d\n", ret); + + *p___p__dstbias() = 0; + _putenv("TZ=xxx+1:3:5zzz"); + _tzset(); + ret = *p___p__daylight(); + ok(ret == 122, "*__p__daylight() = %d\n", ret); + ret = *p___p__timezone(); + ok(ret == 3785, "*__p__timezone() = %d\n", ret); + ret = *p___p__dstbias(); + ok(ret == 0, "*__p__dstbias() = %d\n", ret); + + _putenv(TZ_env); +} + +static void test_clock(void) +{ + static const int THRESH = 50; + clock_t s, e; + int i; + + for (i = 0; i < 10; i++) + { + s = clock(); + Sleep(1000); + e = clock(); + + ok(abs((e-s) - 1000) < THRESH, "clock off on loop %i: %i\n", i, e-s); + } +} + START_TEST(time) { init(); + test__tzset(); test_strftime(); test_ctime(); test_gmtime(); @@ -821,4 +886,5 @@ START_TEST(time) test_localtime64_s(); test_daylight(); test_asctime(); + test_clock(); }