diff --git a/modules/rostests/winetests/msvcrt/CMakeLists.txt b/modules/rostests/winetests/msvcrt/CMakeLists.txt index 53cb3a0067c..8ee88854dc9 100644 --- a/modules/rostests/winetests/msvcrt/CMakeLists.txt +++ b/modules/rostests/winetests/msvcrt/CMakeLists.txt @@ -1,4 +1,6 @@ +remove_definitions(-D_CRT_NON_CONFORMING_SWPRINTFS) + list(APPEND SOURCE cpp.c data.c @@ -15,7 +17,7 @@ list(APPEND SOURCE time.c) list(APPEND PCH_SKIP_SOURCE - printf.c # _CRT_NON_CONFORMING_SWPRINTFS + printf.c testlist.c) add_executable(msvcrt_winetest @@ -25,6 +27,8 @@ add_executable(msvcrt_winetest target_compile_definitions(msvcrt_winetest PRIVATE WINETEST_USE_DBGSTR_LONGLONG _CRT_NONSTDC_NO_DEPRECATE + _USE_MATH_DEFINES + WIN32_NO_STATUS= __msvcrt_ulong=ULONG) if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") @@ -34,13 +38,14 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") endif() endif() -set_module_type(msvcrt_winetest win32cui) -add_importlibs(msvcrt_winetest advapi32 msvcrt kernel32) -target_link_libraries(msvcrt_winetest oldnames) - if(MSVC) - add_importlibs(msvcrt_winetest ntdll) + # 'swscanf' : unknown type field character '\xe1' in format specifier + target_compile_options(msvcrt_winetest PRIVATE /wd4476) endif() +set_module_type(msvcrt_winetest win32cui) +add_importlibs(msvcrt_winetest advapi32 msvcrt kernel32 ntdll) +target_link_libraries(msvcrt_winetest oldnames) + add_pch(msvcrt_winetest precomp.h "${PCH_SKIP_SOURCE}") add_rostests_file(TARGET msvcrt_winetest) diff --git a/modules/rostests/winetests/msvcrt/cpp.c b/modules/rostests/winetests/msvcrt/cpp.c index 07b49ae755d..bfc092e0591 100644 --- a/modules/rostests/winetests/msvcrt/cpp.c +++ b/modules/rostests/winetests/msvcrt/cpp.c @@ -44,12 +44,8 @@ typedef struct __type_info #endif /* Function pointers. We need to use these to call these funcs as __thiscall */ -static HMODULE hMsvcrt; - -static void* (__cdecl *poperator_new)(unsigned int); +static void* (__cdecl *poperator_new)(size_t); static void (__cdecl *poperator_delete)(void*); -static void* (__cdecl *pmalloc)(unsigned int); -static void (__cdecl *pfree)(void*); /* exception */ static void (__thiscall *pexception_ctor)(exception*,LPCSTR*); @@ -112,9 +108,6 @@ static void* (__cdecl *p__RTDynamicCast)(void*,int,void*,void*,int); static char* (__cdecl *p__unDName)(char*,const char*,int,void*,void*,unsigned short int); -/* _very_ early native versions have serious RTTI bugs, so we check */ -static void* bAncientVersion; - /* Emulate a __thiscall */ #ifdef __i386__ @@ -157,23 +150,12 @@ static void init_thiscall_thunk(void) #endif /* __i386__ */ /* Some exports are only available in later versions */ -#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y) +#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hmsvcrt,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) static BOOL InitFunctionPtrs(void) { - hMsvcrt = GetModuleHandleA("msvcrt.dll"); - if (!hMsvcrt) - hMsvcrt = GetModuleHandleA("msvcrtd.dll"); - ok(hMsvcrt != 0, "GetModuleHandleA failed\n"); - if (!hMsvcrt) - { - win_skip("Could not load msvcrt.dll\n"); - return FALSE; - } - - SET(pmalloc, "malloc"); - SET(pfree, "free"); + HMODULE hmsvcrt = GetModuleHandleA("msvcrt.dll"); SET(pexception_vtable, "??_7exception@@6B@"); SET(pbad_typeid_vtable, "??_7bad_typeid@@6B@"); @@ -187,7 +169,6 @@ static BOOL InitFunctionPtrs(void) SET(p__unDName,"__unDName"); /* Extremely early versions export logic_error, and crash in RTTI */ - SETNOFAIL(bAncientVersion, "??0logic_error@@QAE@ABQBD@Z"); if (sizeof(void *) > sizeof(int)) /* 64-bit initialization */ { SETNOFAIL(poperator_new, "??_U@YAPEAX_K@Z"); @@ -242,50 +223,50 @@ static BOOL InitFunctionPtrs(void) 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(pexception_ctor, "??0exception@@QAA@ABQBD@Z"); + SET(pexception_copy_ctor, "??0exception@@QAA@ABV0@@Z"); + SET(pexception_default_ctor, "??0exception@@QAA@XZ"); + SET(pexception_dtor, "??1exception@@UAA@XZ"); + SET(pexception_opequals, "??4exception@@QAAAAV0@ABV0@@Z"); + SET(pexception_what, "?what@exception@@UBAPBDXZ"); + pexception_vector_dtor = (void*)pexception_vtable[0]; + pexception_scalar_dtor = (void*)pexception_vtable[0]; - 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"); + SET(pbad_typeid_ctor, "??0bad_typeid@@QAA@PBD@Z"); + SETNOFAIL(pbad_typeid_ctor_closure, "??_Fbad_typeid@@QAAXXZ"); + SET(pbad_typeid_copy_ctor, "??0bad_typeid@@QAA@ABV0@@Z"); + SET(pbad_typeid_dtor, "??1bad_typeid@@UAA@XZ"); + SET(pbad_typeid_opequals, "??4bad_typeid@@QAAAAV0@ABV0@@Z"); + SET(pbad_typeid_what, "?what@exception@@UBAPBDXZ"); + pbad_typeid_vector_dtor = (void*)pbad_typeid_vtable[0]; + pbad_typeid_scalar_dtor = (void*)pbad_typeid_vtable[0]; 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(pbad_cast_ctor, "??0bad_cast@@AAA@PBQBD@Z"); + SETNOFAIL(pbad_cast_ctor2, "??0bad_cast@@QAA@PBD@Z"); + SETNOFAIL(pbad_cast_ctor_closure, "??_Fbad_cast@@QAAXXZ"); + SET(pbad_cast_copy_ctor, "??0bad_cast@@QAA@ABV0@@Z"); + SET(pbad_cast_dtor, "??1bad_cast@@UAA@XZ"); + SET(pbad_cast_opequals, "??4bad_cast@@QAAAAV0@ABV0@@Z"); + SET(pbad_cast_what, "?what@exception@@UBAPBDXZ"); + pbad_cast_vector_dtor = (void*)pbad_cast_vtable[0]; + pbad_cast_scalar_dtor = (void*)pbad_cast_vtable[0]; - 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(p__non_rtti_object_ctor, "??0__non_rtti_object@@QAA@PBD@Z"); + SET(p__non_rtti_object_copy_ctor, "??0__non_rtti_object@@QAA@ABV0@@Z"); + SET(p__non_rtti_object_dtor, "??1__non_rtti_object@@UAA@XZ"); + SET(p__non_rtti_object_opequals, "??4__non_rtti_object@@QAAAAV0@ABV0@@Z"); + SET(p__non_rtti_object_what, "?what@exception@@UBAPBDXZ"); + p__non_rtti_object_vector_dtor = (void*)p__non_rtti_object_vtable[0]; + p__non_rtti_object_scalar_dtor = (void*)p__non_rtti_object_vtable[0]; 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"); + SET(ptype_info_name, "?name@type_info@@QBAPBDXZ"); + SET(ptype_info_before, "?before@type_info@@QBAHABV1@@Z"); + SET(ptype_info_opequals_equals, "??8type_info@@QBAHABV0@@Z"); + SET(ptype_info_opnot_equals, "??9type_info@@QBAHABV0@@Z"); #else SETNOFAIL(poperator_new, "??_U@YAPAXI@Z"); SETNOFAIL(poperator_delete, "??_V@YAXPAX@Z"); @@ -338,9 +319,9 @@ static BOOL InitFunctionPtrs(void) } if (!poperator_new) - poperator_new = pmalloc; + poperator_new = malloc; if (!poperator_delete) - poperator_delete = pfree; + poperator_delete = free; init_thiscall_thunk(); return TRUE; @@ -448,7 +429,7 @@ static void test_exception(void) name = call_func1(pexception_what, &e); ok(e.name == name, "Bad exception name from vtable e::what()\n"); - if (p__RTtypeid && !bAncientVersion) + if (p__RTtypeid) { /* Check the rtti */ type_info *ti = p__RTtypeid(&e); @@ -571,7 +552,7 @@ static void test_bad_typeid(void) name = call_func1(pbad_typeid_what, &e); ok(e.name == name, "Bad bad_typeid name from vtable e::what()\n"); - if (p__RTtypeid && !bAncientVersion) + if (p__RTtypeid) { /* Check the rtti */ type_info *ti = p__RTtypeid(&e); @@ -699,7 +680,7 @@ static void test_bad_cast(void) name = call_func1(pbad_cast_what, &e); ok(e.name == name, "Bad bad_cast name from vtable e::what()\n"); - if (p__RTtypeid && !bAncientVersion) + if (p__RTtypeid) { /* Check the rtti */ type_info *ti = p__RTtypeid(&e); @@ -801,7 +782,7 @@ static void test___non_rtti_object(void) name = call_func1(p__non_rtti_object_what, &e); ok(e.name == name, "Bad __non_rtti_object name from vtable e::what()\n"); - if (p__RTtypeid && !bAncientVersion) + if (p__RTtypeid) { /* Check the rtti */ type_info *ti = p__RTtypeid(&e); @@ -818,14 +799,14 @@ static void test_type_info(void) char* name; int res; - if (!pmalloc || !pfree || !ptype_info_dtor || !ptype_info_raw_name || + if (!ptype_info_dtor || !ptype_info_raw_name || !ptype_info_name || !ptype_info_before || !ptype_info_opequals_equals || !ptype_info_opnot_equals) return; /* Test calling the dtors */ call_func1(ptype_info_dtor, &t1); /* No effect, since name is NULL */ - t1.name = pmalloc(64); + t1.name = malloc(64); strcpy(t1.name, "foo"); call_func1(ptype_info_dtor, &t1); /* Frees t1.name using 'free' */ @@ -888,7 +869,7 @@ static inline void/*rtti_object_locator*/ *get_obj_locator( void *cppobj ) return (void *)vtable[-1]; } -#ifndef __x86_64__ +#ifdef __i386__ #define DEFINE_RTTI_REF(type, name) type *name #define RTTI_REF(instance, name) &instance.name #define RTTI_REF_SIG0(instance, name, base) RTTI_REF(instance, name) @@ -910,33 +891,36 @@ static void test_rtti(void) DEFINE_RTTI_REF(void, object_locator); } *obj_locator; + struct _rtti_base_descriptor + { + DEFINE_RTTI_REF(type_info, type_descriptor); + int num_base_classes; + struct { + int this_offset; + int vbase_descr; + int vbase_offset; + } this_ptr_offsets; + unsigned int attributes; + }; + + struct _rtti_base_array { + DEFINE_RTTI_REF(struct _rtti_base_descriptor, bases[4]); + }; + + struct _rtti_object_hierarchy { + unsigned int signature; + unsigned int attributes; + int array_len; + DEFINE_RTTI_REF(struct _rtti_base_array, base_classes); + }; + struct rtti_data { type_info type_info[4]; - struct _rtti_base_descriptor - { - DEFINE_RTTI_REF(type_info, type_descriptor); - int num_base_classes; - struct { - int this_offset; - int vbase_descr; - int vbase_offset; - } this_ptr_offsets; - unsigned int attributes; - } base_descriptor[4]; - - struct _rtti_base_array { - DEFINE_RTTI_REF(struct _rtti_base_descriptor, bases[4]); - } base_array; - - struct _rtti_object_hierarchy { - unsigned int signature; - unsigned int attributes; - int array_len; - DEFINE_RTTI_REF(struct _rtti_base_array, base_classes); - } object_hierarchy; - + struct _rtti_base_descriptor base_descriptor[4]; + struct _rtti_base_array base_array; + struct _rtti_object_hierarchy object_hierarchy; struct _object_locator object_locator; } simple_class_rtti = { { {NULL, NULL, "simple_class"} }, @@ -962,11 +946,17 @@ static void test_rtti(void) void *simple_class_vtbl[2] = {&simple_class_rtti.object_locator}; void *simple_class = &simple_class_vtbl[1]; void *child_class_vtbl[2] = {&child_class_rtti.object_locator}; - void *child_class = &child_class_vtbl[1]; + struct { + void *vtbl; + char data[4]; + } child_class = { &child_class_vtbl[1] }; void *simple_class_sig0_vtbl[2] = {&simple_class_sig0_rtti.object_locator}; 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]; + struct { + void *vtbl; + char data[4]; + } 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}; struct { @@ -980,12 +970,11 @@ static void test_rtti(void) exception e,b; void *casted; BOOL old_signature; -#ifdef __x86_64__ +#ifndef __i386__ char *base = (char*)GetModuleHandleW(NULL); #endif - if (bAncientVersion || - !p__RTCastToVoid || !p__RTtypeid || !pexception_ctor || !pbad_typeid_ctor + if (!p__RTCastToVoid || !p__RTtypeid || !pexception_ctor || !pbad_typeid_ctor || !p__RTDynamicCast || !pexception_dtor || !pbad_typeid_dtor) return; @@ -1099,46 +1088,32 @@ static void test_demangle_datatype(void) { char * name; struct _demangle demangle[]={ -/* { "BlaBla"," ?? ::Bla", FALSE}, */ - { "ABVVec4@ref2@dice@@","class dice::ref2::Vec4 const &",TRUE}, - { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0H@@@", "class CDB_GEN_BIG_ENUM_FLAG", TRUE}, - { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HO@@@", "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, - { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HOA@@@", "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, - { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HOAA@@@", "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, - { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$01@@@", "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$01@@@", FALSE}, -/* { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$011@@@", "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$011@@@",FALSE}, */ + { "BlaBla"," ?? ::Bla", FALSE}, + { "ABVVec4@ref2@dice@@", "class dice::ref2::Vec4 const &", TRUE}, + { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0H@@@", + "class CDB_GEN_BIG_ENUM_FLAG", TRUE}, + { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HO@@@", + "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, + { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HOA@@@", + "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, + { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$0HOAA@@@", + "class CDB_GEN_BIG_ENUM_FLAG",TRUE}, + { "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$01@@@", + "?AV?$CDB_GEN_BIG_ENUM_FLAG@W4CDB_WYSIWYG_BITS_ENUM@@$01@@@", FALSE}, + { "P8test@@AACXZ", "signed char (__cdecl test::*)(void)", TRUE}, + { "P8test@@BACXZ", "signed char (__cdecl test::*)(void)const ", TRUE}, }; int i, num_test = ARRAY_SIZE(demangle); for (i = 0; i < num_test; i++) { - name = p__unDName(0, demangle[i].mangled, 0, pmalloc, pfree, 0x2800); + name = p__unDName(0, demangle[i].mangled, 0, malloc, free, 0x2800); todo_wine_if (!demangle[i].test_in_wine) ok(name != NULL && !strcmp(name,demangle[i].result), "Got name \"%s\" for %d\n", name, i); - if(name) - pfree(name); + free(name); } } -/* Compare two strings treating multiple spaces (' ', ascii 0x20) in s2 - as single space. Needed for test_demangle as __unDName() returns sometimes - two spaces instead of one in some older native msvcrt dlls. */ -static int strcmp_space(const char *s1, const char *s2) -{ - const char* s2start = s2; - do { - while (*s1 == *s2 && *s1) { - s1++; - s2++; - } - if (*s2 == ' ' && s2 > s2start && *(s2 - 1) == ' ') - s2++; - else - break; - } while (*s1 && *s2); - return *s1 - *s2; -} - static void test_demangle(void) { static struct {const char* in; const char* out; const char *broken; unsigned int flags;} test[] = { @@ -1202,7 +1177,7 @@ static void test_demangle(void) /* 23 */ {"??0streambuf@@QAE@ABV0@@Z", "public: __thiscall streambuf::streambuf(class streambuf const &)"}, /* 24 */ {"??0strstreambuf@@QAE@ABV0@@Z", "public: __thiscall strstreambuf::strstreambuf(class strstreambuf const &)"}, /* 25 */ {"??0strstreambuf@@QAE@H@Z", "public: __thiscall strstreambuf::strstreambuf(int)"}, -/* 26 */ {"??0strstreambuf@@QAE@P6APAXJ@ZP6AXPAX@Z@Z", "public: __thiscall strstreambuf::strstreambuf(void * (__cdecl*)(long),void (__cdecl*)(void *))"}, +/* 26 */ {"??0strstreambuf@@QAE@Q6APAXJ@ZS6AXPAX@Z@Z", "public: __thiscall strstreambuf::strstreambuf(void * (__cdecl*const)(long),void (__cdecl*const volatile)(void *))"}, /* 27 */ {"??0strstreambuf@@QAE@PADH0@Z", "public: __thiscall strstreambuf::strstreambuf(char *,int,char *)"}, /* 28 */ {"??0strstreambuf@@QAE@PAEH0@Z", "public: __thiscall strstreambuf::strstreambuf(unsigned char *,int,unsigned char *)"}, /* 29 */ {"??0strstreambuf@@QAE@XZ", "public: __thiscall strstreambuf::strstreambuf(void)"}, @@ -1237,7 +1212,7 @@ static void test_demangle(void) /* 58 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAJ@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,long &)const "}, /* 59 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAK@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned long &)const "}, /* 60 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAM@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,float &)const "}, -/* 61 */ {"?_query_new_handler@@YAP6AHI@ZXZ", "int (__cdecl*__cdecl _query_new_handler(void))(unsigned int)"}, +/* 61 */ {"?_query_new_handler@@YAR6AHI@ZXZ", "int (__cdecl*__cdecl _query_new_handler(void))(unsigned int)"}, /* 62 */ {"?register_callback@ios_base@std@@QAEXP6AXW4event@12@AAV12@H@ZH@Z", "public: void __thiscall std::ios_base::register_callback(void (__cdecl*)(enum std::ios_base::event,class std::ios_base &,int),int)"}, /* 63 */ {"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@JW4seekdir@ios_base@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(long,enum std::ios_base::seekdir)"}, /* 64 */ {"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@V?$fpos@H@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(class std::fpos)"}, @@ -1325,22 +1300,54 @@ static void test_demangle(void) "??$run@XVTask_Render_Preview@@@QtConcurrent@@YA?AV?$QFuture@X@@PEAVTask_Render_Preview@@P82@EAAXXZ@Z"}, /* 130 */ {"??_E?$TStrArray@$$BY0BAA@D$0BA@@@UAEPAXI@Z", "public: virtual void * __thiscall TStrArray::`vector deleting destructor'(unsigned int)"}, +/* 131 */ {"??_R0?AVCC@DD@@@8", "class DD::CC `RTTI Type Descriptor'"}, +/* 132 */ {"??$meth@FD@DD@CC@@QAE_NK@Z", "public: bool __thiscall CC::DD::meth(unsigned long)"}, +/* 133 */ {"?func@@YAXPIFAH@Z", "void __cdecl func(int __unaligned * __restrict)"}, +/* 135 */ {"?x@@3PAY02HA", "int (* x)[3]"}, +/* 136 */ {"?Qux@Bar@@0PAPAP6AHPAV1@AAH1PAH@ZA", + "private: static int (__cdecl** * Bar::Qux)(class Bar *,int &,int &,int *)"}, /* variation of 105: note white space handling! */ +/* 137 */ {"?x@@3PAW4myenum@@A", "enum myenum * x"}, +/* 138 */ {"?pfunc@@3PAY0E@P6AXF@ZA", "void (__cdecl*(* pfunc)[4])(short)"}, +/* 139 */ {"??$?0AEAVzzz@BB4@AA@@AEAV012@$0A@@?$pair@Vzzz@BB4@AA@@V123@@std@@QEAA@AEAVzzz@BB4@AA@@0@Z", + "public: __cdecl std::pair::pair(class AA::BB4::zzz & __ptr64,class AA::BB4::zzz & __ptr64) __ptr64"}, +/* 140 */ {"??$?BH@?$foo@N@@QEAAHXZ", "public: __cdecl foo::operator int(void) __ptr64"}, +/* 141 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"}, +/* 142 */ {"??Bcastop@@QAE?BHXZ", "public: __thiscall castop::operator int const (void)"}, +/* 143 */ {"?pfield@@3PTAA@@DT1@", "char const volatile AA::* const volatile pfield"}, +/* 144 */ {"?ptititi1@@3PEQtititi@@IEQ1@", "unsigned int tititi::* __ptr64 __ptr64 ptititi1"}, +/* 145 */ {"?ptititi2@@3PERtititi@@IER1@", "unsigned int const tititi::* __ptr64 const __ptr64 ptititi2"}, +/* 146 */ {"?ptititi3@@3PEStititi@@IES1@", "unsigned int volatile tititi::* __ptr64 volatile __ptr64 ptititi3"}, +/* 147 */ {"?ptititi4@@3PETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4"}, +/* 148 */ {"?ptititi4v@@3RETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4v"}, +/* 149 */ {"?meth@AAA@@QFCEXXZ", "public: void __thiscall AAA::meth(void)volatile __unaligned "}, +/* 150 */ {"?RegisterModuleUninitializer@@@YAXP$AAVEventHandler@System@@@Z", + "void __cdecl ::RegisterModuleUninitializer(class System::EventHandler ^)"}, +/* 151 */ {"?RegisterModuleUninitializer@@@YAXBE$AAVEventHandler@System@@@Z", + "void __cdecl ::RegisterModuleUninitializer(class System::EventHandler % __ptr64 volatile)"}, +/* 152 */ {"??$forward@AEAUFFIValue@?1??call@FFIFunctionBinder@@CAHPEAUlua_State@@@Z@@std@@YAAEAUFFIValue@?1??call@" + "FFIFunctionBinder@@CAHPEAUxlua_State@@@Z@AEAU1?1??23@CAH0@Z@@Z", + "struct `private: static int __cdecl FFIFunctionBinder::call(struct xlua_State * __ptr64)'::`2'::FFIValue & " + "__ptr64 __cdecl std::forward(struct `private: static int __cdecl FFIFunctionBinder::call(struct " + "xlua_State * __ptr64)'::`2'::FFIValue & __ptr64)"}, +/* 153 */ {"?$AAA@XX", "AAA"}, +/* 154 */ {"?$AAA@", "AAA<>"}, }; - int i, num_test = ARRAY_SIZE(test); + int i; char* name; - for (i = 0; i < num_test; i++) + for (i = 0; i < ARRAY_SIZE(test); i++) { - name = p__unDName(0, test[i].in, 0, pmalloc, pfree, test[i].flags); + name = p__unDName(0, test[i].in, 0, malloc, free, test[i].flags); ok(name != NULL, "%u: unDName failed\n", i); if (!name) continue; - ok( !strcmp_space(test[i].out, name) || - broken(test[i].broken && !strcmp_space(test[i].broken, name)), + ok( !strcmp(test[i].out, name) || + broken(test[i].broken && !strcmp(test[i].broken, name)), "%u: Got name \"%s\"\n", i, name ); - ok( !strcmp_space(test[i].out, name) || - broken(test[i].broken && !strcmp_space(test[i].broken, name)), + ok( !strcmp(test[i].out, name) || + broken(test[i].broken && !strcmp(test[i].broken, name)), "%u: Expected \"%s\"\n", i, test[i].out ); - pfree(name); + free(name); } } diff --git a/modules/rostests/winetests/msvcrt/data.c b/modules/rostests/winetests/msvcrt/data.c index b0acc60b20b..b78bc4f7029 100644 --- a/modules/rostests/winetests/msvcrt/data.c +++ b/modules/rostests/winetests/msvcrt/data.c @@ -32,7 +32,11 @@ #include #include -void __cdecl __getmainargs(int *, char ***, char ***, int, int *); +#ifdef __REACTOS__ +_CRTIMP void __cdecl __getmainargs(int *, char ***, char ***, int, int *); +_CRTIMP void __cdecl __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *); +#endif + static int* (__cdecl *p___p___argc)(void); static char*** (__cdecl *p___p___argv)(void); @@ -92,12 +96,12 @@ static void test_initvar( HMODULE hmsvcrt ) winminor = *pp_winminor; winmajor = *pp_winmajor; GetVersionExA( &osvi); - ok( winminor == osvi.dwMinorVersion, "Wrong value for _winminor %02x expected %02x\n", + ok( winminor == osvi.dwMinorVersion, "Wrong value for _winminor %02x expected %02lx\n", winminor, osvi.dwMinorVersion); - ok( winmajor == osvi.dwMajorVersion, "Wrong value for _winmajor %02x expected %02x\n", + ok( winmajor == osvi.dwMajorVersion, "Wrong value for _winmajor %02x expected %02lx\n", winmajor, osvi.dwMajorVersion); ok( winver == ((osvi.dwMajorVersion << 8) | osvi.dwMinorVersion), - "Wrong value for _winver %02x expected %02x\n", + "Wrong value for _winver %02x expected %02lx\n", winver, ((osvi.dwMajorVersion << 8) | osvi.dwMinorVersion)); if( !pp_osver || !pp_osplatform ) { win_skip("_osver variables are not available\n"); @@ -108,10 +112,10 @@ static void test_initvar( HMODULE hmsvcrt ) ok( osver == (osvi.dwBuildNumber & 0xffff) || ((osvi.dwBuildNumber >> 24) == osvi.dwMajorVersion && ((osvi.dwBuildNumber >> 16) & 0xff) == osvi.dwMinorVersion), /* 95/98/ME */ - "Wrong value for _osver %04x expected %04x\n", + "Wrong value for _osver %04x expected %04lx\n", osver, osvi.dwBuildNumber); ok(osplatform == osvi.dwPlatformId, - "Wrong value for _osplatform %x expected %x\n", + "Wrong value for _osplatform %x expected %lx\n", osplatform, osvi.dwPlatformId); } @@ -133,7 +137,7 @@ static void test___getmainargs(void) { int argc, new_argc, mode; char **argv, **new_argv, **envp; - char tmppath[MAX_PATH], filepath[MAX_PATH]; + char tmppath[MAX_PATH], filepath[MAX_PATH + 14]; FILE *f; ok(GetTempPathA(MAX_PATH, tmppath) != 0, "GetTempPath failed\n"); @@ -194,7 +198,7 @@ static void test___getmainargs(void) static void test___getmainargs_parent(char *name) { char cmdline[3*MAX_PATH]; - char tmppath[MAX_PATH], filepath[MAX_PATH]; + char tmppath[MAX_PATH], filepath[MAX_PATH + 14]; STARTUPINFOA startup; PROCESS_INFORMATION proc; FILE *f; @@ -218,7 +222,7 @@ static void test___getmainargs_parent(char *name) 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); + wait_child_process(proc.hProcess); _unlink(filepath); sprintf(filepath, "%swine_test\\a", tmppath); diff --git a/modules/rostests/winetests/msvcrt/dir.c b/modules/rostests/winetests/msvcrt/dir.c index 210cf3983cd..a2a704d85d3 100644 --- a/modules/rostests/winetests/msvcrt/dir.c +++ b/modules/rostests/winetests/msvcrt/dir.c @@ -138,36 +138,6 @@ static void test_makepath(void) } } -static const WCHAR expected0[] = {'\0','X','X','X','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected1[] = {'\0','X','X','X','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected2[] = {'\0',':','X','X','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected3[] = {'\0',':','d','X','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected4[] = {'\0',':','d','\\','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected5[] = {'\0',':','d','\\','f','X','X','X','X','X','X','X','X'}; -static const WCHAR expected6[] = {'\0',':','d','\\','f','i','X','X','X','X','X','X','X'}; -static const WCHAR expected7[] = {'\0',':','d','\\','f','i','l','X','X','X','X','X','X'}; -static const WCHAR expected8[] = {'\0',':','d','\\','f','i','l','e','X','X','X','X','X'}; -static const WCHAR expected9[] = {'\0',':','d','\\','f','i','l','e','.','X','X','X','X'}; -static const WCHAR expected10[] = {'\0',':','d','\\','f','i','l','e','.','e','X','X','X'}; -static const WCHAR expected11[] = {'\0',':','d','\\','f','i','l','e','.','e','x','X','X'}; - -static const WCHAR expected12[] = {'\0',':','X','X','X','X','X','X','X','X'}; -static const WCHAR expected13[] = {'\0',':','d','X','X','X','X','X','X','X'}; -static const WCHAR expected14[] = {'\0',':','d','i','X','X','X','X','X','X'}; -static const WCHAR expected15[] = {'\0',':','d','i','r','X','X','X','X','X'}; -static const WCHAR expected16[] = {'\0',':','d','i','r','\\','X','X','X','X'}; - -static const WCHAR expected17[] = {'\0','o','o'}; -static const WCHAR expected18[] = {'\0','o','o','\0','X'}; -static const WCHAR expected19[] = {'\0','o','o','\0'}; -static const WCHAR expected20[] = {'\0','o','o','\0','X','X','X','X','X'}; -static const WCHAR expected21[] = {'\0','o','o','\\','f','i','l','X','X'}; -static const WCHAR expected22[] = {'\0','o','o','\0','X','X','X','X','X','X','X','X','X'}; -static const WCHAR expected23[] = {'\0','o','o','\\','f','i','l','X','X','X','X','X','X'}; -static const WCHAR expected24[] = {'\0','o','o','\\','f','i','l','e','.','e','x','X','X'}; -static const WCHAR expected25[] = {'\0','o','o','\0','X','X','X','X'}; -static const WCHAR expected26[] = {'\0','o','o','.','e','x','X','X'}; - typedef struct { const char* buffer; @@ -184,35 +154,35 @@ typedef struct static const makepath_s_case makepath_s_cases[] = { /* Behavior with directory parameter containing backslash. */ - {NULL, 1, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", expected0, 13}, - {NULL, 2, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", expected1, 13}, - {NULL, 3, "c:", "d\\", "file", "ext", "\0:XXXXXXXXXXX", expected2, 13}, - {NULL, 4, "c:", "d\\", "file", "ext", "\0:dXXXXXXXXXX", expected3, 13}, - {NULL, 5, "c:", "d\\", "file", "ext", "\0:d\\XXXXXXXXX", expected4, 13}, - {NULL, 6, "c:", "d\\", "file", "ext", "\0:d\\fXXXXXXXX", expected5, 13}, - {NULL, 7, "c:", "d\\", "file", "ext", "\0:d\\fiXXXXXXX", expected6, 13}, - {NULL, 8, "c:", "d\\", "file", "ext", "\0:d\\filXXXXXX", expected7, 13}, - {NULL, 9, "c:", "d\\", "file", "ext", "\0:d\\fileXXXXX", expected8, 13}, - {NULL, 10, "c:", "d\\", "file", "ext", "\0:d\\file.XXXX", expected9, 13}, - {NULL, 11, "c:", "d\\", "file", "ext", "\0:d\\file.eXXX", expected10, 13}, - {NULL, 12, "c:", "d\\", "file", "ext", "\0:d\\file.exXX", expected11, 13}, + {NULL, 1, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", L"\0XXXXXXXXXXXX", 13}, + {NULL, 2, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", L"\0XXXXXXXXXXXX", 13}, + {NULL, 3, "c:", "d\\", "file", "ext", "\0:XXXXXXXXXXX", L"\0:XXXXXXXXXXX", 13}, + {NULL, 4, "c:", "d\\", "file", "ext", "\0:dXXXXXXXXXX", L"\0:dXXXXXXXXXX", 13}, + {NULL, 5, "c:", "d\\", "file", "ext", "\0:d\\XXXXXXXXX", L"\0:d\\XXXXXXXXX", 13}, + {NULL, 6, "c:", "d\\", "file", "ext", "\0:d\\fXXXXXXXX", L"\0:d\\fXXXXXXXX", 13}, + {NULL, 7, "c:", "d\\", "file", "ext", "\0:d\\fiXXXXXXX", L"\0:d\\fiXXXXXXX", 13}, + {NULL, 8, "c:", "d\\", "file", "ext", "\0:d\\filXXXXXX", L"\0:d\\filXXXXXX", 13}, + {NULL, 9, "c:", "d\\", "file", "ext", "\0:d\\fileXXXXX", L"\0:d\\fileXXXXX", 13}, + {NULL, 10, "c:", "d\\", "file", "ext", "\0:d\\file.XXXX", L"\0:d\\file.XXXX", 13}, + {NULL, 11, "c:", "d\\", "file", "ext", "\0:d\\file.eXXX", L"\0:d\\file.eXXX", 13}, + {NULL, 12, "c:", "d\\", "file", "ext", "\0:d\\file.exXX", L"\0:d\\file.exXX", 13}, /* Behavior with directory parameter lacking backslash. */ - {NULL, 3, "c:", "dir", "f", "ext", "\0:XXXXXXXX", expected12, 10}, - {NULL, 4, "c:", "dir", "f", "ext", "\0:dXXXXXXX", expected13, 10}, - {NULL, 5, "c:", "dir", "f", "ext", "\0:diXXXXXX", expected14, 10}, - {NULL, 6, "c:", "dir", "f", "ext", "\0:dirXXXXX", expected15, 10}, - {NULL, 7, "c:", "dir", "f", "ext", "\0:dir\\XXXX", expected16, 10}, + {NULL, 3, "c:", "dir", "f", "ext", "\0:XXXXXXXX", L"\0:XXXXXXXX", 10}, + {NULL, 4, "c:", "dir", "f", "ext", "\0:dXXXXXXX", L"\0:dXXXXXXX", 10}, + {NULL, 5, "c:", "dir", "f", "ext", "\0:diXXXXXX", L"\0:diXXXXXX", 10}, + {NULL, 6, "c:", "dir", "f", "ext", "\0:dirXXXXX", L"\0:dirXXXXX", 10}, + {NULL, 7, "c:", "dir", "f", "ext", "\0:dir\\XXXX", L"\0:dir\\XXXX", 10}, /* Behavior with overlapped buffer. */ - {"foo", 2, USE_BUFF, NULL, NULL, NULL, "\0oo", expected17, 3}, - {"foo", 4, NULL, USE_BUFF, NULL, NULL, "\0oo\0X", expected18, 5}, - {"foo", 3, NULL, NULL, USE_BUFF, NULL, "\0oo\0", expected19, 4}, - {"foo", 4, NULL, USE_BUFF, "file", NULL, "\0oo\0XXXXX", expected20, 9}, - {"foo", 8, NULL, USE_BUFF, "file", NULL, "\0oo\\filXX", expected21, 9}, - {"foo", 4, NULL, USE_BUFF, "file", "ext", "\0oo\0XXXXXXXXX", expected22, 13}, - {"foo", 8, NULL, USE_BUFF, "file", "ext", "\0oo\\filXXXXXX", expected23, 13}, - {"foo", 12, NULL, USE_BUFF, "file", "ext", "\0oo\\file.exXX", expected24, 13}, - {"foo", 4, NULL, NULL, USE_BUFF, "ext", "\0oo\0XXXX", expected25, 8}, - {"foo", 7, NULL, NULL, USE_BUFF, "ext", "\0oo.exXX", expected26, 8}, + {"foo", 2, USE_BUFF, NULL, NULL, NULL, "\0oo", L"\0oo", 3}, + {"foo", 4, NULL, USE_BUFF, NULL, NULL, "\0oo\0X", L"\0oo\0X", 5}, + {"foo", 3, NULL, NULL, USE_BUFF, NULL, "\0oo\0", L"\0oo", 4}, + {"foo", 4, NULL, USE_BUFF, "file", NULL, "\0oo\0XXXXX", L"\0oo\0XXXXX", 9}, + {"foo", 8, NULL, USE_BUFF, "file", NULL, "\0oo\\filXX", L"\0oo\\filXX", 9}, + {"foo", 4, NULL, USE_BUFF, "file", "ext", "\0oo\0XXXXXXXXX", L"\0oo\0XXXXXXXXX", 13}, + {"foo", 8, NULL, USE_BUFF, "file", "ext", "\0oo\\filXXXXXX", L"\0oo\\filXXXXXX", 13}, + {"foo", 12, NULL, USE_BUFF, "file", "ext", "\0oo\\file.exXX", L"\0oo\\file.exXX", 13}, + {"foo", 4, NULL, NULL, USE_BUFF, "ext", "\0oo\0XXXX", L"\0oo\0XXXX", 8}, + {"foo", 7, NULL, NULL, USE_BUFF, "ext", "\0oo.exXX", L"\0oo.exXX", 8}, }; static void test_makepath_s(void) @@ -438,10 +408,6 @@ static void test_searchenv(void) "\\search_env_test\\dir3longer\\3.dat" }; - const WCHAR env_w[] = {'T','E','S','T','_','P','A','T','H',0}; - const WCHAR dat1_w[] = {'1','.','d','a','t',0}; - const WCHAR dat3_w[] = {'3','.','d','a','t',0}; - char env1[4*MAX_PATH], env2[4*MAX_PATH], tmppath[MAX_PATH], path[2*MAX_PATH]; char result[MAX_PATH], exp[2*MAX_PATH]; WCHAR result_w[MAX_PATH]; @@ -510,13 +476,13 @@ static void test_searchenv(void) } memset(result_w, 'x', sizeof(result_w)); - _wsearchenv(dat1_w, env_w, result_w); + _wsearchenv(L"1.dat", L"TEST_PATH", result_w); WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); if (p_wsearchenv_s) { memset(result_w, 'x', sizeof(result_w)); - i = p_wsearchenv_s(dat1_w, env_w, result_w, MAX_PATH); + i = p_wsearchenv_s(L"1.dat", L"TEST_PATH", result_w, MAX_PATH); ok(!i, "wsearchenv_s returned %d\n", i); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); } @@ -535,13 +501,13 @@ static void test_searchenv(void) } memset(result_w, 'x', sizeof(result_w)); - _wsearchenv(dat3_w, env_w, result_w); + _wsearchenv(L"3.dat", L"TEST_PATH", result_w); WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); if (p_wsearchenv_s) { memset(result_w, 'x', sizeof(result_w)); - i = p_wsearchenv_s(dat3_w, env_w, result_w, MAX_PATH); + i = p_wsearchenv_s(L"3.dat", L"TEST_PATH", result_w, MAX_PATH); ok(!i, "wsearchenv_s returned %d\n", i); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); } @@ -561,13 +527,13 @@ static void test_searchenv(void) } memset(result_w, 'x', sizeof(result_w)); - _wsearchenv(dat1_w, env_w, result_w); + _wsearchenv(L"1.dat", L"TEST_PATH", result_w); WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); if (p_wsearchenv_s) { memset(result_w, 'x', sizeof(result_w)); - i = p_wsearchenv_s(dat1_w, env_w, result_w, MAX_PATH); + i = p_wsearchenv_s(L"1.dat", L"TEST_PATH", result_w, MAX_PATH); ok(!i, "wsearchenv_s returned %d\n", i); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); } @@ -586,17 +552,31 @@ static void test_searchenv(void) } memset(result_w, 'x', sizeof(result_w)); - _wsearchenv(dat3_w, env_w, result_w); + _wsearchenv(L"3.dat", L"TEST_PATH", result_w); WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); if (p_wsearchenv_s) { memset(result_w, 'x', sizeof(result_w)); - i = p_wsearchenv_s(dat3_w, env_w, result_w, MAX_PATH); + i = p_wsearchenv_s(L"3.dat", L"TEST_PATH", result_w, MAX_PATH); ok(!i, "wsearchenv_s returned %d\n", i); ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); } + strcpy(env1, "TEST_PATH="); + strcat(env1, tmppath); + strcat(env1, "\"\\search_env_test\\\"d\"i\"r\"1"); + putenv(env1); + strcpy(exp, tmppath); + strcat(exp, files[0]); + _searchenv("1.dat", "TEST_PATH", result); + ok(!strcmp(result, exp), "got %s, expected '%s'\n", result, exp); + + strcat(env1, ";"); + putenv(env1); + _searchenv("1.dat", "TEST_PATH", result); + ok(!result[0], "got %s, expected ''\n", result); + putenv("TEST_PATH="); for (i=ARRAY_SIZE(files)-1; i>=0; i--) { diff --git a/modules/rostests/winetests/msvcrt/environ.c b/modules/rostests/winetests/msvcrt/environ.c index b8e0ae6251a..9951c5b1308 100644 --- a/modules/rostests/winetests/msvcrt/environ.c +++ b/modules/rostests/winetests/msvcrt/environ.c @@ -19,7 +19,15 @@ */ #include "wine/test.h" +#include #include +#include +#include + +#ifdef __REACTOS__ +_CRTIMP void __cdecl __getmainargs(int *, char ***, char ***, int, int *); +_CRTIMP void __cdecl __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *); +#endif static const char *a_very_long_env_string = "LIBRARY_PATH=" @@ -42,13 +50,15 @@ static const char *a_very_long_env_string = "/usr/lib/mingw32/3.4.2/;" "/usr/lib/"; -void __cdecl __getmainargs(int *, char ***, char ***, int, int *); -void __cdecl __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *); - static char ***(__cdecl *p__p__environ)(void); static WCHAR ***(__cdecl *p__p__wenviron)(void); -static void (*p_get_environ)(char ***); -static void (*p_get_wenviron)(WCHAR ***); +static char ***(__cdecl *p__p___initenv)(void); +static wchar_t ***(__cdecl *p__p___winitenv)(void); +static void (__cdecl *p_get_environ)(char ***); +static void (__cdecl *p_get_wenviron)(WCHAR ***); +static errno_t (__cdecl *p_putenv_s)(const char*, const char*); +static errno_t (__cdecl *p_wputenv_s)(const wchar_t*, const wchar_t*); +static errno_t (__cdecl *p_getenv_s)(size_t*, char*, size_t, const char*); static char ***p_environ; static WCHAR ***p_wenviron; @@ -59,10 +69,15 @@ static void init(void) p__p__environ = (void *)GetProcAddress(hmod, "__p__environ"); p__p__wenviron = (void *)GetProcAddress(hmod, "__p__wenviron"); + p__p___initenv = (void *)GetProcAddress(hmod, "__p___initenv"); + p__p___winitenv = (void *)GetProcAddress(hmod, "__p___winitenv"); p_environ = (void *)GetProcAddress(hmod, "_environ"); p_wenviron = (void *)GetProcAddress(hmod, "_wenviron"); p_get_environ = (void *)GetProcAddress(hmod, "_get_environ"); p_get_wenviron = (void *)GetProcAddress(hmod, "_get_wenviron"); + p_putenv_s = (void *)GetProcAddress(hmod, "_putenv_s"); + p_wputenv_s = (void *)GetProcAddress(hmod, "_wputenv_s"); + p_getenv_s = (void *)GetProcAddress(hmod, "getenv_s"); } static void test_system(void) @@ -74,30 +89,46 @@ static void test_system(void) ok(ret == 0, "Expected system to return 0, got %d\n", ret); } +static unsigned env_get_entry_countA( char **env ) +{ + unsigned count; + + if (!env) return 0; + for (count = 0; env[count] != NULL; count++) {} + return count; +} + +static wchar_t *env_get_valueW( wchar_t **envp, const wchar_t *var ) +{ + unsigned i; + size_t len = wcslen( var ); + + if (!envp) return NULL; + for (i = 0; envp[i] != NULL; i++) + { + wchar_t *ptr; + + if (!(ptr = wcschr( envp[i], L'=' ))) continue; + + if (ptr - envp[i] == len && !memcmp( envp[i], var, len * sizeof(wchar_t) )) + return ptr + 1; + } + return NULL; +} + static void test__environ(void) { int argc; - char **argv, **envp = NULL; - int i, mode = 0; + char **argv, **envp = NULL, **initenv = NULL; + int mode = 0; ok( p_environ != NULL, "Expected the pointer to _environ to be non-NULL\n" ); - if (p_environ) - ok( *p_environ != NULL, "Expected _environ to be initialized on startup\n" ); + ok( *p_environ != NULL, "Expected _environ to be initialized on startup\n" ); - if (!p_environ || !*p_environ) - { - skip( "_environ pointers are not valid\n" ); - return; - } - - /* Examine the returned pointer from __p__environ(), if available. */ - if (p__p__environ) - { - ok( *p__p__environ() == *p_environ, - "Expected _environ pointers to be identical\n" ); - } + if (sizeof(void*) != sizeof(int)) + ok( !p__p__environ, "__p__environ() should be 32-bit only\n"); else - skip( "__p__environ() is not available\n" ); + ok( *p__p__environ() == *p_environ, "Expected _environ pointers to be identical\n" ); if (p_get_environ) { @@ -109,76 +140,74 @@ static void test__environ(void) else win_skip( "_get_environ() is not available\n" ); + if (p__p___initenv) + { + initenv = *p__p___initenv(); + + ok( initenv == *p_environ, + "Expected _environ to be equal to initial env\n" ); + } + else + skip( "__p___initenv() is not available\n" ); + /* Note that msvcrt from Windows versions older than Vista * expects the mode pointer parameter to be valid.*/ __getmainargs(&argc, &argv, &envp, 0, &mode); - ok( envp != NULL, "Expected initial environment block pointer to be non-NULL\n" ); - if (!envp) - { - skip( "Initial environment block pointer is not valid\n" ); - return; - } + ok( envp != NULL, + "Expected initial environment block pointer to be non-NULL\n" ); + ok( envp == *p_environ, + "Expected initial environment to be equal to _environ\n" ); - for (i = 0; ; i++) + ok( _putenv("cat=dog") == 0, "failed setting cat=dog\n" ); + if (p__p___initenv) { - if ((*p_environ)[i]) - { - ok( envp[i] != NULL, "Expected environment block pointer element to be non-NULL\n" ); - ok( !strcmp((*p_environ)[i], envp[i]), - "Expected _environ and environment block pointer strings (%s vs. %s) to match\n", - (*p_environ)[i], envp[i] ); - } - else - { - ok( !envp[i], "Expected environment block pointer element to be NULL, got %p\n", envp[i] ); - break; - } + char **retptr = *p__p___initenv(); + + ok( retptr != *p_environ, + "Expected _environ[] not to be equal to initial env\n" ); + ok( retptr == initenv, + "Unexpected modification of initial env\n" ); } + ok( _putenv("cat=") == 0, "failed setting cat=\n" ); } static void test__wenviron(void) { - static const WCHAR cat_eq_dogW[] = {'c','a','t','=','d','o','g',0}; - static const WCHAR cat_eqW[] = {'c','a','t','=',0}; - int argc; char **argv, **envp = NULL; WCHAR **wargv, **wenvp = NULL; - int i, mode = 0; + int mode = 0; ok( p_wenviron != NULL, "Expected the pointer to _wenviron to be non-NULL\n" ); - if (p_wenviron) - ok( *p_wenviron == NULL, "Expected _wenviron to be NULL, got %p\n", *p_wenviron ); - else - { - win_skip( "Pointer to _wenviron is not valid\n" ); - return; - } + ok( !*p_wenviron, "Expected _wenviron[] to be NULL, got %p\n", *p_wenviron ); - /* Examine the returned pointer from __p__wenviron(), if available. */ - if (p__p__wenviron) - { - ok( *p__p__wenviron() == NULL, - "Expected _wenviron pointers to be NULL\n" ); - } + if (sizeof(void*) != sizeof(int)) + ok( !p__p__wenviron, "__p__wenviron() should be 32-bit only\n"); else - skip( "__p__wenviron() is not available\n" ); + ok( !*p__p__wenviron(), "Expected _wenviron to be NULL, got %p\n", *p_wenviron ); if (p_get_wenviron) { WCHAR **retptr; p_get_wenviron(&retptr); - ok( retptr == NULL, - "Expected _wenviron pointers to be NULL\n" ); + ok( retptr == *p_wenviron, "Expected _wenviron pointers to be NULL\n" ); } else win_skip( "_get_wenviron() is not available\n" ); + if (p__p___winitenv) + { + wchar_t ***retptr = p__p___winitenv(); + ok( !*retptr, "Expected initial env to be NULL\n" ); + } + else + skip( "__p___winitenv() is not available\n" ); + /* __getmainargs doesn't initialize _wenviron. */ __getmainargs(&argc, &argv, &envp, 0, &mode); - ok( *p_wenviron == NULL, "Expected _wenviron to be NULL, got %p\n", *p_wenviron); + ok( !*p_wenviron, "Expected _wenviron to be NULL\n"); ok( envp != NULL, "Expected initial environment block pointer to be non-NULL\n" ); if (!envp) { @@ -188,24 +217,31 @@ static void test__wenviron(void) /* Neither does calling the non-Unicode environment manipulation functions. */ ok( _putenv("cat=dog") == 0, "failed setting cat=dog\n" ); - ok( *p_wenviron == NULL, "Expected _wenviron to be NULL, got %p\n", *p_wenviron); - ok( _putenv("cat=") == 0, "failed deleting cat\n" ); + ok( !*p_wenviron, "Expected _wenviron to be NULL\n" ); /* _wenviron isn't initialized until __wgetmainargs is called or * one of the Unicode environment manipulation functions is called. */ - ok( _wputenv(cat_eq_dogW) == 0, "failed setting cat=dog\n" ); + ok( _wputenv(L"cat=dog2") == 0, "failed setting cat=dog2\n" ); ok( *p_wenviron != NULL, "Expected _wenviron to be non-NULL\n" ); - ok( _wputenv(cat_eqW) == 0, "failed deleting cat\n" ); __wgetmainargs(&argc, &wargv, &wenvp, 0, &mode); - - ok( *p_wenviron != NULL, "Expected _wenviron to be non-NULL\n" ); ok( wenvp != NULL, "Expected initial environment block pointer to be non-NULL\n" ); - if (!wenvp) + ok( wenvp == *p_wenviron, "Expected initial environment to be _wenviron[]\n" ); + + if (p__p___winitenv) { - skip( "Initial environment block pointer is not valid\n" ); - return; + wchar_t ***retptr = p__p___winitenv(); + wchar_t *value; + + ok( *retptr != NULL, "Expected *__p___winitenv() to be NULL\n" ); + ok( *retptr != *p_wenviron, + "Expected _wenviron to be different from __p___winitenv() %p %p\n", *retptr, *p_wenviron ); + /* test that w-initial env is derived from current _environ[] and not from ansi initial env */ + value = env_get_valueW( *retptr, L"cat" ); + ok( value && !wcscmp( value, L"dog" ), + "Expecting initial env to be derived from current env (got %ls)\n", value ); } + _putenv("cat="); /* Examine the returned pointer from __p__wenviron(), * if available, after _wenviron is initialized. */ @@ -222,29 +258,27 @@ static void test__wenviron(void) ok( retptr == *p_wenviron, "Expected _wenviron pointers to be identical\n" ); } - - for (i = 0; ; i++) - { - if ((*p_wenviron)[i]) - { - ok( wenvp[i] != NULL, "Expected environment block pointer element to be non-NULL\n" ); - ok( !winetest_strcmpW((*p_wenviron)[i], wenvp[i]), - "Expected _wenviron and environment block pointer strings (%s vs. %s) to match\n", - wine_dbgstr_w((*p_wenviron)[i]), wine_dbgstr_w(wenvp[i]) ); - } - else - { - ok( !wenvp[i], "Expected environment block pointer element to be NULL, got %p\n", wenvp[i] ); - break; - } - } } static void test_environment_manipulation(void) { + char buf[256]; + errno_t ret; + size_t len; + unsigned count; + char* first; + char* second; + ok( _putenv("cat=") == 0, "_putenv failed on deletion of nonexistent environment variable\n" ); ok( _putenv("cat=dog") == 0, "failed setting cat=dog\n" ); ok( strcmp(getenv("cat"), "dog") == 0, "getenv did not return 'dog'\n" ); + if (p_getenv_s) + { + ret = p_getenv_s(&len, buf, sizeof(buf), "cat"); + ok( !ret, "getenv_s returned %d\n", ret ); + ok( len == 4, "getenv_s returned length is %Id\n", len); + ok( !strcmp(buf, "dog"), "getenv_s did not return 'dog'\n"); + } ok( _putenv("cat=") == 0, "failed deleting cat\n" ); ok( _putenv("=") == -1, "should not accept '=' as input\n" ); @@ -252,16 +286,190 @@ static void test_environment_manipulation(void) ok( _putenv(a_very_long_env_string) == 0, "_putenv failed for long environment string\n"); ok( getenv("nonexistent") == NULL, "getenv should fail with nonexistent var name\n" ); + + if (p_putenv_s) + { + ret = p_putenv_s(NULL, "dog"); + ok( ret == EINVAL, "_putenv_s returned %d\n", ret); + ret = p_putenv_s("cat", NULL); + ok( ret == EINVAL, "_putenv_s returned %d\n", ret); + ret = p_putenv_s("a=b", NULL); + ok( ret == EINVAL, "_putenv_s returned %d\n", ret); + ret = p_putenv_s("cat", "a=b"); + ok( !ret, "_putenv_s returned %d\n", ret); + ret = p_putenv_s("cat", ""); + ok( !ret, "_putenv_s returned %d\n", ret); + } + + if (p_wputenv_s) + { + ret = p_wputenv_s(NULL, L"dog"); + ok( ret == EINVAL, "_wputenv_s returned %d\n", ret); + ret = p_wputenv_s(L"cat", NULL); + ok( ret == EINVAL, "_wputenv_s returned %d\n", ret); + ret = p_wputenv_s(L"a=b", NULL); + ok( ret == EINVAL, "_wputenv_s returned %d\n", ret); + ret = p_wputenv_s(L"cat", L"a=b"); + ok( !ret, "_wputenv_s returned %d\n", ret); + ret = p_wputenv_s(L"cat", L""); + ok( !ret, "_wputenv_s returned %d\n", ret); + } + + if (p_getenv_s) + { + buf[0] = 'x'; + len = 1; + errno = 0xdeadbeef; + ret = p_getenv_s(&len, buf, sizeof(buf), "nonexistent"); + ok( !ret, "_getenv_s returned %d\n", ret); + ok( !len, "getenv_s returned length is %Id\n", len); + ok( !buf[0], "buf = %s\n", buf); + ok( errno == 0xdeadbeef, "errno = %d\n", errno); + + buf[0] = 'x'; + len = 1; + errno = 0xdeadbeef; + ret = p_getenv_s(&len, buf, sizeof(buf), NULL); + ok( !ret, "_getenv_s returned %d\n", ret); + ok( !len, "getenv_s returned length is %Id\n", len); + ok( !buf[0], "buf = %s\n", buf); + ok( errno == 0xdeadbeef, "errno = %d\n", errno); + } + + /* test stability of _environ[] pointers */ + ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env var\n" ); + ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" ); + count = env_get_entry_countA( *p_environ ); + ok( _putenv( "__winetest_cat=mew") == 0, "Couldn't set env var\n" ); + ok( !strcmp( (*p_environ)[count], "__winetest_cat=mew"), "Unexpected env var value\n" ); + first = (*p_environ)[count]; + ok( getenv("__winetest_cat") == strchr( (*p_environ)[count], '=') + 1, "Expected getenv() to return pointer inside _environ[] entry\n" ); + ok( _putenv( "__winetest_dog=bark" ) == 0, "Couldn't set env var\n" ); + ok( !strcmp( (*p_environ)[count + 1], "__winetest_dog=bark" ), "Unexpected env var value\n" ); + ok( getenv( "__winetest_dog" ) == strchr( (*p_environ)[count + 1], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" ); + ok( first == (*p_environ)[count], "Expected stability of _environ[count] pointer\n" ); + second = (*p_environ)[count + 1]; + ok( count + 2 == env_get_entry_countA( *p_environ ), "Unexpected count\n" ); + + ok( _putenv( "__winetest_cat=purr" ) == 0, "Couldn't set env var\n" ); + ok( !strcmp( (*p_environ)[count], "__winetest_cat=purr" ), "Unexpected env var value\n" ); + ok( getenv( "__winetest_cat" ) == strchr( (*p_environ)[count], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" ); + ok( second == (*p_environ)[count + 1], "Expected stability of _environ[count] pointer\n" ); + ok( !strcmp( (*p_environ)[count + 1], "__winetest_dog=bark" ), "Couldn't get env var value\n" ); + ok( getenv( "__winetest_dog" ) == strchr( (*p_environ)[count + 1], '=' ) + 1, "Expected getenv() to return pointer inside _environ[] entry\n" ); + ok( count + 2 == env_get_entry_countA( *p_environ ), "Unexpected count\n" ); + ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env vat\n" ); + ok( second == (*p_environ)[count], "Expected _environ[count] to be second\n" ); + ok( !strcmp( (*p_environ)[count], "__winetest_dog=bark" ), "Unexpected env var value\n" ); + ok( count + 1 == env_get_entry_countA( *p_environ ), "Unexpected count\n" ); + ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" ); + ok( count == env_get_entry_countA( *p_environ ), "Unexpected count\n" ); + + /* in putenv, only changed variable is updated (no other reload of kernel info is done) */ + ret = SetEnvironmentVariableA( "__winetest_cat", "meow" ); + ok( ret, "SetEnvironmentVariableA failed: %lu\n", GetLastError() ); + ok( _putenv( "__winetest_dog=bark" ) == 0, "Couldn't set env var\n" ); + ok( getenv( "__winetest_cat" ) == NULL, "msvcrt env cache shouldn't have been updated\n" ); + ok( _putenv( "__winetest_cat=" ) == 0, "Couldn't reset env var\n" ); + ok( _putenv( "__winetest_dog=" ) == 0, "Couldn't reset env var\n" ); + + /* test setting unicode bits */ + count = env_get_entry_countA( *p_environ ); + ret = WideCharToMultiByte( CP_ACP, 0, L"\u263a", -1, buf, ARRAY_SIZE(buf), 0, 0 ); + ok( ret, "WideCharToMultiByte failed: %lu\n", GetLastError() ); + ok( _wputenv( L"__winetest_cat=\u263a" ) == 0, "Couldn't set env var\n" ); + ok( _wgetenv( L"__winetest_cat" ) && !wcscmp( _wgetenv( L"__winetest_cat" ), L"\u263a" ), "Couldn't retrieve env var\n" ); + ok( getenv( "__winetest_cat" ) && !strcmp( getenv( "__winetest_cat" ), buf ), "Couldn't retrieve env var\n" ); + ok( _wputenv( L"__winetest_cat=" ) == 0, "Couldn't reset env var\n" ); + + ret = WideCharToMultiByte( CP_ACP, 0, L"__winetest_\u263a", -1, buf, ARRAY_SIZE(buf), 0, 0 ); + ok( ret, "WideCharToMultiByte failed: %lu\n", GetLastError() ); + ok( _wputenv( L"__winetest_\u263a=bark" ) == 0, "Couldn't set env var\n" ); + ok( _wgetenv( L"__winetest_\u263a" ) && !wcscmp( _wgetenv( L"__winetest_\u263a" ), L"bark"), "Couldn't retrieve env var\n" ); + ok( getenv( buf ) && !strcmp( getenv( buf ), "bark"), "Couldn't retrieve env var %s\n", wine_dbgstr_a(buf) ); + ok( _wputenv( L"__winetest_\u263a=" ) == 0, "Couldn't reset env var\n" ); + ok( count == env_get_entry_countA( *p_environ ), "Unexpected modification of _environ[]\n" ); +} + +static void test_child_env(char** argv) +{ + STARTUPINFOA si = {sizeof(si)}; + WCHAR *cur_env, *env, *p, *q; + PROCESS_INFORMATION pi; + char tmp[1024]; + BOOL ret; + int len; + + cur_env = GetEnvironmentStringsW(); + ok( cur_env != NULL, "GetEnvironemntStrings failed\n" ); + + p = cur_env; + while (*p) p += wcslen( p ) + 1; + len = p - cur_env; + env = malloc( (len + 1024) * sizeof(*env) ); + memcpy(env, cur_env, len * sizeof(*env) ); + q = env + len; + FreeEnvironmentStringsW( cur_env ); + + wcscpy( q, L"__winetest_dog=bark" ); + q += wcslen( L"__winetest_dog=bark" ) + 1; + wcscpy( q, L"__winetest_\u263a=\u03b2" ); + q += wcslen( L"__winetest_\u263a=\u03b2" ) + 1; + *q = 0; + + snprintf( tmp, sizeof(tmp), "%s %s create", argv[0], argv[1] ); + ret = CreateProcessA( NULL, tmp, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi ); + ok( ret, "Couldn't create child process %s\n", tmp ); + winetest_wait_child_process( pi.hProcess ); + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + free( env ); +} + +static void test_case_insensitive(void) +{ + const char *uppercase_env = getenv("APPDATA"); + const char *lowercase_env = getenv("appdata"); + const wchar_t *uppercase_wenv = _wgetenv(L"APPDATA"); + const wchar_t *lowercase_wenv = _wgetenv(L"appdata"); + + ok( uppercase_env == lowercase_env, "getenv() must be case insensitive, %p should be %p\n", + lowercase_env, uppercase_env ); + ok( uppercase_wenv == lowercase_wenv, "_wgetenv() must be case insensitive, %p should be %p\n", + lowercase_wenv, uppercase_wenv ); + + ok( !_putenv("cAt=bar"), "Failed to set CAT=bar\n" ); + ok( !_putenv("CAT=BAR"), "Failed to set CAT=BAR\n" ); + ok( !strcmp(getenv("cAt"), "BAR"), "_putenv() must be case insensitive\n" ); + + ok( !_wputenv(L"cAt=bar"), "Failed to set CAT=bar\n" ); + ok( !_wputenv(L"CAT=BAR"), "Failed to set CAT=BAR\n" ); + ok( !wcscmp(_wgetenv(L"cAt"), L"BAR"), "_wputenv() must be case insensitive\n" ); + + _putenv("cat="); } START_TEST(environ) { + char **argv; + int argc; + init(); - /* The environ tests should always be run first, as they assume - * that the process has not manipulated the environment. */ + argc = winetest_get_mainargs( &argv ); + if (argc == 3 && !strcmp( argv[2], "create" )) + { + ok( getenv( "__winetest_dog" ) && !strcmp( getenv( "__winetest_dog" ), "bark" ), + "Couldn't find env var\n" ); + ok( _wgetenv( L"__winetest_\u263a" ) && !wcscmp( _wgetenv( L"__winetest_\u263a" ), L"\u03b2" ), + "Couldn't find unicode env var\n" ); + return; + } + test__environ(); test__wenviron(); test_environment_manipulation(); + test_child_env(argv); test_system(); + test_case_insensitive(); } diff --git a/modules/rostests/winetests/msvcrt/file.c b/modules/rostests/winetests/msvcrt/file.c index fe62d5c385e..d082bb269c6 100644 --- a/modules/rostests/winetests/msvcrt/file.c +++ b/modules/rostests/winetests/msvcrt/file.c @@ -35,6 +35,25 @@ #include #include #include +#ifdef __REACTOS__ +#include +#else +#include +#endif + +#define WX_OPEN 0x01 +#define WX_ATEOF 0x02 +#define WX_READNL 0x04 +#define WX_PIPE 0x08 +#define WX_DONTINHERIT 0x10 +#define WX_APPEND 0x20 +#define WX_TTY 0x40 +#define WX_TEXT 0x80 + +#define EF_UTF8 0x01 +#define EF_UTF16 0x02 +#define EF_CRIT_INIT 0x04 +#define EF_UNK_UNICODE 0x08 #define MSVCRT_FD_BLOCK_SIZE 32 typedef struct { @@ -52,6 +71,7 @@ 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 errno_t (__cdecl *p__get_fmode)(int*); static errno_t (__cdecl *p__set_fmode)(int); +static int (__cdecl *p__setmaxstdio)(int); static const char* get_base_name(const char *path) { @@ -76,6 +96,7 @@ static void init(void) __pioinfo = (void*)GetProcAddress(hmod, "__pioinfo"); p__get_fmode = (void*)GetProcAddress(hmod, "_get_fmode"); p__set_fmode = (void*)GetProcAddress(hmod, "_set_fmode"); + p__setmaxstdio = (void*)GetProcAddress(hmod, "_setmaxstdio"); } static void test_filbuf( void ) @@ -211,7 +232,50 @@ static void test_fileops( void ) ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n"); /* feof should be set now */ ok(feof(file), "feof after fread failed\n"); - fclose (file); + clearerr(file); + ok(!feof(file), "feof after clearerr failed\n"); + fclose(file); + + file = fopen("fdopen.tst", "rb"); + ok( file != NULL, "fopen failed\n"); + /* sizeof(buffer) > content of file */ + ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n"); + /* feof should be set now */ + ok(feof(file), "feof after fread failed\n"); + rewind(file); + ok(!feof(file), "feof after rewind failed\n"); + fclose(file); + + file = fopen("fdopen.tst", "rb"); + ok( file != NULL, "fopen failed\n"); + /* sizeof(buffer) > content of file */ + ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n"); + /* feof should be set now */ + ok(feof(file), "feof after fread failed\n"); + fseek(file, 0, SEEK_SET); + ok(!feof(file), "feof after fseek failed\n"); + fclose(file); + + file = fopen("fdopen.tst", "rb"); + ok( file != NULL, "fopen failed\n"); + /* sizeof(buffer) > content of file */ + ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n"); + /* feof should be set now */ + ok(feof(file), "feof after fread failed\n"); + fgetpos(file, &pos); + fsetpos(file, &pos); + ok(!feof(file), "feof after fsetpos failed\n"); + fclose(file); + + file = fopen("fdopen.tst", "rb"); + ok( file != NULL, "fopen failed\n"); + /* sizeof(buffer) > content of file */ + ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n"); + /* feof should be set now */ + ok(feof(file), "feof after fread failed\n"); + fsetpos(file, &pos); + ok(!feof(file), "feof after fsetpos failed\n"); + fclose(file); unlink ("fdopen.tst"); } @@ -233,7 +297,7 @@ static void test_readmode( BOOL ascii_mode ) fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE); /* an internal buffer of BUFSIZ is maintained, so make a file big - * enough to test operations that cross the buffer boundary + * enough to test operations that cross the buffer boundary */ j = (2*BUFSIZ-4)/strlen(padbuffer); for (i=0; i_file; + tempfh->_file = -1; + + ok(tempfh->_ptr - tempfh->_base, "buffer is empty\n"); + ret = fflush(tempfh); + ok(ret == EOF, "expected EOF, got %d\n", ret); + ok(!(tempfh->_ptr - tempfh->_base), "buffer should be empty\n"); + ok(!tempfh->_cnt, "tempfh->_cnt = %d\n", tempfh->_cnt); + + tempfh->_file = fd; + fclose(tempfh); unlink(tempf); free(tempf); } @@ -764,10 +863,10 @@ static void test_fgetwc( void ) tempfh = fopen(tempf,"rt"); /* open in TEXT mode */ fgetws(wtextW,LLEN,tempfh); l=ftell(tempfh); - ok(l==BUFSIZ-2, "ftell expected %d got %d\n", BUFSIZ-2, l); + ok(l==BUFSIZ-2, "ftell expected %d got %ld\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+lstrlenA(mytext), l); + ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n", BUFSIZ-2+lstrlenA(mytext), l); mytextW = AtoW (mytext); aptr = mytextW; wptr = wtextW; @@ -779,7 +878,7 @@ static void test_fgetwc( void ) ok(*wptr == '\n', "Carriage return was not skipped\n"); fclose(tempfh); unlink(tempf); - + tempfh = fopen(tempf,"wb"); j = 'a'; /* pad to almost the length of the internal buffer. Use an odd number of bytes @@ -800,25 +899,25 @@ static void test_fgetwc( void ) fgetws(wtextW,j,tempfh); l=ftell(tempfh); j=(j-1)*sizeof(WCHAR); - ok(l==j, "ftell expected %d got %d\n", j, l); + ok(l==j, "ftell expected %d got %ld\n", j, l); i=fgetc(tempfh); ok(i=='a', "fgetc expected %d got %d\n", 0x61, i); l=ftell(tempfh); j++; - ok(l==j, "ftell expected %d got %d\n", j, l); + ok(l==j, "ftell expected %d got %ld\n", j, l); fgetws(wtextW,3,tempfh); ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]); ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]); l=ftell(tempfh); j += 4; - ok(l==j, "ftell expected %d got %d\n", j, l); + ok(l==j, "ftell expected %d got %ld\n", j, l); for(i=0; i 0, "utf-8 conversion failed\n"); + utf8_text[ret] = 0; + 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 < ARRAY_SIZE(wchar_text); 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); + + tempfh = fopen(tempfile, "rt, ccs=unicode"); + ok(tempfh != NULL, "can't open tempfile\n"); + for (i = 0; utf8_text[i]; i++) + { + ch = fgetwc(tempfh); + ok(ch == (unsigned char) utf8_text[i], + "got %04hx, expected %04x (unicode[%d])\n", ch, (unsigned char)utf8_text[i], i); + } + ch = fgetwc(tempfh); + ok(ch == WEOF, "got %04hx, expected WEOF (unicode)\n", ch); + fclose(tempfh); + unlink(temppath); } @@ -1034,6 +1216,98 @@ static void test_fputwc(void) _unlink(tempfile); } +static void test_freopen( void ) +{ + char filename1[8] = "AXXXXXX"; + char filename2[8] = "BXXXXXX"; + FILE *file; + FILE *new; + int ret; + int fd; + char ch; + long pos; + + mktemp(filename1); + mktemp(filename2); + + file = fopen(filename1, "wt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + ret = fwrite("1", 1, 1, file); + ok(ret == 1, "fwrite() returned %d (%d)\n", ret, errno); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename2, "wt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + ret = fwrite("2", 1, 1, file); + ok(ret == 1, "fwrite() returned %d (%d)\n", ret, errno); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "rt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + file = freopen(filename2, "rt", file); + ok(file != NULL, "fopen(filename2) returned NULL\n"); + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '2', "fread() read %c\n", ch); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "at"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + file = freopen(filename1, "rt", file); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + pos = ftell(file); + ok(pos == 0, "ftell() returned %ld\n", pos); + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '1', "fread() read %c\n", ch); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "rt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + fd = fileno(file); + ok(fd > 0, "fileno() returned %d\n", fd); + /* invalid filename */ + new = freopen("_:", "rt", file); + ok(new == NULL, "fopen(_:) returned non NULL\n"); + errno = 0xdeadbeef; + ch = '#'; + ret = read(fd, &ch, 1); + ok(ret == -1, "read() returned %d\n", ret); + ok(errno == EBADF, "errno is %d\n", errno); + errno = 0xdeadbeef; + ret = fclose(file); + ok(ret == EOF, "fclose(file) succeeded\n"); + ok(errno == 0xdeadbeef, "errno is %d\n", errno); + + file = fopen(filename1, "rb"); + ok(file != NULL, "couldn't open %s\n", filename1); + close(file->_file); + file->_file = -1; + + new = freopen(filename2, "rb", file); + ok(new == file, "freopen() didn't return same FILE*\n"); + + fd = fileno(file); + ok(fd > 0, "fileno() returned %d\n", fd); + + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '2', "Unexpected char\n"); + + ret = fclose(file); + ok(ret == 0, "fclose(file) returned %d\n", ret); + + unlink(filename1); + unlink(filename2); +} + static void test_ctrlz( void ) { char* tempf; @@ -1062,17 +1336,17 @@ static void test_ctrlz( void ) ok(i==j, "returned string length expected %d got %d\n", j, i); j+=4; /* ftell should indicate the true end of file */ l=ftell(tempfh); - ok(l==j, "ftell expected %d got %d\n", j, l); + ok(l==j, "ftell expected %d got %ld\n", j, l); ok(feof(tempfh), "did not get EOF\n"); fclose(tempfh); - + tempfh = fopen(tempf,"rb"); /* open in BINARY mode */ ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n"); i=strlen(buffer); j=strlen(mytext)+3; /* should get through newline */ ok(i==j, "returned string length expected %d got %d\n", j, i); l=ftell(tempfh); - ok(l==j, "ftell expected %d got %d\n", j, l); + ok(l==j, "ftell expected %d got %ld\n", j, l); ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n"); i=strlen(buffer); ok(i==1, "returned string length expected %d got %d\n", 1, i); @@ -1185,7 +1459,7 @@ static void test_file_write_read( void ) memset(btext, 0, LLEN); tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */ - ok(tell(tempfd) == 0, "bad position %u expecting 0\n", tell(tempfd)); + ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd)); ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n"); ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n"); _close(tempfd); @@ -1206,15 +1480,15 @@ static void test_file_write_read( void ) _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); - ok(tell(tempfd) == 41, "bad position %u expecting 41\n", tell(tempfd)); + ok(tell(tempfd) == 41, "bad position %lu expecting 41\n", tell(tempfd)); _lseek(tempfd, -3, FILE_END); ret = _read(tempfd,btext,2); ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret); - ok(tell(tempfd) == 42, "bad position %u expecting 42\n", tell(tempfd)); + ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd)); _lseek(tempfd, -3, FILE_END); ret = _read(tempfd,btext,3); ok(ret == 2 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret); - ok(tell(tempfd) == 43, "bad position %u expecting 43\n", tell(tempfd)); + ok(tell(tempfd) == 43, "bad position %lu expecting 43\n", tell(tempfd)); _close(tempfd); ret = unlink(tempf); @@ -1336,9 +1610,9 @@ static void test_file_write_read( void ) /* 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); + 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, "\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); } @@ -1355,13 +1629,27 @@ static void test_file_write_read( void ) free(tempf); } -static void test_file_inherit_child(const char* fd_s) +static void test_file_inherit_child(const char* fd_s, const char *handle_str) { + HANDLE handle_value; int fd = atoi(fd_s); + HANDLE *handle_ptr; + unsigned int count; char buffer[32]; + STARTUPINFOA si; int ret; - ret =write(fd, "Success", 8); + GetStartupInfoA(&si); + count = *(unsigned *)si.lpReserved2; + if (handle_str) + { + ok(count == 3, "Got unexpected count %u.\n", count); + sscanf(handle_str, "%p", &handle_value); + handle_ptr = (HANDLE *)(si.lpReserved2 + sizeof(unsigned) + count); + ok(handle_value == handle_ptr[1], "Got unexpected handle %p.\n", handle_ptr[1]); + } + + ret = write(fd, "Success", 8); ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno)); lseek(fd, 0, SEEK_SET); ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n"); @@ -1374,7 +1662,7 @@ static void test_file_inherit_child_no(const char* fd_s) int ret; ret = write(fd, "Success", 8); - ok( ret == -1 && errno == EBADF, + ok( ret == -1 && errno == EBADF, "Wrong write result in child process on %d (%s)\n", fd, strerror(errno)); } @@ -1430,7 +1718,7 @@ static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hst CreateProcessA( NULL, cmdline, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, startup, &proc ); - winetest_wait_child_process( proc.hProcess ); + wait_child_process( proc.hProcess ); data = read_file( hErrorFile ); if (expect_stdout) @@ -1451,6 +1739,18 @@ static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hst DeleteFileA( "fdopen.err" ); } +static unsigned WINAPI read_pipe_thread(void *argument) +{ + unsigned char buffer[2]; + int ret; + int *pipefds = argument; + + ret = _read(pipefds[0], buffer, sizeof(buffer)); + ok(ret == 1, "ret = %d\n", ret); + ok(buffer[0] == 'a', "%x\n", buffer[0]); + return 0; +} + static void test_file_inherit( const char* selfname ) { int fd; @@ -1460,33 +1760,62 @@ static void test_file_inherit( const char* selfname ) STARTUPINFOA startup; SECURITY_ATTRIBUTES sa; HANDLE handles[3]; + HANDLE thread_handle; + int pipefds[2]; + intptr_t ret; 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] = get_base_name(selfname); - arg_v[1] = "tests/file.c"; + arg_v[1] = "file"; arg_v[2] = "inherit"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); arg_v[4] = 0; - _spawnvp(_P_WAIT, selfname, arg_v); - ok(tell(fd) == 8, "bad position %u expecting 8\n", tell(fd)); + ret = _spawnvp(_P_WAIT, selfname, arg_v); + ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); + ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd)); lseek(fd, 0, SEEK_SET); ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n"); close (fd); ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n"); - + 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[1] = "tests/file.c"; + arg_v[1] = "file"; arg_v[2] = "inherit_no"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); arg_v[4] = 0; - _spawnvp(_P_WAIT, selfname, arg_v); - ok(tell(fd) == 0, "bad position %u expecting 0\n", tell(fd)); + ret = _spawnvp(_P_WAIT, selfname, arg_v); + ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); + ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd)); ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer); close (fd); ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n"); + /* Show that spawn works while a read is active */ + ok(_pipe(pipefds, 1, O_BINARY) == 0, "_pipe() failed\n"); + thread_handle = (HANDLE)_beginthreadex(NULL, 0, read_pipe_thread, pipefds, 0, NULL); + Sleep(100); /* try to make sure the thread is reading */ + 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[1] = "tests/file.c"; + arg_v[2] = "inherit"; + arg_v[3] = buffer; sprintf(buffer, "%d", fd); + arg_v[4] = 0; + ret = _spawnvp(_P_WAIT, selfname, arg_v); + ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); + ret = tell(fd); + ok(ret == 8, "bad position %Iu expecting 8\n", ret); + lseek(fd, 0, SEEK_SET); + ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n"); + close (fd); + ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n"); + _write(pipefds[1], "a", 1); + WaitForSingleObject(thread_handle, INFINITE); + CloseHandle(thread_handle); + close(pipefds[0]); + close(pipefds[1]); + /* make file handle inheritable */ sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; @@ -1544,6 +1873,22 @@ static void test_file_inherit( const char* selfname ) test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block" ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); + + /* test inherit block with invalid handle */ + handles[1] = INVALID_HANDLE_VALUE; + create_io_inherit_block( &startup, 3, handles ); + sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "INVALID_HANDLE_VALUE stdout handle" ); + + handles[1] = NULL; + create_io_inherit_block( &startup, 3, handles ); + sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "NULL stdout handle" ); + + handles[1] = (void *)0xdeadbeef; + create_io_inherit_block( &startup, 3, handles ); + sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "invalid stdout handle" ); } static void test_invalid_stdin_child( void ) @@ -1557,6 +1902,8 @@ static void test_invalid_stdin_child( void ) handle = (HANDLE)_get_osfhandle(STDIN_FILENO); ok(handle == (HANDLE)-2, "handle = %p\n", handle); ok(errno == 0xdeadbeef, "errno = %d\n", errno); + handle = GetStdHandle(STD_INPUT_HANDLE); + ok((LONG_PTR)handle > 0, "Expecting passed handle to be untouched\n"); info = &__pioinfo[STDIN_FILENO/MSVCRT_FD_BLOCK_SIZE][STDIN_FILENO%MSVCRT_FD_BLOCK_SIZE]; ok(info->handle == (HANDLE)-2, "info->handle = %p\n", info->handle); @@ -1631,7 +1978,11 @@ static void test_invalid_stdin( const char* selfname ) } ret = RegOpenCurrentUser(KEY_READ, &key); - ok(!ret, "RegOpenCurrentUser failed: %x\n", ret); + ok(!ret, "RegOpenCurrentUser failed: %lx\n", ret); + + ret = DuplicateHandle(GetCurrentProcess(), key, GetCurrentProcess(), + (HANDLE *)&key, GENERIC_READ, TRUE, DUPLICATE_CLOSE_SOURCE); + ok(ret, "DuplicateHandle failed: %lx\n", GetLastError()); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; @@ -1647,10 +1998,10 @@ static void test_invalid_stdin( const char* selfname ) sprintf(cmdline, "%s file stdin", selfname); CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS, NULL, NULL, &startup, &proc); - winetest_wait_child_process(proc.hProcess); + wait_child_process(proc.hProcess); ret = RegCloseKey(key); - ok(!ret, "RegCloseKey failed: %x\n", ret); + ok(!ret, "RegCloseKey failed: %lx\n", ret); } static void test_tmpnam( void ) @@ -1678,8 +2029,8 @@ static void test_chsize( void ) LONG cur, pos, count; char temptext[] = "012345678"; char *tempfile = _tempnam( ".", "tst" ); - - ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile ); + + ok( tempfile != NULL, "Couldn't create test file\n" ); fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE ); ok( fd > 0, "Couldn't open test file\n" ); @@ -1694,14 +2045,14 @@ static void test_chsize( void ) ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" ); pos = _lseek( fd, 0, SEEK_CUR ); - ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos ); + ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos ); ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" ); /* enlarge the file */ - ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); + ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); pos = _lseek( fd, 0, SEEK_CUR ); - ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos ); + ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos ); ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" ); _close( fd ); @@ -1733,7 +2084,7 @@ static void test_fopen_fclose_fcloseall( void ) "filename is empty, errno = %d (expected 2 or 22)\n", errno); errno = 0xfaceabad; stream4 = fopen(NULL, "w+"); - ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), + ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), "filename is NULL, errno = %d (expected 2 or 22)\n", errno); /* testing fclose() */ @@ -1748,6 +2099,9 @@ static void test_fopen_fclose_fcloseall( void ) ret = fclose(stream3); ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret); ok(errno == 0xdeadbeef, "errno = %d\n", errno); + ret = fclose(NULL); + ok(ret == EOF, "Closing NULL file returned %d\n", ret); + ok(errno == EINVAL, "errno = %d\n", errno); /* testing fcloseall() */ numclosed = _fcloseall(); @@ -1879,12 +2233,6 @@ static void test_fopen_s( void ) static void test__wfopen_s( void ) { const char name[] = "empty1"; - const WCHAR wname[] = { - 'e','m','p','t','y','1',0 - }; - const WCHAR wmode[] = { - 'w',0 - }; char buff[16]; FILE *file; int ret; @@ -1896,7 +2244,7 @@ static void test__wfopen_s( void ) return; } /* testing _wfopen_s */ - ret = p__wfopen_s(&file, wname, wmode); + ret = p__wfopen_s(&file, L"empty1", L"w"); ok(ret == 0, "_wfopen_s failed with %d\n", ret); ok(file != 0, "_wfopen_s failed to return value\n"); fwrite(name, sizeof(name), 1, file); @@ -2007,8 +2355,12 @@ static void test_get_osfhandle(void) static void test_setmaxstdio(void) { - ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048)); - ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049)); + if (p__setmaxstdio) + { + ok(2048 == p__setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",p__setmaxstdio(2048)); + ok(-1 == p__setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",p__setmaxstdio(2049)); + } + else win_skip( "_setmaxstdio not supported\n" ); } static void test_stat(void) @@ -2168,7 +2520,7 @@ static void test_pipes(const char* selfname) } arg_v[0] = get_base_name(selfname); - arg_v[1] = "tests/file.c"; + arg_v[1] = "file"; arg_v[2] = "pipes"; arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]); arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]); @@ -2197,7 +2549,7 @@ static void test_pipes(const char* selfname) return; } - arg_v[1] = "tests/file.c"; + arg_v[1] = "file"; arg_v[2] = "pipes"; arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]); arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]); @@ -2313,7 +2665,7 @@ static void test_stdin(void) "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); + ok(r == TRUE, "SetStdHandle returned %lx, expected TRUE\n", r); h = GetStdHandle(STD_INPUT_HANDLE); ok(h == INVALID_HANDLE_VALUE, "h = %p\n", h); @@ -2548,7 +2900,7 @@ static void test__creat(void) pos = _tell(fd); ok(pos == 6, "expected pos 6 (text mode), got %d\n", pos); } - ok(_lseek(fd, SEEK_SET, 0) == 0, "_lseek failed\n"); + ok(_lseek(fd, 0, SEEK_SET) == 0, "_lseek failed\n"); count = _read(fd, buf, 6); ok(count == 4, "_read returned %d, expected 4\n", count); count = count > 0 ? count > 4 ? 4 : count : 0; @@ -2568,7 +2920,7 @@ static void test__creat(void) pos = _tell(fd); ok(pos == 4, "expected pos 4 (binary mode), got %d\n", pos); } - ok(_lseek(fd, SEEK_SET, 0) == 0, "_lseek failed\n"); + ok(_lseek(fd, 0, SEEK_SET) == 0, "_lseek failed\n"); count = _read(fd, buf, 6); ok(count == 4, "_read returned %d, expected 4\n", count); count = count > 0 ? count > 4 ? 4 : count : 0; @@ -2583,6 +2935,215 @@ static void test__creat(void) p__set_fmode(old_fmode); } +static void test_lseek(void) +{ + int fd; + char testdata[4] = {'a', '\n', 'b', '\n'}; + + errno = 0xdeadbeef; + ok(_lseek(-42, 0, SEEK_SET) == -1, "expected failure\n"); + ok(errno == EBADF, "errno = %d\n", errno); + + fd = _creat("_creat.tst", _S_IWRITE); + ok(fd > 0, "_creat failed\n"); + _write(fd, testdata, 4); + + errno = 0xdeadbeef; + ok(_lseek(fd, 0, 42) == -1, "expected failure\n"); + ok(errno == EINVAL, "errno = %d\n", errno); + + errno = 0xdeadbeef; + ok(_lseek(fd, -42, SEEK_SET) == -1, "expected failure\n"); + ok(errno == EINVAL, "errno = %d\n", errno); + + _close(fd); + DeleteFileA("_creat.tst"); +} + +static BOOL has_sequential_hint(int fd) +{ + HANDLE handle; + FILE_MODE_INFORMATION mode_info; + IO_STATUS_BLOCK io; + NTSTATUS status; + + handle = (HANDLE)_get_osfhandle(fd); + status = NtQueryInformationFile(handle, &io, &mode_info, sizeof(mode_info), + FileModeInformation); + ok(!status, "NtQueryInformationFile failed\n"); + return (mode_info.Mode & FILE_SEQUENTIAL_ONLY) != 0; +} + +static void test_fopen_hints(void) +{ + static const struct { + const char *mode; + BOOL seq; + } tests[] = { + { "rb", FALSE }, + { "rbS", TRUE }, + { "rbR", FALSE }, + { "rbSR", TRUE }, + { "rbRS", FALSE } + }; + + char temppath[MAX_PATH], tempfile[MAX_PATH]; + FILE *fp; + int i; + + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + fp = fopen(tempfile, tests[i].mode); + ok(fp != NULL, "unable to fopen test file with mode \"%s\"\n", tests[i].mode); + ok(has_sequential_hint(_fileno(fp)) == tests[i].seq, + "unexpected sequential hint for fopen mode \"%s\"\n", tests[i].mode); + fclose(fp); + } + unlink(tempfile); +} + +static void test_open_hints(void) +{ + static const struct { + int mode; + BOOL seq; + } tests[] = { + { _O_RDONLY | _O_BINARY, FALSE }, + { _O_RDONLY | _O_BINARY | _O_SEQUENTIAL, TRUE }, + { _O_RDONLY | _O_BINARY | _O_RANDOM, FALSE }, + { _O_RDONLY | _O_BINARY | _O_RANDOM | _O_SEQUENTIAL, TRUE } + }; + + char temppath[MAX_PATH], tempfile[MAX_PATH]; + int fd; + int i; + + GetTempPathA(MAX_PATH, temppath); + GetTempFileNameA(temppath, "", 0, tempfile); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + fd = open(tempfile, tests[i].mode); + ok(fd != -1, "unable to _open test file with flags %x\n", tests[i].mode); + ok(has_sequential_hint(fd) == tests[i].seq, + "unexpected sequential hint for _open flags %x\n", tests[i].mode); + close(fd); + } + unlink(tempfile); +} + +static void test_ioinfo_flags(void) +{ + HANDLE handle; + ioinfo *info; + char *tempf; + int tempfd; + + tempf = _tempnam(".","wne"); + + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + + handle = (HANDLE)_get_osfhandle(tempfd); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == handle, "Unexpected handle %p, expected %p.\n", info->handle, handle); + ok(info->exflag == (EF_UTF16 | EF_CRIT_INIT | EF_UNK_UNICODE), "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + + close(tempfd); + + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(info->exflag == (EF_UTF16 | EF_CRIT_INIT | EF_UNK_UNICODE), "Unexpected exflag %#x.\n", info->exflag); + ok(!info->wxflag, "Unexpected wxflag %#x.\n", info->wxflag); + + info = &__pioinfo[(tempfd + 4) / MSVCRT_FD_BLOCK_SIZE][(tempfd + 4) % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(!info->exflag, "Unexpected exflag %#x.\n", info->exflag); + + unlink(tempf); + free(tempf); +} + +static void test_std_stream_buffering(void) +{ + int dup_fd, ret, pos; + FILE *file; + char ch; + + dup_fd = _dup(STDOUT_FILENO); + ok(dup_fd != -1, "_dup failed\n"); + + file = freopen("std_stream_test.tmp", "w", stdout); + ok(file != NULL, "freopen failed\n"); + + ret = fprintf(stdout, "test"); + pos = _telli64(STDOUT_FILENO); + + fflush(stdout); + _dup2(dup_fd, STDOUT_FILENO); + close(dup_fd); + setvbuf(stdout, NULL, _IONBF, 0); + + ok(ret == 4, "fprintf(stdout) returned %d\n", ret); + ok(!pos, "expected stdout to be buffered\n"); + + dup_fd = _dup(STDERR_FILENO); + ok(dup_fd != -1, "_dup failed\n"); + + file = freopen("std_stream_test.tmp", "w", stderr); + ok(file != NULL, "freopen failed\n"); + + ret = fprintf(stderr, "test"); + ok(ret == 4, "fprintf(stderr) returned %d\n", ret); + pos = _telli64(STDERR_FILENO); + ok(!pos, "expected stderr to be buffered\n"); + + fflush(stderr); + _dup2(dup_fd, STDERR_FILENO); + close(dup_fd); + + dup_fd = _dup(STDIN_FILENO); + ok(dup_fd != -1, "_dup failed\n"); + + file = freopen("std_stream_test.tmp", "r", stdin); + ok(file != NULL, "freopen failed\n"); + + ch = 0; + ret = fscanf(stdin, "%c", &ch); + ok(ret == 1, "fscanf returned %d\n", ret); + ok(ch == 't', "ch = 0x%x\n", (unsigned char)ch); + pos = _telli64(STDIN_FILENO); + ok(pos == 4, "pos = %d\n", pos); + + fflush(stdin); + _dup2(dup_fd, STDIN_FILENO); + close(dup_fd); + + ok(DeleteFileA("std_stream_test.tmp"), "DeleteFile failed\n"); +} + +static void test_std_stream_open(void) +{ + FILE *f; + int fd; + + fd = _dup(STDIN_FILENO); + ok(fd != -1, "_dup failed\n"); + + ok(!fclose(stdin), "fclose failed\n"); + f = fopen("nul", "r"); + ok(f == stdin, "f = %p, expected %p\n", f, stdin); + ok(_fileno(f) == STDIN_FILENO, "_fileno(f) = %d\n", _fileno(f)); + + _dup2(fd, STDIN_FILENO); + close(fd); +} + START_TEST(file) { int arg_c; @@ -2596,7 +3157,7 @@ START_TEST(file) if (arg_c >= 3) { if (strcmp(arg_v[2], "inherit") == 0) - test_file_inherit_child(arg_v[3]); + test_file_inherit_child(arg_v[3], arg_c > 4 ? arg_v[4] : NULL); else if (strcmp(arg_v[2], "inherit_no") == 0) test_file_inherit_child_no(arg_v[3]); else if (strcmp(arg_v[2], "pipes") == 0) @@ -2642,6 +3203,7 @@ START_TEST(file) test_fgetwc_locale("AB\x83\xa9", "C", 0); test_fgetwc_unicode(); test_fputwc(); + test_freopen(); test_ctrlz(); test_file_put_get(); test_tmpnam(); @@ -2654,6 +3216,12 @@ START_TEST(file) test_write_flush(); test_close(); test__creat(); + test_lseek(); + test_fopen_hints(); + test_open_hints(); + test_ioinfo_flags(); + test_std_stream_buffering(); + test_std_stream_open(); /* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order diff --git a/modules/rostests/winetests/msvcrt/heap.c b/modules/rostests/winetests/msvcrt/heap.c index d934bf0c542..e8da95bb867 100644 --- a/modules/rostests/winetests/msvcrt/heap.c +++ b/modules/rostests/winetests/msvcrt/heap.c @@ -23,17 +23,13 @@ #include #include "wine/test.h" -#ifdef __REACTOS__ -#if defined(__GNUC__) && __GNUC__ >= 7 -#pragma GCC diagnostic ignored "-Walloc-size-larger-than=9223372036854775807" -#endif -#endif - -static void (__cdecl *p_aligned_free)(void*) = NULL; -static void * (__cdecl *p_aligned_malloc)(size_t,size_t) = NULL; -static void * (__cdecl *p_aligned_offset_malloc)(size_t,size_t,size_t) = NULL; -static void * (__cdecl *p_aligned_realloc)(void*,size_t,size_t) = NULL; -static void * (__cdecl *p_aligned_offset_realloc)(void*,size_t,size_t,size_t) = NULL; +static void (__cdecl *p_aligned_free)(void*); +static void * (__cdecl *p_aligned_malloc)(size_t,size_t); +static void * (__cdecl *p_aligned_offset_malloc)(size_t,size_t,size_t); +static void * (__cdecl *p_aligned_realloc)(void*,size_t,size_t); +static void * (__cdecl *p_aligned_offset_realloc)(void*,size_t,size_t,size_t); +static int (__cdecl *p__set_sbh_threshold)(size_t); +static size_t (__cdecl *p__get_sbh_threshold)(void); static void test_aligned_malloc(unsigned int size, unsigned int alignment) { @@ -421,28 +417,37 @@ static void test_aligned(void) static void test_sbheap(void) { + HMODULE msvcrt = GetModuleHandleA("msvcrt.dll"); void *mem; int threshold; + p__set_sbh_threshold = (void*)GetProcAddress(msvcrt, "_set_sbh_threshold"); + p__get_sbh_threshold = (void*)GetProcAddress(msvcrt, "_get_sbh_threshold"); + if (!p__set_sbh_threshold || !p__get_sbh_threshold) + { + win_skip("_set_sbh_threshold not available\n"); + return; + } + if(sizeof(void*) == 8) { - ok(!_set_sbh_threshold(0), "_set_sbh_threshold succeeded\n"); - ok(!_set_sbh_threshold(1000), "_set_sbh_threshold succeeded\n"); + ok(!p__set_sbh_threshold(0), "_set_sbh_threshold succeeded\n"); + ok(!p__set_sbh_threshold(1000), "_set_sbh_threshold succeeded\n"); return; } mem = malloc(1); ok(mem != NULL, "malloc failed\n"); - ok(_set_sbh_threshold(1), "_set_sbh_threshold failed\n"); - threshold = _get_sbh_threshold(); + ok(p__set_sbh_threshold(1), "_set_sbh_threshold failed\n"); + threshold = p__get_sbh_threshold(); ok(threshold == 16, "threshold = %d\n", threshold); - ok(_set_sbh_threshold(8), "_set_sbh_threshold failed\n"); - threshold = _get_sbh_threshold(); + ok(p__set_sbh_threshold(8), "_set_sbh_threshold failed\n"); + threshold = p__get_sbh_threshold(); ok(threshold == 16, "threshold = %d\n", threshold); - ok(_set_sbh_threshold(1000), "_set_sbh_threshold failed\n"); - threshold = _get_sbh_threshold(); + ok(p__set_sbh_threshold(1000), "_set_sbh_threshold failed\n"); + threshold = p__get_sbh_threshold(); ok(threshold == 1008, "threshold = %d\n", threshold); free(mem); @@ -455,13 +460,42 @@ static void test_sbheap(void) ok(mem != NULL, "realloc failed\n"); ok(!((UINT_PTR)mem & 0xf), "incorrect alignment (%p)\n", mem); - ok(_set_sbh_threshold(0), "_set_sbh_threshold failed\n"); - threshold = _get_sbh_threshold(); + ok(p__set_sbh_threshold(0), "_set_sbh_threshold failed\n"); + threshold = p__get_sbh_threshold(); ok(threshold == 0, "threshold = %d\n", threshold); free(mem); } +static void test_malloc(void) +{ + /* use function pointers to bypass gcc builtins */ + void *(__cdecl *p_malloc)(size_t); + void *(__cdecl *p_realloc)(void *,size_t); + void *mem; + + p_malloc = (void *)GetProcAddress( GetModuleHandleA("msvcrt.dll"), "malloc"); + p_realloc = (void *)GetProcAddress( GetModuleHandleA("msvcrt.dll"), "realloc"); + + mem = p_malloc(0); + ok(mem != NULL, "memory not allocated for size 0\n"); + free(mem); + + mem = p_realloc(NULL, 10); + ok(mem != NULL, "memory not allocated\n"); + + mem = p_realloc(mem, 20); + ok(mem != NULL, "memory not reallocated\n"); + + mem = p_realloc(mem, 0); + ok(mem == NULL, "memory not freed\n"); + + mem = p_realloc(NULL, 0); + ok(mem != NULL, "memory not (re)allocated for size 0\n"); + + free(mem); +} + static void test_calloc(void) { /* use function pointer to bypass gcc builtin */ @@ -489,29 +523,16 @@ static void test_calloc(void) free(ptr); } +static void test__get_heap_handle(void) +{ + ok((HANDLE)_get_heap_handle() != GetProcessHeap(), "Expected _get_heap_handle() not to return GetProcessHeap()\n"); +} + START_TEST(heap) { - void *mem; - - mem = malloc(0); - ok(mem != NULL, "memory not allocated for size 0\n"); - free(mem); - - mem = realloc(NULL, 10); - ok(mem != NULL, "memory not allocated\n"); - - mem = realloc(mem, 20); - ok(mem != NULL, "memory not reallocated\n"); - - mem = realloc(mem, 0); - ok(mem == NULL, "memory not freed\n"); - - mem = realloc(NULL, 0); - ok(mem != NULL, "memory not (re)allocated for size 0\n"); - - free(mem); - test_aligned(); test_sbheap(); + test_malloc(); test_calloc(); + test__get_heap_handle(); } diff --git a/modules/rostests/winetests/msvcrt/locale.c b/modules/rostests/winetests/msvcrt/locale.c index 08abac00bed..62632ce4b9d 100644 --- a/modules/rostests/winetests/msvcrt/locale.c +++ b/modules/rostests/winetests/msvcrt/locale.c @@ -19,6 +19,7 @@ */ #include +#include #include "wine/test.h" #include "winnls.h" @@ -27,6 +28,9 @@ static BOOL (__cdecl *p__crtGetStringTypeW)(DWORD, DWORD, const wchar_t*, int, W static int (__cdecl *pmemcpy_s)(void *, size_t, void*, size_t); static int (__cdecl *p___mb_cur_max_func)(void); static int *(__cdecl *p__p___mb_cur_max)(void); +static _locale_t(__cdecl *p_create_locale)(int, const char*); +static void(__cdecl *p_free_locale)(_locale_t); +static int (__cdecl *p_wcsicmp_l)(const wchar_t*, const wchar_t*, _locale_t); void* __cdecl _Gettnames(void); static void init(void) @@ -37,6 +41,9 @@ static void init(void) pmemcpy_s = (void*)GetProcAddress(hmod, "memcpy_s"); p___mb_cur_max_func = (void*)GetProcAddress(hmod, "___mb_cur_max_func"); p__p___mb_cur_max = (void*)GetProcAddress(hmod, "__p___mb_cur_max"); + p_create_locale = (void*)GetProcAddress(hmod, "_create_locale"); + p_free_locale = (void*)GetProcAddress(hmod, "_free_locale"); + p_wcsicmp_l = (void*)GetProcAddress(hmod, "_wcsicmp_l"); } static void test_setlocale(void) @@ -45,6 +52,8 @@ static void test_setlocale(void) "LC_MONETARY=Greek_Greece.1253;LC_NUMERIC=Polish_Poland.1250;LC_TIME=C"; char *ret, buf[100]; + char *ptr; + int len; ret = setlocale(20, "C"); ok(ret == NULL, "ret = %s\n", ret); @@ -571,12 +580,14 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "trk"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Turkish_Turkey.1254"), "ret = %s\n", ret); + ok(!strcmp(ret, "Turkish_Turkey.1254") + || !strcmp(ret, "Turkish_T\xfcrkiye.1254"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "turkish"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Turkish_Turkey.1254"), "ret = %s\n", ret); + ok(!strcmp(ret, "Turkish_Turkey.1254") + || !strcmp(ret, "Turkish_T\xfcrkiye.1254"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "uk"); ok(ret != NULL, "ret == NULL\n"); @@ -612,6 +623,27 @@ static void test_setlocale(void) ok(!strcmp(ret, buf), "ret = %s, expected %s\n", ret, buf); } + GetLocaleInfoA(GetUserDefaultLCID(), LOCALE_IDEFAULTCODEPAGE, buf, sizeof(buf)); + if(IsValidCodePage(atoi(buf))) { + ret = setlocale(LC_ALL, ".OCP"); + ok(ret != NULL, "ret == NULL\n"); + ptr = strchr(ret, '.'); + ok(ptr && !strcmp(ptr + 1, buf), "ret %s, buf %s.\n", ret, buf); + } + + len = GetLocaleInfoA(GetUserDefaultLCID(), LOCALE_IDEFAULTANSICODEPAGE, buf, sizeof(buf)) - 1; + if(buf[0] == '0' && !buf[1]) + len = sprintf(buf, "%d", GetACP()); + ret = setlocale(LC_ALL, ".ACP"); + ok(ret != NULL, "ret == NULL\n"); + ptr = strchr(ret, '.'); + ok(ptr && !strncmp(ptr + 1, buf, len), "ret %s, buf %s.\n", ret, buf); + + ret = setlocale(LC_ALL, ".1250"); + ok(ret != NULL, "ret == NULL\n"); + ptr = strchr(ret, '.'); + ok(ptr && !strcmp(ptr, ".1250"), "ret %s, buf %s.\n", ret, buf); + ret = setlocale(LC_ALL, "English_United States.UTF8"); ok(ret == NULL, "ret != NULL\n"); @@ -621,13 +653,7 @@ static void test_setlocale(void) static void test_crtGetStringTypeW(void) { - static const wchar_t str0[] = { '0', '\0' }; - static const wchar_t strA[] = { 'A', '\0' }; - static const wchar_t str_space[] = { ' ', '\0' }; - static const wchar_t str_null[] = { '\0', '\0' }; - static const wchar_t str_rand[] = { 1234, '\0' }; - - const wchar_t *str[] = { str0, strA, str_space, str_null, str_rand }; + const wchar_t *str[] = { L"0", L"A", L" ", L"\0", L"\x04d2" }; WORD out_crt, out; BOOL ret_crt, ret; @@ -712,10 +738,14 @@ static void test__Gettnames(void) { size = GetLocaleInfoA(MAKELCID(LANG_ENGLISH, SORT_DEFAULT), time_data[i], buf, sizeof(buf)); - ok(size, "GetLocaleInfo failed: %x\n", GetLastError()); + ok(size, "GetLocaleInfo failed: %lx\n", GetLastError()); ok(!strcmp(ret->str[i], buf), "ret->str[%i] = %s, expected %s\n", i, ret->str[i], buf); } + ok(ret->wstr[0] != NULL, "ret->wstr[0] = NULL\n"); + ok(ret->str[42] + strlen(ret->str[42])+1 != (char*)ret->wstr[0], + "ret->str[42] = %p len = %Id, ret->wstr[0] = %p\n", + ret->str[42], strlen(ret->str[42]), ret->wstr[0]); free(ret); if(!setlocale(LC_TIME, "german")) @@ -726,7 +756,7 @@ static void test__Gettnames(void) { size = GetLocaleInfoA(MAKELCID(LANG_GERMAN, SORT_DEFAULT), time_data[i], buf, sizeof(buf)); - ok(size, "GetLocaleInfo failed: %x\n", GetLastError()); + ok(size, "GetLocaleInfo failed: %lx\n", GetLastError()); ok(!strcmp(ret->str[i], buf), "ret->str[%i] = %s, expected %s\n", i, ret->str[i], buf); } free(ret); @@ -775,6 +805,178 @@ static void test___mb_cur_max_func(void) } } +static void test__wcsicmp_l(void) +{ + const struct { + const wchar_t *str1; + const wchar_t *str2; + int exp; + const char *loc; + } tests[] = { + { L"i", L"i", 0 }, + { L"I", L"i", 0 }, + { L"I", L"i", 0, "Turkish" }, + { L"i", L"a", 8 }, + { L"a", L"i", -8 }, + { L"i", L"a", 8, "Turkish" }, + }; + int ret, i; + + if (!p_wcsicmp_l || !p_create_locale) + { + win_skip("_wcsicmp_l or _create_locale not available\n"); + return; + } + ok(!!p_free_locale, "_free_locale not available\n"); + + for(i=0; ilocinfo; + locinfo2 = locale2->locinfo; + + ok(locinfo->mb_cur_max == locinfo2->mb_cur_max, "Got wrong max char size %d %d.\n", + locinfo->mb_cur_max, locinfo2->mb_cur_max); + ok(locinfo->ctype1_refcount != locinfo2->ctype1_refcount, "Got wrong refcount pointer %p vs %p.\n", + locinfo->ctype1_refcount, locinfo2->ctype1_refcount); + ok(locinfo->lc_codepage == 932 && locinfo->lc_codepage == locinfo2->lc_codepage, + "Got wrong codepage %d vs %d.\n", locinfo->lc_codepage, locinfo2->lc_codepage); + ok(locinfo->lc_id[LC_CTYPE].wCodePage == 932 + && locinfo->lc_id[LC_CTYPE].wCodePage == locinfo2->lc_id[LC_CTYPE].wCodePage, + "Got wrong LC_CTYPE codepage %d vs %d.\n", locinfo->lc_id[LC_CTYPE].wCodePage, + locinfo2->lc_id[LC_CTYPE].wCodePage); + ret = strcmp(locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); + ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, + locinfo2->lc_category[LC_CTYPE].locale); + ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); + ok(!ret, "Got wrong ctype1 data.\n"); + ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); + ok(!ret, "Got wrong pclmap data.\n"); + ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); + ok(!ret, "Got wrong pcumap data.\n"); + ok(locinfo->lc_handle[LC_CTYPE] != locinfo2->lc_handle[LC_CTYPE], + "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]); + + p_free_locale(locale2); + locale2 = p_create_locale(LC_ALL, "Japanese_Japan.1252"); + locinfo2 = locale2->locinfo; + + ok(locinfo->mb_cur_max != locinfo2->mb_cur_max, "Got wrong max char size %d %d.\n", + locinfo->mb_cur_max, locinfo2->mb_cur_max); + ok(locinfo->ctype1_refcount != locinfo2->ctype1_refcount, "Got wrong refcount pointer %p vs %p.\n", + locinfo->ctype1_refcount, locinfo2->ctype1_refcount); + ok(locinfo2->lc_codepage == 1252, "Got wrong codepage %d.\n", locinfo2->lc_codepage); + ok(locinfo2->lc_id[LC_CTYPE].wCodePage == 1252, "Got wrong LC_CTYPE codepage %d.\n", + locinfo2->lc_id[LC_CTYPE].wCodePage); + ok(locinfo->lc_codepage != locinfo2->lc_codepage, "Got wrong codepage %d vs %d.\n", + locinfo->lc_codepage, locinfo2->lc_codepage); + ok(locinfo->lc_id[LC_CTYPE].wCodePage != locinfo2->lc_id[LC_CTYPE].wCodePage, + "Got wrong LC_CTYPE codepage %d vs %d.\n", locinfo->lc_id[LC_CTYPE].wCodePage, + locinfo2->lc_id[LC_CTYPE].wCodePage); + ret = strcmp(locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); + ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, + locinfo2->lc_category[LC_CTYPE].locale); + ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); + ok(!!ret, "Got wrong ctype1 data.\n"); + ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); + ok(!!ret, "Got wrong pclmap data.\n"); + ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); + ok(!!ret, "Got wrong pcumap data.\n"); + ok(locinfo->lc_handle[LC_CTYPE] == locinfo2->lc_handle[LC_CTYPE], + "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]); + + p_free_locale(locale2); + locale2 = p_create_locale(LC_ALL, "Japanese_Japan.3000"); /* an invalid codepage */ + ok(!locale2, "Got %p.\n", locale2); + + p_free_locale(locale); + } + + locale = p_create_locale(LC_ALL, "German_Germany.437"); + locale2 = p_create_locale(LC_ALL, "German_Germany.1252"); + locinfo = locale->locinfo; + locinfo2 = locale2->locinfo; + + ok(locinfo->mb_cur_max == locinfo2->mb_cur_max, "Got wrong max char size %d %d.\n", + locinfo->mb_cur_max, locinfo2->mb_cur_max); + ok(locinfo->ctype1_refcount != locinfo2->ctype1_refcount, "Got wrong refcount pointer %p vs %p.\n", + locinfo->ctype1_refcount, locinfo2->ctype1_refcount); + ok(locinfo->lc_codepage != locinfo2->lc_codepage, "Got wrong codepage %d vs %d.\n", + locinfo->lc_codepage, locinfo2->lc_codepage); + ok(locinfo->lc_id[LC_CTYPE].wCodePage != locinfo2->lc_id[LC_CTYPE].wCodePage, + "Got wrong LC_CTYPE codepage %d vs %d.\n", locinfo->lc_id[LC_CTYPE].wCodePage, + locinfo2->lc_id[LC_CTYPE].wCodePage); + ret = strcmp(locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); + ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, + locinfo2->lc_category[LC_CTYPE].locale); + ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); + ok(!!ret, "Got wrong ctype1 data.\n"); + ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); + ok(!!ret, "Got wrong pclmap data.\n"); + ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); + ok(!!ret, "Got wrong pcumap data.\n"); + ok(locinfo->lc_handle[LC_CTYPE] == locinfo2->lc_handle[LC_CTYPE], + "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]); + + p_free_locale(locale2); + p_free_locale(locale); +} + START_TEST(locale) { init(); @@ -783,4 +985,7 @@ START_TEST(locale) test_setlocale(); test__Gettnames(); test___mb_cur_max_func(); + test__wcsicmp_l(); + test_thread_setlocale(); + test_locale_info(); } diff --git a/modules/rostests/winetests/msvcrt/misc.c b/modules/rostests/winetests/msvcrt/misc.c index d82f71e122e..7b54b3aeb88 100644 --- a/modules/rostests/winetests/msvcrt/misc.c +++ b/modules/rostests/winetests/msvcrt/misc.c @@ -20,31 +20,12 @@ #include "wine/test.h" #include +#include +#include #include #include -#include "msvcrt.h" #include -static inline float __port_infinity(void) -{ - static const unsigned __inf_bytes = 0x7f800000; - return *(const float *)&__inf_bytes; -} -#ifdef __REACTOS__ -#undef INFINITY -#endif -#define INFINITY __port_infinity() - -static inline float __port_nan(void) -{ - static const unsigned __nan_bytes = 0x7fc00000; - return *(const float *)&__nan_bytes; -} -#ifdef __REACTOS__ -#undef NAN -#endif -#define NAN __port_nan() - static inline BOOL almost_equal(double d1, double d2) { if(d1-d2>-1e-30 && d1-d2<1e-30) return TRUE; @@ -56,14 +37,14 @@ struct uld { ULONG lo, hi, exp; }; static int (__cdecl *prand_s)(unsigned int *); static int (__cdecl *pI10_OUTPUT)(struct uld, int, int, void*); -static int (__cdecl *pstrerror_s)(char *, MSVCRT_size_t, int); +static int (__cdecl *pstrerror_s)(char *, size_t, int); static int (__cdecl *p_get_doserrno)(int *); static int (__cdecl *p_get_errno)(int *); static int (__cdecl *p_set_doserrno)(int); static int (__cdecl *p_set_errno)(int); static void (__cdecl *p__invalid_parameter)(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t); -static void (__cdecl *p_qsort_s)(void*, MSVCRT_size_t, MSVCRT_size_t, +static void (__cdecl *p_qsort_s)(void*, size_t, size_t, int (__cdecl*)(void*, const void*, const void*), void*); static double (__cdecl *p_atan)(double); static double (__cdecl *p_exp)(double); @@ -194,7 +175,7 @@ static void test_I10_OUTPUT(void) j = strlen(I10_OUTPUT_tests[i].remain); todo_wine_if(j && I10_OUTPUT_tests[i].remain[j-1]=='9') ok(!strncmp(out.str+out.len+1, I10_OUTPUT_tests[i].remain, j), - "%d: &out.str[%d] = %.25s...\n", i, out.len+1, out.str+out.len+1); + "%d: &out.str[%d] = %.25s...\n", i, out.len+1, out.str+out.len+1); for(j=out.len+strlen(I10_OUTPUT_tests[i].remain)+1; j= 3) { - if(!strcmp(arg_v[2], "popen")) - test__popen_child(); + if (!strcmp(arg_v[2], "popen_read")) + test__popen_read_child(); + else if(arg_c == 4 && !strcmp(arg_v[2], "popen")) + test__popen_child(atoi(arg_v[3])); else ok(0, "invalid argument '%s'\n", arg_v[2]); @@ -705,5 +769,6 @@ START_TEST(misc) test_qsort_s(); test_math_functions(); test_thread_handle_close(); + test_thread_suspended(); test__lfind_s(); } diff --git a/modules/rostests/winetests/msvcrt/printf.c b/modules/rostests/winetests/msvcrt/printf.c index 4bf55afc1ff..dc0038b3372 100644 --- a/modules/rostests/winetests/msvcrt/printf.c +++ b/modules/rostests/winetests/msvcrt/printf.c @@ -23,9 +23,7 @@ /* With Visual Studio >= 2005, swprintf() takes an extra parameter unless * the following macro is defined. */ -#ifndef _CRT_NON_CONFORMING_SWPRINTFS #define _CRT_NON_CONFORMING_SWPRINTFS -#endif #include #include @@ -38,24 +36,6 @@ #include "wine/test.h" -#ifndef __REACTOS__ - -static inline float __port_infinity(void) -{ - static const unsigned __inf_bytes = 0x7f800000; - return *(const float *)&__inf_bytes; -} -#define INFINITY __port_infinity() - -static inline float __port_nan(void) -{ - static const unsigned __nan_bytes = 0x7fc00000; - return *(const float *)&__nan_bytes; -} -#define NAN __port_nan() - -#endif - static inline float __port_ind(void) { static const unsigned __ind_bytes = 0xffc00000; @@ -63,11 +43,11 @@ static inline float __port_ind(void) } #define IND __port_ind() -static int (__cdecl *p__vscprintf)(const char *format, __ms_va_list valist); -static int (__cdecl *p__vscwprintf)(const wchar_t *format, __ms_va_list valist); +static int (__cdecl *p__vscprintf)(const char *format, va_list valist); +static int (__cdecl *p__vscwprintf)(const wchar_t *format, va_list valist); static int (__cdecl *p__vsnwprintf_s)(wchar_t *str, size_t sizeOfBuffer, size_t count, const wchar_t *format, - __ms_va_list valist); + va_list valist); static int (__cdecl *p__ecvt_s)(char *buffer, size_t length, double number, int ndigits, int *decpt, int *sign); static int (__cdecl *p__fcvt_s)(char *buffer, size_t length, double number, @@ -75,17 +55,17 @@ static int (__cdecl *p__fcvt_s)(char *buffer, size_t length, double number, static unsigned int (__cdecl *p__get_output_format)(void); static unsigned int (__cdecl *p__set_output_format)(unsigned int); static int (WINAPIV *p_sprintf)(char*, ...); -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); +static int (__cdecl *p__vsprintf_p)(char*, size_t, const char*, va_list); +static int (__cdecl *p_vswprintf)(wchar_t *str, const wchar_t *format, va_list valist); +static int (__cdecl *p__vswprintf)(wchar_t *str, const wchar_t *format, va_list valist); static int (__cdecl *p__vswprintf_l)(wchar_t *str, const wchar_t *format, - void *locale, __ms_va_list valist); + void *locale, va_list valist); static int (__cdecl *p__vswprintf_c)(wchar_t *str, size_t size, const wchar_t *format, - __ms_va_list valist); + va_list valist); static int (__cdecl *p__vswprintf_c_l)(wchar_t *str, size_t size, const wchar_t *format, - void *locale, __ms_va_list valist); + void *locale, va_list valist); static int (__cdecl *p__vswprintf_p_l)(wchar_t *str, size_t size, const wchar_t *format, - void *locale, __ms_va_list valist); + void *locale, va_list valist); static void init( void ) { @@ -110,466 +90,295 @@ static void init( void ) static void test_sprintf( void ) { + enum { + NO_ARG, + INT_ARG, + ULONGLONG_ARG, + DOUBLE_ARG, + PTR_ARG, + TODO_FLAG = 0x1000 + }; + + struct { + const char *format; + const char *out; + const char *broken; + int type; + int arg_i; + ULONGLONG arg_ull; + double arg_d; + const void *arg_ptr; + } tests[] = { + { "%+#23.15e", "+7.894561230000000e+008", 0, DOUBLE_ARG, 0, 0, 789456123 }, + { "%-#23.15e", "7.894561230000000e+008 ", 0, DOUBLE_ARG, 0, 0, 789456123 }, + { "%#23.15e", " 7.894561230000000e+008", 0, DOUBLE_ARG, 0, 0, 789456123 }, + { "%#1.1g", "8.e+008", 0, DOUBLE_ARG, 0, 0, 789456123 }, + { "%I64d", "-8589934591", 0, ULONGLONG_ARG, 0, ((ULONGLONG)0xffffffff)*0xffffffff }, + { "%+8I64d", " +100", 0, ULONGLONG_ARG, 0, 100 }, + { "%+.8I64d", "+00000100", 0, ULONGLONG_ARG, 0, 100 }, + { "%+10.8I64d", " +00000100", 0, ULONGLONG_ARG, 0, 100 }, + { "%_1I64d", "_1I64d", 0, ULONGLONG_ARG, 0, 100 }, + { "%-1.5I64d", "-00100", 0, ULONGLONG_ARG, 0, -100 }, + { "%5I64d", " 100", 0, ULONGLONG_ARG, 0, 100 }, + { "%5I64d", " -100", 0, ULONGLONG_ARG, 0, -100 }, + { "%-5I64d", "100 ", 0, ULONGLONG_ARG, 0, 100 }, + { "%-5I64d", "-100 ", 0, ULONGLONG_ARG, 0, -100 }, + { "%-.5I64d", "00100", 0, ULONGLONG_ARG, 0, 100 }, + { "%-.5I64d", "-00100", 0, ULONGLONG_ARG, 0, -100 }, + { "%-8.5I64d", "00100 ", 0, ULONGLONG_ARG, 0, 100 }, + { "%-8.5I64d", "-00100 ", 0, ULONGLONG_ARG, 0, -100 }, + { "%05I64d", "00100", 0, ULONGLONG_ARG, 0, 100 }, + { "%05I64d", "-0100", 0, ULONGLONG_ARG, 0, -100 }, + { "% I64d", " 100", 0, ULONGLONG_ARG, 0, 100 }, + { "% I64d", "-100", 0, ULONGLONG_ARG, 0, -100 }, + { "% 5I64d", " 100", 0, ULONGLONG_ARG, 0, 100 }, + { "% 5I64d", " -100", 0, ULONGLONG_ARG, 0, -100 }, + { "% .5I64d", " 00100", 0, ULONGLONG_ARG, 0, 100 }, + { "% .5I64d", "-00100", 0, ULONGLONG_ARG, 0, -100 }, + { "% 8.5I64d", " 00100", 0, ULONGLONG_ARG, 0, 100 }, + { "% 8.5I64d", " -00100", 0, ULONGLONG_ARG, 0, -100 }, + { "%.0I64d", "", 0, ULONGLONG_ARG }, + { "%#+21.18I64x", " 0x00ffffffffffffff9c", 0, ULONGLONG_ARG, 0, -100 }, + { "%#.25I64o", "0001777777777777777777634", 0, ULONGLONG_ARG, 0, -100 }, + { "%#+24.20I64o", " 01777777777777777777634", 0, ULONGLONG_ARG, 0, -100 }, + { "%#+18.21I64X", "0X00000FFFFFFFFFFFFFF9C", 0, ULONGLONG_ARG, 0, -100 }, + { "%#+20.24I64o", "001777777777777777777634", 0, ULONGLONG_ARG, 0, -100 }, + { "%#+25.22I64u", " 0018446744073709551615", 0, ULONGLONG_ARG, 0, -1 }, + { "%#+25.22I64u", " 0018446744073709551615", 0, ULONGLONG_ARG, 0, -1 }, + { "%#+30.25I64u", " 0000018446744073709551615", 0, ULONGLONG_ARG, 0, -1 }, + { "%+#25.22I64d", " -0000000000000000000001", 0, ULONGLONG_ARG, 0, -1 }, + { "%#-8.5I64o", "00144 ", 0, ULONGLONG_ARG, 0, 100 }, + { "%#-+ 08.5I64d", "+00100 ", 0, ULONGLONG_ARG, 0, 100 }, + { "%.80I64d", + "00000000000000000000000000000000000000000000000000000000000000000000000000000001", + 0, ULONGLONG_ARG, 0, 1 }, + { "% .80I64d", + " 00000000000000000000000000000000000000000000000000000000000000000000000000000001", + 0, ULONGLONG_ARG, 0, 1 }, + { "% .80d", + " 00000000000000000000000000000000000000000000000000000000000000000000000000000001", + 0, INT_ARG, 1 }, + { "%I", "I", 0, INT_ARG, 1 }, + { "%Iq", "Iq", 0, INT_ARG, 1 }, + { "%Ihd", "Ihd", 0, INT_ARG, 1 }, + { "%I0d", "I0d", 0, INT_ARG, 1 }, + { "%I64D", "D", 0, ULONGLONG_ARG, 0, -1 }, + { "%zx", "1", "zx", INT_ARG, 1 }, + { "%z", "z", 0, INT_ARG, 1 }, + { "%tx", "1", "tx", INT_ARG, 1 }, + { "%t", "t", 0, INT_ARG, 1 }, + { "% d", " 1", 0, INT_ARG, 1 }, + { "%+ d", "+1", 0, INT_ARG, 1 }, + { "%S", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%04c", "0001", 0, INT_ARG, '1' }, + { "%-04c", "1 ", 0, INT_ARG, '1' }, + { "%#012x", "0x0000000001", 0, INT_ARG, 1 }, + { "%#012x", "000000000000", 0, INT_ARG, 0 }, + { "%#04.8x", "0x00000001", 0, INT_ARG, 1 }, + { "%#04.8x", "00000000", 0, INT_ARG, 0 }, + { "%#-08.2x", "0x01 ", 0, INT_ARG, 1 }, + { "%#-08.2x", "00 ", 0, INT_ARG, 0 }, + { "%#.0x", "0x1", 0, INT_ARG, 1 }, + { "%#.0x", "", 0, INT_ARG, 0 }, + { "%#08o", "00000001", 0, INT_ARG, 1 }, + { "%#o", "01", 0, INT_ARG, 1 }, + { "%#o", "0", 0, INT_ARG, 0 }, + { "%04s", "0foo", 0, PTR_ARG, 0, 0, 0, "foo" }, + { "%.1s", "f", 0, PTR_ARG, 0, 0, 0, "foo" }, + { "hello", "hello", 0, NO_ARG }, + { "%ws", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%-10ws", "wide ", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%10ws", " wide", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%#+ -03whlls", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%w0s", "0s", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%w-s", "-s", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%ls", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" }, + { "%Ls", "not wide", 0, PTR_ARG, 0, 0, 0, "not wide" }, + { "%b", "b", 0, NO_ARG }, + { "%3c", " a", 0, INT_ARG, 'a' }, + { "%3d", "1234", 0, INT_ARG, 1234 }, + { "%3h", "", 0, NO_ARG }, + { "%k%m%q%r%t%v%y%z", "kmqrtvyz", 0, NO_ARG }, + { "%-1d", "2", 0, INT_ARG, 2 }, + { "%2.4f", "8.6000", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "%0f", "0.600000", 0, DOUBLE_ARG, 0, 0, 0.6 }, + { "%.0f", "1", 0, DOUBLE_ARG, 0, 0, 0.6 }, + { "%2.4e", "8.6000e+000", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "% 2.4e", " 8.6000e+000", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "% 014.4e", " 008.6000e+000", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "% 2.4e", "-8.6000e+000", 0, DOUBLE_ARG, 0, 0, -8.6 }, + { "%+2.4e", "+8.6000e+000", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "%2.4g", "8.6", 0, DOUBLE_ARG, 0, 0, 8.6 }, + { "%-i", "-1", 0, INT_ARG, -1 }, + { "%-i", "1", 0, INT_ARG, 1 }, + { "%+i", "+1", 0, INT_ARG, 1 }, + { "%o", "12", 0, INT_ARG, 10 }, + { "%s", "(null)", 0, PTR_ARG, 0, 0, 0, NULL }, + { "%s", "%%%%", 0, PTR_ARG, 0, 0, 0, "%%%%" }, + { "%u", "4294967295", 0, INT_ARG, -1 }, + { "%w", "", 0, INT_ARG, -1 }, + { "%h", "", 0, INT_ARG, -1 }, + { "%j", "", "j", ULONGLONG_ARG, 0, -1 }, + { "%jd", "-1", "jd", ULONGLONG_ARG, 0, -1 }, + { "%F", "", 0, INT_ARG, -1 }, + { "%N", "", 0, INT_ARG, -1 }, + { "%H", "H", 0, INT_ARG, -1 }, + { "x%cx", "xXx", 0, INT_ARG, 0x100+'X' }, + { "%%0", "%0", 0, NO_ARG }, + { "%hx", "2345", 0, INT_ARG, 0x12345 }, + { "%hhx", "123", 0, INT_ARG, 0x123 }, + { "%hhx", "2345", 0, INT_ARG, 0x12345 }, + { "%lf", "-1.#IND00", 0, DOUBLE_ARG, 0, 0, IND }, + { "%lf", "1.#QNAN0", 0, DOUBLE_ARG, 0, 0, NAN }, + { "%lf", "1.#INF00", 0, DOUBLE_ARG, 0, 0, INFINITY }, + { "%le", "-1.#IND00e+000", 0, DOUBLE_ARG, 0, 0, IND }, + { "%le", "1.#QNAN0e+000", 0, DOUBLE_ARG, 0, 0, NAN }, + { "%le", "1.#INF00e+000", 0, DOUBLE_ARG, 0, 0, INFINITY }, + { "%lg", "-1.#IND", 0, DOUBLE_ARG, 0, 0, IND }, + { "%lg", "1.#QNAN", 0, DOUBLE_ARG, 0, 0, NAN }, + { "%lg", "1.#INF", 0, DOUBLE_ARG, 0, 0, INFINITY }, + { "%010.2lf", "-000001.#J", 0, DOUBLE_ARG, 0, 0, IND }, + { "%010.2lf", "0000001.#R", 0, DOUBLE_ARG, 0, 0, NAN }, + { "%010.2lf", "0000001.#J", 0, DOUBLE_ARG, 0, 0, INFINITY }, + { "%c", "a", 0, INT_ARG, 'a' }, + { "%c", "\x82", 0, INT_ARG, 0xa082 }, + { "%C", "a", 0, INT_ARG, 'a' }, + { "%C", "", 0, INT_ARG, 0x3042 }, + { "a%Cb", "ab", 0, INT_ARG, 0x3042 }, + { "%lld", "-8589934591", "1", ULONGLONG_ARG, 0, ((ULONGLONG)0xffffffff)*0xffffffff }, + { "%I32d", "1", "I32d", INT_ARG, 1 }, + { "%.0f", "-2", 0, DOUBLE_ARG, 0, 0, -1.5 }, + { "%.0f", "-1", 0, DOUBLE_ARG, 0, 0, -0.5 }, + { "%.0f", "1", 0, DOUBLE_ARG, 0, 0, 0.5 }, + { "%.0f", "2", 0, DOUBLE_ARG, 0, 0, 1.5 }, + { "%.30f", "0.333333333333333310000000000000", 0, TODO_FLAG | DOUBLE_ARG, 0, 0, 1.0/3.0 }, + { "%.30lf", "1.414213562373095100000000000000", 0, TODO_FLAG | DOUBLE_ARG, 0, 0, sqrt(2) }, + { "%f", "3.141593", 0, DOUBLE_ARG, 0, 0, 3.141592653590000 }, + { "%.10f", "3.1415926536", 0, DOUBLE_ARG, 0, 0, 3.141592653590000 }, + { "%.11f", "3.14159265359", 0, DOUBLE_ARG, 0, 0, 3.141592653590000 }, + { "%.15f", "3.141592653590000", 0, DOUBLE_ARG, 0, 0, 3.141592653590000 }, + { "%.15f", "3.141592653589793", 0, DOUBLE_ARG, 0, 0, M_PI }, + { "%.13f", "37.8662615745371", 0, DOUBLE_ARG, 0, 0, 37.866261574537077 }, + { "%.14f", "37.86626157453708", 0, DOUBLE_ARG, 0, 0, 37.866261574537077 }, + { "%.15f", "37.866261574537077", 0, DOUBLE_ARG, 0, 0, 37.866261574537077 }, + { "%g", "0.0005", 0, DOUBLE_ARG, 0, 0, 0.0005 }, + { "%g", "5e-005", 0, DOUBLE_ARG, 0, 0, 0.00005 }, + { "%g", "5e-006", 0, DOUBLE_ARG, 0, 0, 0.000005 }, + { "%g", "1e+015", 0, DOUBLE_ARG, 0, 0, 999999999999999.0 }, + { "%g", "1e+015", 0, DOUBLE_ARG, 0, 0, 1000000000000000.0 }, + { "%.15g", "0.0005", 0, DOUBLE_ARG, 0, 0, 0.0005 }, + { "%.15g", "5e-005", 0, DOUBLE_ARG, 0, 0, 0.00005 }, + { "%.15g", "5e-006", 0, DOUBLE_ARG, 0, 0, 0.000005 }, + { "%.15g", "999999999999999", 0, DOUBLE_ARG, 0, 0, 999999999999999.0 }, + { "%.15g", "1e+015", 0, DOUBLE_ARG, 0, 0, 1000000000000000.0 }, + }; + char buffer[100]; - const char *format; - double pnumber=789456123; - int x, r; - WCHAR wide[] = { 'w','i','d','e',0}; - WCHAR buf_w[2]; + int i, x, r; - format = "%+#23.15e"; - r = p_sprintf(buffer,format,pnumber); - ok(!strcmp(buffer,"+7.894561230000000e+008"),"+#23.15e failed: '%s'\n", buffer); - ok( r==23, "return count wrong\n"); + for (i=0; i 1.0 with 0 or -ve precision */ + { -0.0, 5, "00000", "00000", 0, 0, 1 }, + { -0.0, 0, "", "", 0, 0, 1 }, + { -0.0, -1, "", "", 0, 0, 1 }, { -123.0001, 0, "", "123", 3, 3, 1 }, { -123.0001, -1, "", "12", 3, 3, 1 }, { -123.0001, -2, "", "1", 3, 3, 1 }, { -123.0001, -3, "", "", 3, 3, 1 }, - /* Numbers > 1.0, but with rounding at the point of precision */ { 99.99, 1, "1", "1000", 3, 3, 0 }, - /* Numbers < 1.0 where rounding occurs at the point of precision */ { 0.0063, 2, "63", "1", -2, -1, 0 }, { 0.0063, 3, "630", "6", -2, -2, 0 }, { 0.09999999996, 2, "10", "10", 0, 0, 0 }, @@ -1105,12 +691,18 @@ static struct { { 0.4, 0, "", "", 0, 0, 0 }, { 0.49, 0, "", "", 0, 0, 0 }, { 0.51, 0, "", "1", 1, 1, 0 }, - /* ask for ridiculous precision, ruin formatting this table */ + { NAN, 2, "1$", "1#R", 1, 1, 0 }, + { NAN, 5, "1#QNB", "1#QNAN", 1, 1, 0 }, + { -NAN, 2, "1$", "1#J", 1, 1, 1 }, + { -NAN, 5, "1#IND", "1#IND0", 1, 1, 1 }, + { INFINITY, 2, "1$", "1#J", 1, 1, 0 }, + { INFINITY, 5, "1#INF", "1#INF0", 1, 1, 0 }, + { -INFINITY, 2, "1$", "1#J", 1, 1, 1 }, + { -INFINITY, 5, "1#INF", "1#INF0", 1, 1, 1 }, { 1.0, 30, "100000000000000000000000000000", "1000000000000000000000000000000", 1, 1, 0}, { 123456789012345678901.0, 30, "123456789012345680000000000000", "123456789012345680000000000000000000000000000000000", 21, 21, 0}, - /* end marker */ { 0, 0, "END"} }; @@ -1125,14 +717,14 @@ static void test_xcvt(void) test_cvt_testcases[i].nrdigits, &decpt, &sign); - ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_e, 15), - "_ecvt() bad return, got \n'%s' expected \n'%s'\n", str, + ok( !strncmp( str, test_cvt_testcases[i].expstr_e, 15), + "%d) _ecvt() bad return, got '%s' expected '%s'\n", i, str, test_cvt_testcases[i].expstr_e); ok( decpt == test_cvt_testcases[i].expdecpt_e, - "_ecvt() decimal point wrong, got %d expected %d\n", decpt, + "%d) _ecvt() decimal point wrong, got %d expected %d\n", i, decpt, test_cvt_testcases[i].expdecpt_e); ok( sign == test_cvt_testcases[i].expsign, - "_ecvt() sign wrong, got %d expected %d\n", sign, + "%d) _ecvt() sign wrong, got %d expected %d\n", i, sign, test_cvt_testcases[i].expsign); } for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ @@ -1141,14 +733,14 @@ static void test_xcvt(void) test_cvt_testcases[i].nrdigits, &decpt, &sign); - ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15), - "_fcvt() bad return, got \n'%s' expected \n'%s'\n", str, + ok( !strncmp( str, test_cvt_testcases[i].expstr_f, 15), + "%d) _fcvt() bad return, got '%s' expected '%s'\n", i, str, test_cvt_testcases[i].expstr_f); ok( decpt == test_cvt_testcases[i].expdecpt_f, - "_fcvt() decimal point wrong, got %d expected %d\n", decpt, + "%d) _fcvt() decimal point wrong, got %d expected %d\n", i, decpt, test_cvt_testcases[i].expdecpt_f); ok( sign == test_cvt_testcases[i].expsign, - "_fcvt() sign wrong, got %d expected %d\n", sign, + "%d) _fcvt() sign wrong, got %d expected %d\n", i, sign, test_cvt_testcases[i].expsign); } @@ -1159,14 +751,14 @@ static void test_xcvt(void) decpt = sign = 100; err = p__ecvt_s(str, 1024, test_cvt_testcases[i].value, test_cvt_testcases[i].nrdigits, &decpt, &sign); ok(err == 0, "_ecvt_s() failed with error code %d\n", err); - ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_e, 15), - "_ecvt_s() bad return, got \n'%s' expected \n'%s'\n", str, + ok( !strncmp( str, test_cvt_testcases[i].expstr_e, 15), + "%d) _ecvt_s() bad return, got '%s' expected '%s'\n", i, str, test_cvt_testcases[i].expstr_e); ok( decpt == test_cvt_testcases[i].expdecpt_e, - "_ecvt_s() decimal point wrong, got %d expected %d\n", decpt, + "%d) _ecvt_s() decimal point wrong, got %d expected %d\n", i, decpt, test_cvt_testcases[i].expdecpt_e); ok( sign == test_cvt_testcases[i].expsign, - "_ecvt_s() sign wrong, got %d expected %d\n", sign, + "%d) _ecvt_s() sign wrong, got %d expected %d\n", i, sign, test_cvt_testcases[i].expsign); } free(str); @@ -1203,15 +795,15 @@ static void test_xcvt(void) for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ decpt = sign = 100; err = p__fcvt_s(str, 1024, test_cvt_testcases[i].value, test_cvt_testcases[i].nrdigits, &decpt, &sign); - ok(err == 0, "_fcvt_s() failed with error code %d\n", err); - ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15), - "_fcvt_s() bad return, got '%s' expected '%s'. test %d\n", str, + ok(!err, "%d) _fcvt_s() failed with error code %d\n", i, err); + ok( !strncmp( str, test_cvt_testcases[i].expstr_f, 15), + "%d) _fcvt_s() bad return, got '%s' expected '%s'. test %d\n", i, str, test_cvt_testcases[i].expstr_f, i); ok( decpt == test_cvt_testcases[i].expdecpt_f, - "_fcvt_s() decimal point wrong, got %d expected %d\n", decpt, + "%d) _fcvt_s() decimal point wrong, got %d expected %d\n", i, decpt, test_cvt_testcases[i].expdecpt_f); ok( sign == test_cvt_testcases[i].expsign, - "_fcvt_s() sign wrong, got %d expected %d\n", sign, + "%d) _fcvt_s() sign wrong, got %d expected %d\n", i, sign, test_cvt_testcases[i].expsign); } free(str); @@ -1223,104 +815,94 @@ static void test_xcvt(void) static int WINAPIV _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = _vsnwprintf(str, len, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static void test_vsnwprintf(void) { - const wchar_t format[] = {'%','w','s','%','w','s','%','w','s',0}; - const wchar_t one[] = {'o','n','e',0}; - const wchar_t two[] = {'t','w','o',0}; - const wchar_t three[] = {'t','h','r','e','e',0}; - int ret; wchar_t str[32]; char buf[32]; - ret = _vsnwprintf_wrapper( str, ARRAY_SIZE(str), format, one, two, three ); - + ret = _vsnwprintf_wrapper( str, ARRAY_SIZE(str), L"%ws%ws%ws", L"one", L"two", L"three" ); ok( ret == 11, "got %d expected 11\n", ret ); WideCharToMultiByte( CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL ); ok( !strcmp(buf, "onetwothree"), "got %s expected 'onetwothree'\n", buf ); - ret = _vsnwprintf_wrapper( str, 0, format, one, two, three ); + ret = _vsnwprintf_wrapper( str, 0, L"%ws%ws%ws", L"one", L"two", L"three" ); ok( ret == -1, "got %d, expected -1\n", ret ); - ret = _vsnwprintf_wrapper( NULL, 0, format, one, two, three ); + ret = _vsnwprintf_wrapper( NULL, 0, L"%ws%ws%ws", L"one", L"two", L"three" ); ok( ret == 11 || broken(ret == -1 /* Win2k */), "got %d, expected 11\n", ret ); } static int WINAPIV vswprintf_wrapper(wchar_t *str, const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p_vswprintf(str, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static int WINAPIV _vswprintf_wrapper(wchar_t *str, const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vswprintf(str, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static int WINAPIV _vswprintf_l_wrapper(wchar_t *str, const wchar_t *format, void *locale, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, locale); + va_list valist; + va_start(valist, locale); ret = p__vswprintf_l(str, format, locale, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static int WINAPIV _vswprintf_c_wrapper(wchar_t *str, size_t size, const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vswprintf_c(str, size, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static int WINAPIV _vswprintf_c_l_wrapper(wchar_t *str, size_t size, const wchar_t *format, void *locale, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, locale); + va_list valist; + va_start(valist, locale); ret = p__vswprintf_c_l(str, size, format, locale, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static int WINAPIV _vswprintf_p_l_wrapper(wchar_t *str, size_t size, const wchar_t *format, void *locale, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, locale); + va_list valist; + va_start(valist, locale); ret = p__vswprintf_p_l(str, size, format, locale, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static void test_vswprintf(void) { - const wchar_t format[] = {'%','s',' ','%','d',0}; - const wchar_t number[] = {'n','u','m','b','e','r',0}; - const wchar_t out[] = {'n','u','m','b','e','r',' ','1','2','3',0}; wchar_t buf[20]; - int ret; if (!p_vswprintf || !p__vswprintf || !p__vswprintf_l ||!p__vswprintf_c @@ -1330,43 +912,48 @@ static void test_vswprintf(void) return; } - ret = vswprintf_wrapper(buf, format, number, 123); + ret = vswprintf_wrapper(buf, L"%s %d", L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); memset(buf, 0, sizeof(buf)); - ret = _vswprintf_wrapper(buf, format, number, 123); + ret = _vswprintf_wrapper(buf, L"%s %d", L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); memset(buf, 0, sizeof(buf)); - ret = _vswprintf_l_wrapper(buf, format, NULL, number, 123); + ret = _vswprintf_l_wrapper(buf, L"%s %d", NULL, L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); memset(buf, 0, sizeof(buf)); - ret = _vswprintf_c_wrapper(buf, 20, format, number, 123); + ret = _vswprintf_c_wrapper(buf, 20, L"%s %d", L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); + + memset(buf, 'x', sizeof(buf)); + ret = _vswprintf_c_wrapper(buf, 10, L"%s %d", L"number", 123); + ok(ret == -1, "got %d, expected -1\n", ret); + ok(!wcscmp(buf, L"number 12"), "buf = %s\n", wine_dbgstr_w(buf)); memset(buf, 0, sizeof(buf)); - ret = _vswprintf_c_l_wrapper(buf, 20, format, NULL, number, 123); + ret = _vswprintf_c_l_wrapper(buf, 20, L"%s %d", NULL, L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); memset(buf, 0, sizeof(buf)); - ret = _vswprintf_p_l_wrapper(buf, 20, format, NULL, number, 123); + ret = _vswprintf_p_l_wrapper(buf, 20, L"%s %d", NULL, L"number", 123); ok(ret == 10, "got %d, expected 10\n", ret); - ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf)); + ok(!wcscmp(buf, L"number 123"), "buf = %s\n", wine_dbgstr_w(buf)); } static int WINAPIV _vscprintf_wrapper(const char *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vscprintf(format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } @@ -1387,18 +974,15 @@ static void test_vscprintf(void) static int WINAPIV _vscwprintf_wrapper(const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vscwprintf(format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static void test_vscwprintf(void) { - const wchar_t format[] = {'%','s',' ','%','d',0}; - const wchar_t number[] = {'n','u','m','b','e','r',0}; - int ret; if (!p__vscwprintf) @@ -1407,7 +991,7 @@ static void test_vscwprintf(void) return; } - ret = _vscwprintf_wrapper( format, number, 1 ); + ret = _vscwprintf_wrapper(L"%s %d", L"number", 1 ); ok( ret == 8, "got %d expected 8\n", ret ); } @@ -1415,22 +999,17 @@ static int WINAPIV _vsnwprintf_s_wrapper(wchar_t *str, size_t sizeOfBuffer, size_t count, const wchar_t *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vsnwprintf_s(str, sizeOfBuffer, count, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } static void test_vsnwprintf_s(void) { - const wchar_t format[] = { 'A','B','%','u','C',0 }; - const wchar_t out7[] = { 'A','B','1','2','3','C',0 }; - const wchar_t out6[] = { 'A','B','1','2','3',0 }; - const wchar_t out2[] = { 'A',0 }; - const wchar_t out1[] = { 0 }; wchar_t buffer[14] = { 0 }; - int exp, got; + int ret; if (!p__vsnwprintf_s) { @@ -1439,44 +1018,40 @@ static void test_vsnwprintf_s(void) } /* Enough room. */ - exp = wcslen(out7); + ret = _vsnwprintf_s_wrapper(buffer, 14, _TRUNCATE, L"AB%uC", 123); + ok( ret == 6, "length wrong, expect=6, got=%d\n", ret); + ok( !wcscmp(L"AB123C", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - got = _vsnwprintf_s_wrapper(buffer, 14, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); + ret = _vsnwprintf_s_wrapper(buffer, 12, _TRUNCATE, L"AB%uC", 123); + ok( ret == 6, "length wrong, expect=6, got=%d\n", ret); + ok( !wcscmp(L"AB123C", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - got = _vsnwprintf_s_wrapper(buffer, 12, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - - got = _vsnwprintf_s_wrapper(buffer, 7, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); + ret = _vsnwprintf_s_wrapper(buffer, 7, _TRUNCATE, L"AB%uC", 123); + ok( ret == 6, "length wrong, expect=6, got=%d\n", ret); + ok( !wcscmp(L"AB123C", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); /* Not enough room. */ - exp = -1; + ret = _vsnwprintf_s_wrapper(buffer, 6, _TRUNCATE, L"AB%uC", 123); + ok( ret == -1, "length wrong, expect=-1, got=%d\n", ret); + ok( !wcscmp(L"AB123", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - got = _vsnwprintf_s_wrapper(buffer, 6, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out6, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); + ret = _vsnwprintf_s_wrapper(buffer, 2, _TRUNCATE, L"AB%uC", 123); + ok( ret == -1, "length wrong, expect=-1, got=%d\n", ret); + ok( !wcscmp(L"A", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - got = _vsnwprintf_s_wrapper(buffer, 2, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out2, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); - - got = _vsnwprintf_s_wrapper(buffer, 1, _TRUNCATE, format, 123); - ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); - ok( !wcscmp(out1, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); + ret = _vsnwprintf_s_wrapper(buffer, 1, _TRUNCATE, L"AB%uC", 123); + ok( ret == -1, "length wrong, expect=-1, got=%d\n", ret); + ok( !wcscmp(L"", buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); } static int WINAPIV _vsprintf_p_wrapper(char *str, size_t sizeOfBuffer, const char *format, ...) { int ret; - __ms_va_list valist; - __ms_va_start(valist, format); + va_list valist; + va_start(valist, format); ret = p__vsprintf_p(str, sizeOfBuffer, format, valist); - __ms_va_end(valist); + va_end(valist); return ret; } diff --git a/modules/rostests/winetests/msvcrt/scanf.c b/modules/rostests/winetests/msvcrt/scanf.c index 6d38e438c8c..e175342796b 100644 --- a/modules/rostests/winetests/msvcrt/scanf.c +++ b/modules/rostests/winetests/msvcrt/scanf.c @@ -22,6 +22,41 @@ #include "wine/test.h" +static void test_fscanf( void ) +{ + static const char file_name[] = "fscanf.tst"; + static const char contents[] = + "line1\n" + "line2 " + ; + char buf[1024]; + FILE *fp; + int ret; + + fp = fopen(file_name, "wb"); + ok(fp != NULL, "fp = %p\n", fp); + if(!fp) { + skip("failed to create temporary test file\n"); + return; + } + + ret = fprintf(fp, contents); + fclose(fp); + + fp = fopen(file_name, "rb"); + ret = fscanf(fp, "%s", buf); + ok(ret == 1, "ret = %d\n", ret); + ok(strcmp(buf, "line1") == 0, "buf = %s\n", buf); + ret = fscanf(fp, "%s", buf); + ok(ret == 1, "ret = %d\n", ret); + ok(strcmp(buf, "line2") == 0, "buf = %s\n", buf); + ret = fscanf(fp, "%s", buf); + ok(ret == EOF, "ret = %d\n", ret); + fclose(fp); + + unlink(file_name); +} + static void test_sscanf( void ) { /* use function pointers to bypass gcc builtin */ @@ -48,6 +83,14 @@ static void test_sscanf( void ) ret = p_sscanf(buffer, "%d", &result); ok( ret == EOF,"sscanf returns %x instead of %x\n", ret, EOF ); + ret = p_sscanf(" \t\n\n", "%s", buffer); + ok( ret == EOF, "ret = %d\n", ret ); + + buffer1[0] = 'a'; + ret = p_sscanf("test\n", "%s%c", buffer, buffer1); + ok( ret == 2, "ret = %d\n", ret ); + ok( buffer1[0] == '\n', "buffer1[0] = %d\n", buffer1[0] ); + /* check %p */ ok( p_sscanf("000000000046F170", "%p", &ptr) == 1, "sscanf failed\n" ); ok( ptr == (void *)0x46F170,"sscanf reads %p instead of %x\n", ptr, 0x46F170 ); @@ -122,6 +165,12 @@ static void test_sscanf( void ) ok(double_res >= 1.1e-30-1e-45 && double_res <= 1.1e-30+1e-45, "Got %.18le, expected %.18le\n", double_res, 1.1e-30); + buffer[0] = 0; + double_res = 1; + ret = p_sscanf(buffer, "%lf", &double_res); + ok(ret == -1, "expected 0, got %u\n", ret); + ok(double_res == 1, "Got %lf, expected 1\n", double_res); + /* check strings */ ret = p_sprintf(buffer," %s", pname); ok( ret == 26, "expected 26, got %u\n", ret); @@ -137,6 +186,22 @@ 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]); + ret = p_sscanf("-123", "%[-0-9]", buffer); + ok( ret == 1, "Error with format \"%s\"\n", "%[-0-9]"); + ok( strcmp("-123", buffer) == 0, "Error with \"-123\" \"%s\"\n", buffer); + + ret = p_sscanf("-321", "%[0-9-]", buffer); + ok( ret == 1, "Error with format \"%s\"\n", "%[0-9-]"); + ok( strcmp("-321", buffer) == 0, "Error with \"-321\" \"%s\"\n", buffer); + + ret = p_sscanf("-4123", "%[1-2-4]", buffer); + ok( ret == 1, "Error with format \"%s\"\n", "%[1-2-4]"); + ok( strcmp("-412", buffer) == 0, "Error with \"-412\" \"%s\"\n", buffer); + + ret = p_sscanf("-456123", "%[1-2-45-6]", buffer); + ok( ret == 1, "Error with format \"%s\"\n", "%[1-2-45-6]"); + ok( strcmp("-45612", buffer) == 0, "Error with \"-45612\" \"%s\"\n", buffer); + buffer1[0] = 'b'; ret = p_sscanf("a","%s%s", buffer, buffer1); ok( ret == 1, "expected 1, got %u\n", ret); @@ -162,6 +227,30 @@ static void test_sscanf( void ) ok(ret == 1, "Wrong number of arguments read: %d\n", ret); ok(result == 0xdead614e, "Wrong number read (%x)\n", result); + result = 0xdeadbeef; + strcpy(buffer,"12345678"); + ret = p_sscanf(buffer, "%02hd", &result); + ok(ret == 1, "Wrong number of arguments read: %d\n", ret); + ok(result == 0xdead000c, "Wrong number read (%x)\n", result); + + result = 0xdeadbeef; + strcpy(buffer,"12345678"); + ret = p_sscanf(buffer, "%h02d", &result); + ok(ret == 1, "Wrong number of arguments read: %d\n", ret); + ok(result == 0xdead000c, "Wrong number read (%x)\n", result); + + result = 0xdeadbeef; + strcpy(buffer,"12345678"); + ret = p_sscanf(buffer, "%000h02d", &result); + ok(ret == 1, "Wrong number of arguments read: %d\n", ret); + ok(result == 0xdead000c, "Wrong number read (%x)\n", result); + + result = 0xdeadbeef; + strcpy(buffer,"12345678"); + ret = p_sscanf(buffer, "%2h0d", &result); + ok(ret == 1, "Wrong number of arguments read: %d\n", ret); + ok(result == 0xdead614e, "Wrong number read (%x)\n", result); + result = 0xdeadbeef; ret = p_sscanf(buffer, "%hhd", &result); ok(ret == 1, "Wrong number of arguments read: %d\n", ret); @@ -313,35 +402,34 @@ static void test_sscanf_s(void) static void test_swscanf( void ) { - wchar_t buffer[100]; + wchar_t buffer[100], results[100]; int result, ret; - static const WCHAR formatd[] = {'%','d',0}; - const WCHAR format2[] = {'a',0x1234,'%',0x1234,'%','c',0}; WCHAR c; /* check WEOF */ /* WEOF is an unsigned short -1 but swscanf returns int so it should be sign-extended */ buffer[0] = 0; - ret = swscanf(buffer, formatd, &result); + ret = swscanf(buffer, L"%d", &result); /* msvcrt returns 0 but should return -1 (later versions do) */ ok( ret == (short)WEOF || broken(ret == 0), "swscanf returns %x instead of %x\n", ret, WEOF ); + ret = swscanf(L" \t\n\n", L"%s", results); + /* sscanf returns EOF under this case, but swscanf does not return WEOF */ + ok( ret == 0, "ret = %d\n", ret ); + buffer[0] = 'a'; buffer[1] = 0x1234; buffer[2] = 0x1234; buffer[3] = 'b'; - ret = swscanf(buffer, format2, &c); + ret = swscanf(buffer, L"a\x1234%\x1234%c", &c); ok(ret == 1, "swscanf returned %d\n", ret); ok(c == 'b', "c = %x\n", c); } static void test_swscanf_s(void) { - static const wchar_t fmt1[] = {'%','c',0}; - static const wchar_t fmt2[] = {'%','[','a','-','z',']',0}; - int (WINAPIV *pswscanf_s)(const wchar_t*,const wchar_t*,...); HMODULE hmod = GetModuleHandleA("msvcrt.dll"); wchar_t buf[2], out[2]; @@ -356,15 +444,15 @@ static void test_swscanf_s(void) buf[0] = 'a'; buf[1] = '1'; out[1] = 'b'; - ret = pswscanf_s(buf, fmt1, out, 1); + ret = pswscanf_s(buf, L"%c", out, 1); ok(ret == 1, "swscanf_s returned %d\n", ret); ok(out[0] == 'a', "out[0] = %x\n", out[0]); ok(out[1] == 'b', "out[1] = %x\n", out[1]); - ret = pswscanf_s(buf, fmt2, out, 1); + ret = pswscanf_s(buf, L"%[a-z]", out, 1); ok(!ret, "swscanf_s returned %d\n", ret); - ret = pswscanf_s(buf, fmt2, out, 2); + ret = pswscanf_s(buf, L"%[a-z]", out, 2); ok(ret == 1, "swscanf_s returned %d\n", ret); ok(out[0] == 'a', "out[0] = %x\n", out[0]); ok(!out[1], "out[1] = %x\n", out[1]); @@ -372,6 +460,7 @@ static void test_swscanf_s(void) START_TEST(scanf) { + test_fscanf(); test_sscanf(); test_sscanf_s(); test_swscanf(); diff --git a/modules/rostests/winetests/msvcrt/string.c b/modules/rostests/winetests/msvcrt/string.c index 573289d77b5..911a06e47d4 100644 --- a/modules/rostests/winetests/msvcrt/string.c +++ b/modules/rostests/winetests/msvcrt/string.c @@ -28,12 +28,15 @@ #include #include #include +#include #include /* make it use a definition from string.h */ #undef strncpy +#undef wcsncpy #include "winbase.h" #include "winnls.h" +#include "winuser.h" static char *buf_to_string(const unsigned char *bin, int len, int nr) { @@ -56,9 +59,13 @@ static void* (__cdecl *pmemcpy)(void *, const void *, size_t n); static int (__cdecl *p_memcpy_s)(void *, size_t, const void *, size_t); static int (__cdecl *p_memmove_s)(void *, size_t, const void *, size_t); static int* (__cdecl *pmemcmp)(void *, const void *, size_t n); +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t); static int (__cdecl *p_strcpy)(char *dst, const char *src); static int (__cdecl *pstrcpy_s)(char *dst, size_t len, const char *src); static int (__cdecl *pstrcat_s)(char *dst, size_t len, const char *src); +static int (__cdecl *p_strncpy_s)(char *dst, size_t size, const char *src, size_t count); +static int (__cdecl *p_strncat_s)(char *dst, size_t elem, const char *src, size_t count); static int (__cdecl *p_mbscat_s)(unsigned char *dst, size_t size, const unsigned char *src); static int (__cdecl *p_mbsnbcat_s)(unsigned char *dst, size_t size, const unsigned char *src, size_t count); static int (__cdecl *p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsigned char * src, size_t count); @@ -73,6 +80,7 @@ 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 *p_wcstombs_s_l)(size_t*,char*,size_t,const wchar_t*,size_t,_locale_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*); static int (__cdecl *p_mbsrtowcs_s)(size_t*,wchar_t*,size_t,const char**,size_t,mbstate_t*); @@ -87,6 +95,7 @@ static int (__cdecl *p_wcslwr_s)(wchar_t*,size_t); static errno_t (__cdecl *p_mbsupr_s)(unsigned char *str, size_t numberOfElements); static errno_t (__cdecl *p_mbslwr_s)(unsigned char *str, size_t numberOfElements); static int (__cdecl *p_wctob)(wint_t); +static wint_t (__cdecl *p_btowc)(int); static size_t (__cdecl *p_wcrtomb)(char*, wchar_t, mbstate_t*); static int (__cdecl *p_wcrtomb_s)(size_t*, char*, size_t, wchar_t, mbstate_t*); static int (__cdecl *p_tolower)(int); @@ -109,6 +118,12 @@ static int (__cdecl *p__mbccpy_s)(unsigned char*, size_t, int*, const unsigned c static int (__cdecl *p__memicmp)(const char*, const char*, size_t); static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t, _locale_t); static size_t (__cdecl *p___strncnt)(const char*, size_t); +static unsigned int (__cdecl *p_mbsnextc_l)(const unsigned char*, _locale_t); +static int (__cdecl *p_mbscmp_l)(const unsigned char*, const unsigned char*, _locale_t); +static int (__cdecl *p__strnicmp_l)(const char*, const char*, size_t, _locale_t); +static int (__cdecl *p_toupper)(int); + +int CDECL __STRINGTOLD(_LDOUBLE*, char**, const char*, int); #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) @@ -120,13 +135,13 @@ static void test_swab( void ) { char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#"; char expected2[] = "ABCDEFGHIJKLMNOPQRSTUVWX$"; char expected3[] = "$"; - + char from[30]; char to[30]; - + int testsize; - - /* Test 1 - normal even case */ + + /* Test 1 - normal even case */ memset(to,'$', sizeof(to)); memset(from,'@', sizeof(from)); testsize = 26; @@ -134,7 +149,7 @@ static void test_swab( void ) { _swab( from, to, testsize ); ok(memcmp(to,expected1,testsize) == 0, "Testing even size %d returned '%*.*s'\n", testsize, testsize, testsize, to); - /* Test 2 - uneven case */ + /* Test 2 - uneven case */ memset(to,'$', sizeof(to)); memset(from,'@', sizeof(from)); testsize = 25; @@ -142,7 +157,7 @@ static void test_swab( void ) { _swab( from, to, testsize ); ok(memcmp(to,expected2,testsize) == 0, "Testing odd size %d returned '%*.*s'\n", testsize, testsize, testsize, to); - /* Test 3 - from = to */ + /* Test 3 - from = to */ memset(to,'$', sizeof(to)); memset(from,'@', sizeof(from)); testsize = 26; @@ -150,7 +165,7 @@ static void test_swab( void ) { _swab( to, to, testsize ); ok(memcmp(to,expected1,testsize) == 0, "Testing overlapped size %d returned '%*.*s'\n", testsize, testsize, testsize, to); - /* Test 4 - 1 bytes */ + /* Test 4 - 1 bytes */ memset(to,'$', sizeof(to)); memset(from,'@', sizeof(from)); testsize = 1; @@ -159,6 +174,29 @@ static void test_swab( void ) { ok(memcmp(to,expected3,testsize) == 0, "Testing small size %d returned '%*.*s'\n", testsize, testsize, testsize, to); } +static void test_strcspn(void) +{ + static const struct { + const char *str; + const char *rej; + int ret; + } tests[] = { + { "test", "a", 4 }, + { "test", "e", 1 }, + { "test", "", 4 }, + { "", "a", 0 }, + { "a\xf1", "\xf1", 1 } + }; + int r, i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + r = strcspn(tests[i].str, tests[i].rej); + ok(r == tests[i].ret, "strcspn(\"%s\", \"%s\") = %d, expected %d\n", + tests[i].str, tests[i].rej, r, tests[i].ret); + } +} + #if 0 /* use this to generate more tests */ static void test_codepage(int cp) @@ -228,6 +266,7 @@ static void test_mbcp(void) unsigned char *mbstring2 = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5"; /* correct string */ unsigned char *mbsonlylead = (unsigned char *)"\xb0\0\xb1\xb2 \xb3"; unsigned char buf[16]; + unsigned char *ret; int step; CPINFO cp_info; @@ -299,6 +338,7 @@ static void test_mbcp(void) expect_eq(_ismbstrail(mbsonlylead, &mbsonlylead[5]), FALSE, int, "%d"); /* _mbsbtype */ + expect_eq(_mbsbtype(NULL, 0), _MBC_ILLEGAL, int, "%d"); expect_eq(_mbsbtype(mbstring, 0), _MBC_LEAD, int, "%d"); expect_eq(_mbsbtype(mbstring, 1), _MBC_TRAIL, int, "%d"); expect_eq(_mbsbtype(mbstring, 2), _MBC_LEAD, int, "%d"); @@ -321,10 +361,16 @@ static void test_mbcp(void) expect_eq(_mbsnextc(&mbstring[2]), 0xb220, int, "%x"); /* lead + invalid tail */ expect_eq(_mbsnextc(&mbstring[3]), 0x20, int, "%x"); /* single char */ + if (!p_mbsnextc_l) + win_skip("_mbsnextc_l tests\n"); + else + expect_eq(p_mbsnextc_l(mbstring, NULL), 0xb0b1, int, "%x"); + /* _mbclen/_mbslen */ expect_eq(_mbclen(mbstring), 2, int, "%d"); expect_eq(_mbclen(&mbstring[2]), 2, int, "%d"); expect_eq(_mbclen(&mbstring[3]), 1, int, "%d"); + expect_eq(_mbclen(mbsonlylead), 1, int, "%d"); expect_eq(_mbslen(mbstring2), 4, int, "%d"); expect_eq(_mbslen(mbsonlylead), 0, int, "%d"); /* lead + NUL not counted as character */ expect_eq(_mbslen(mbstring), 4, int, "%d"); /* lead + invalid trail counted */ @@ -419,6 +465,53 @@ static void test_mbcp(void) expect_bin(buf, "\x00\xff", 2); } + errno = 0xdeadbeef; + ret = _mbsncpy(NULL, mbstring, 1); + ok(ret == NULL, "_mbsncpy returned %p, expected NULL\n", ret); + ok(errno == EINVAL, "_mbsncpy returned %d\n", errno); + + memset(buf, 0xff, sizeof(buf)); + errno = 0xdeadbeef; + ret = _mbsncpy(buf, NULL, 1); + ok(ret == NULL, "_mbsncpy returned %p, expected NULL\n", ret); + ok(errno == EINVAL, "_mbsncpy returned %d\n", errno); + expect_bin(buf, "\xff\xff\xff", 3); + + errno = 0xdeadbeef; + ret = _mbsncpy(NULL, mbstring, 0); + ok(ret == NULL, "_mbsncpy returned %p, expected NULL\n", ret); + ok(errno == 0xdeadbeef, "_mbsncpy should not change errno\n"); + + memset(buf, 0xff, sizeof(buf)); + errno = 0xdeadbeef; + ret = _mbsncpy(buf, NULL, 0); + ok(ret == buf, "_mbsncpy returned %p, expected %sp\n", ret, buf); + ok(errno == 0xdeadbeef, "_mbsncpy should not change errno\n"); + + memset(buf, 0xff, sizeof(buf)); + errno = 0xdeadbeef; + ret = _mbsncpy(NULL, mbstring, 1); + ok(ret == NULL, "_mbsncpy returned %p, expected NULL\n", ret); + ok(errno == EINVAL, "_mbsncpy returned %d\n", errno); + + memset(buf, 0xff, sizeof(buf)); + errno = 0xdeadbeef; + ret = _mbsncpy(buf, NULL, 1); + ok(ret == NULL, "_mbsncpy returned %p, expected NULL\n", ret); + ok(errno == EINVAL, "_mbsncpy returned %d\n", errno); + + memset(buf, 0xff, sizeof(buf)); + ret = _mbsncpy(NULL, mbstring, 0); + ok(ret == NULL, "_mbsncpy returned %p, expected %p\n", ret, buf); + + memset(buf, 0xff, sizeof(buf)); + ret = _mbsncpy(buf, NULL, 0); + ok(ret == buf, "_mbsncpy returned %p, expected %sp\n", ret, buf); + + memset(buf, 0xff, sizeof(buf)); + ret = _mbsncpy(buf, mbstring, 0); + ok(ret == buf, "_mbsncpy returned %p, expected %p\n", ret, buf); + memset(buf, 0xff, sizeof(buf)); _mbsncpy(buf, mbstring, 1); expect_bin(buf, "\xb0\xb1\xff", 3); @@ -530,6 +623,13 @@ static void test_mbsspn( void) ret=_mbsspn( str1, empty); ok( ret==0, "_mbsspn returns %d should be 0\n", ret); + ret=_mbscspn( str1, set); + ok( ret==0, "_mbscspn returns %d should be 0\n", ret); + ret=_mbscspn( str2, set); + ok( ret==4, "_mbscspn returns %d should be 4\n", ret); + ret=_mbscspn( str1, empty); + ok( ret==8, "_mbscspn returns %d should be 8\n", ret); + _setmbcp( 932); ret=_mbsspn( mbstr, mbset1); ok( ret==8, "_mbsspn returns %d should be 8\n", ret); @@ -542,6 +642,17 @@ static void test_mbsspn( void) ret=_mbsspn( mbstr, mbset3); ok( ret==14, "_mbsspn returns %d should be 14\n", ret); + ret=_mbscspn( mbstr, mbset1); + ok( ret==0, "_mbscspn returns %d should be 0\n", ret); + ret=_mbscspn( mbstr, mbset2); + ok( ret==0, "_mbscspn returns %d should be 0\n", ret); + ret=_mbscspn( mbstr+8, mbset1); + ok( ret==2, "_mbscspn returns %d should be 2\n", ret); + ret=_mbscspn( mbstr+8, mbset2); + ok( ret==0, "_mbscspn returns %d should be 0\n", ret); + ret=_mbscspn( mbstr, mbset3); + ok( ret==0, "_mbscspn returns %d should be 0\n", ret); + _setmbcp( cp); } @@ -582,10 +693,60 @@ static void test_mbsspnp( void) static void test_strdup(void) { - char *str; - str = _strdup( 0 ); - ok( str == 0, "strdup returns %s should be 0\n", str); - free( str ); + char *str; + errno = 0xdeadbeef; + str = strdup(0); + ok(str == 0, "strdup returned %s, expected NULL\n", wine_dbgstr_a(str)); + ok(errno == 0xdeadbeef, "errno is %d, expected 0xdeadbeef\n", errno); +} + +static void test_wcsdup(void) +{ + WCHAR *str; + errno = 0xdeadbeef; + str = wcsdup(0); + ok(str == 0, "wcsdup returned %s, expected NULL\n", wine_dbgstr_w(str)); + ok(errno == 0xdeadbeef, "errno is %d, expected 0xdeadbeef\n", errno); +} + +static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); +#ifdef _WIN64 + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); +#else + ret = p_strncmp( "", "abc", 3 ); + ok( ret == 0 - 'a', "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == 'c' - 0xa0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 0xb0 - 0xa0, "wrong ret %d\n", ret ); +#endif + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); } static void test_strcpy_s(void) @@ -650,6 +811,55 @@ static void test_strcpy_s(void) dest[4] == 'l' && dest[5] == '\0' && dest[6] == '\0' && dest[7] == 'X', "Unexpected return data from strcpy: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + if(!p_strncpy_s) + { + win_skip("strncpy_s not found\n"); + return; + } + + ret = p_strncpy_s(NULL, 18, big, ARRAY_SIZE(big)); + ok(ret == EINVAL, "p_strncpy_s expect EINVAL got %d\n", ret); + + dest[0] = 'A'; + ret = p_strncpy_s(dest, 8, NULL, 1); + ok(ret == EINVAL, "expected EINVAL got %d\n", ret); + ok(dest[0] == 0, "dest[0] not 0\n"); + + dest[0] = 'A'; + ret = p_strncpy_s(dest, 8, NULL, 0); + ok(ret == 0, "expected ERROR_SUCCESS got %d\n", ret); + ok(dest[0] == 0, "dest[0] not 0\n"); + + dest[0] = 'A'; + ret = p_strncpy_s(dest, 0, big, ARRAY_SIZE(big)); + ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(dest[0] == 0 || ret == EINVAL, "dest[0] not 0\n"); + + ret = p_strncpy_s(dest, 8, small, ARRAY_SIZE(small)); + ok(ret == 0, "expected 0 got %d\n", ret); + ok(!strcmp(dest, small), "dest != small\n"); + + dest[0] = 'A'; + ret = p_strncpy_s(dest, 8, big, ARRAY_SIZE(big)); + ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(dest[0] == 0, "dest[0] not 0\n"); + + dest[0] = 'A'; + ret = p_strncpy_s(dest, 5, big, -1); + ok(ret == STRUNCATE, "expected STRUNCATE got %d\n", ret); + ok(dest[4] == 0, "dest[4] not 0\n"); + ok(!memcmp(dest, big, 4), "dest = %s\n", wine_dbgstr_a(dest)); + + ret = p_strncpy_s(NULL, 0, (void*)0xdeadbeef, 0); + ok(ret == 0, "ret = %d\n", ret); + + dest[0] = '1'; + dest[1] = 0; + ret = p_strncpy_s(dest+1, 4, dest, -1); + ok(ret == STRUNCATE, "expected ERROR_SUCCESS got %d\n", ret); + ok(dest[0]=='1' && dest[1]=='1' && dest[2]=='1' && dest[3]=='1', + "dest = %s\n", wine_dbgstr_a(dest)); } #define okchars(dst, b0, b1, b2, b3, b4, b5, b6, b7) \ @@ -1016,7 +1226,7 @@ static void test__mbscpy_s(void) static void test_wcscpy_s(void) { - static const WCHAR szLongText[] = { 'T','h','i','s','A','L','o','n','g','s','t','r','i','n','g',0 }; + static const WCHAR szLongText[] = L"ThisALongstring"; static WCHAR szDest[18]; static WCHAR szDestShort[8]; int ret; @@ -1122,11 +1332,8 @@ static void test_wcscpy_s(void) static void test__wcsupr_s(void) { - static const WCHAR mixedString[] = {'M', 'i', 'X', 'e', 'D', 'l', 'o', 'w', - 'e', 'r', 'U', 'P', 'P', 'E', 'R', 0}; - static const WCHAR expectedString[] = {'M', 'I', 'X', 'E', 'D', 'L', 'O', - 'W', 'E', 'R', 'U', 'P', 'P', 'E', - 'R', 0}; + static const WCHAR mixedString[] = L"MiXeDlowerUPPER"; + static const WCHAR expectedString[] = L"MIXEDLOWERUPPER"; WCHAR testBuffer[2*ARRAY_SIZE(mixedString)]; int ret; @@ -1209,11 +1416,8 @@ static void test__wcsupr_s(void) static void test__wcslwr_s(void) { - static const WCHAR mixedString[] = {'M', 'i', 'X', 'e', 'D', 'l', 'o', 'w', - 'e', 'r', 'U', 'P', 'P', 'E', 'R', 0}; - static const WCHAR expectedString[] = {'m', 'i', 'x', 'e', 'd', 'l', 'o', - 'w', 'e', 'r', 'u', 'p', 'p', 'e', - 'r', 0}; + static const WCHAR mixedString[] = L"MiXeDlowerUPPER"; + static const WCHAR expectedString[] = L"mixedlowerupper"; WCHAR buffer[2*ARRAY_SIZE(mixedString)]; int ret; @@ -1603,6 +1807,14 @@ static void test_strtok(void) "third call string (%p) \'%s\' return %p\n", teststr, testcases_strtok[i].string, strret); } + + strcpy( teststr, "test a=b" ); + strret = strtok( teststr, " " ); + ok( strret == teststr, "strret = %p, expected %p\n", strret, teststr ); + strret = strtok( NULL, "ab=" ); + ok( !strret, "strret = %p, expected NULL\n", strret ); + strret = strtok( NULL, "=" ); + ok( !strret, "strret = %p, expected NULL\n", strret ); } static void test_strtol(void) @@ -1617,58 +1829,58 @@ static void test_strtol(void) /* errno is modified on W2K8+ */ errno = EBADF; l = strtol("-1234", &e, 0); - ok(l==-1234, "wrong value %d\n", l); + ok(l==-1234, "wrong value %ld\n", l); ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); errno = EBADF; ul = strtoul("1234", &e, 0); - ok(ul==1234, "wrong value %u\n", ul); + ok(ul==1234, "wrong value %lu\n", ul); ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); errno = EBADF; l = strtol("2147483647L", &e, 0); - ok(l==2147483647, "wrong value %d\n", l); + ok(l==2147483647, "wrong value %ld\n", l); ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); errno = EBADF; l = strtol("-2147483648L", &e, 0); - ok(l==-2147483647L - 1, "wrong value %d\n", l); + ok(l==-2147483647L - 1, "wrong value %ld\n", l); ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); errno = EBADF; ul = strtoul("4294967295UL", &e, 0); - ok(ul==4294967295ul, "wrong value %u\n", ul); + ok(ul==4294967295ul, "wrong value %lu\n", ul); ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); errno = 0; l = strtol("9223372036854775807L", &e, 0); - ok(l==2147483647, "wrong value %d\n", l); + ok(l==2147483647, "wrong value %ld\n", l); ok(errno == ERANGE, "wrong errno %d\n", errno); errno = 0; ul = strtoul("9223372036854775807L", &e, 0); - ok(ul==4294967295ul, "wrong value %u\n", ul); + ok(ul==4294967295ul, "wrong value %lu\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(ul == -2, "wrong value %lu\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(ul == 2, "wrong value %lu\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(ul==1, "wrong value %lu\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(ul == 1, "wrong value %lu\n", ul); ok(errno == ERANGE, "wrong errno %d\n", errno); errno = 0; l = strtol(neg, &e, 0); - ok(l == 0, "wrong value %d\n", l); + ok(l == 0, "wrong value %ld\n", l); ok(errno == 0, "wrong errno %d\n", errno); ok(e == neg, "e = %p, neg = %p\n", e, neg); } @@ -1838,56 +2050,75 @@ static void test__strtoi64(void) ok(errno == ERANGE, "errno = %x\n", errno); } -static inline BOOL almost_equal(double d1, double d2) { - if(d1-d2>-1e-30 && d1-d2<1e-30) - return TRUE; - return FALSE; +static inline BOOL compare_double(double f, double g, unsigned int ulps) +{ + ULONGLONG x = *(ULONGLONG *)&f; + ULONGLONG y = *(ULONGLONG *)&g; + + if (f < 0) + x = ~x + 1; + else + x |= ((ULONGLONG)1)<<63; + if (g < 0) + y = ~y + 1; + else + y |= ((ULONGLONG)1)<<63; + + return (x>y ? x-y : y-x) <= ulps; } static void test__strtod(void) { - const char double1[] = "12.1"; - const char double2[] = "-13.721"; - const char double3[] = "INF"; - const char double4[] = ".21e12"; - const char double5[] = "214353e-3"; - const char double6[] = "NAN"; + static const struct { + const char *str; + int len; + double ret; + int err; + } tests[] = { + { "12.1", 4, 12.1 }, + { "-13.721", 7, -13.721 }, + { "INF", 0, 0 }, + { ".21e12", 6, 210000000000.0 }, + { "214353e-3", 9, 214.353 }, + { "NAN", 0, 0 }, + { "12.1d2", 6, 12.1e2 }, + { " d10", 0, 0 }, + { "0.1", 3, 0.1 }, + { "-0.1", 4, -0.1 }, + { "0.1281832188491894198128921", 27, 0.1281832188491894198128921 }, + { "0.82181281288121", 16, 0.82181281288121 }, + { "21921922352523587651128218821", 29, 21921922352523587651128218821.0 }, + { "0.1d238", 7, 0.1e238 }, + { "0.1D-4736", 9, 0, ERANGE }, + { "3.4028234663852887e38", 21, FLT_MAX }, + { "1.1754943508222875e-38", 22, FLT_MIN }, + { "1.7976931348623158e+308", 23, DBL_MAX }, + { "1.7976931348623159e+308", 23, INFINITY, ERANGE }, + { "2.2250738585072014e-308", 23, DBL_MIN }, + { "-1.7976931348623158e+308", 24, -DBL_MAX }, + { "-1.7976931348623159e+308", 24, -INFINITY, ERANGE }, + { "00", 2, 0 }, + { "00.", 3, 0 }, + { ".00", 3, 0 }, + { "-0.", 3, 0 }, + { "0e13", 4, 0 }, + }; const char overflow[] = "1d9999999999999999999"; - const char white_chars[] = " d10"; char *end; double d; + int i; - d = strtod(double1, &end); - ok(almost_equal(d, 12.1), "d = %lf\n", d); - ok(end == double1+4, "incorrect end (%d)\n", (int)(end-double1)); - - d = strtod(double2, &end); - ok(almost_equal(d, -13.721), "d = %lf\n", d); - ok(end == double2+7, "incorrect end (%d)\n", (int)(end-double2)); - - d = strtod(double3, &end); - ok(almost_equal(d, 0), "d = %lf\n", d); - ok(end == double3, "incorrect end (%d)\n", (int)(end-double3)); - - d = strtod(double4, &end); - ok(almost_equal(d, 210000000000.0), "d = %lf\n", d); - ok(end == double4+6, "incorrect end (%d)\n", (int)(end-double4)); - - d = strtod(double5, &end); - ok(almost_equal(d, 214.353), "d = %lf\n", d); - ok(end == double5+9, "incorrect end (%d)\n", (int)(end-double5)); - - d = strtod(double6, &end); - ok(almost_equal(d, 0), "d = %lf\n", d); - ok(end == double6, "incorrect end (%d)\n", (int)(end-double6)); - - d = strtod("12.1d2", NULL); - ok(almost_equal(d, 12.1e2), "d = %lf\n", d); - - d = strtod(white_chars, &end); - ok(almost_equal(d, 0), "d = %lf\n", d); - ok(end == white_chars, "incorrect end (%d)\n", (int)(end-white_chars)); + for (i=0; i DBL_MAX) continue; + snprintf(num, sizeof(num), "%de%d", i, j); + ret = _atodbl(&d, num); + ok(compare_double(d.x, expected, 2), "d.x = %.16e, expected %.16e\n", d.x, expected); + } + } + + /* check with denormal doubles */ 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); + ok(compare_double(d.x, 1e-309, 1), "d.x = %.16e, 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); + ok(compare_double(d.x, 1e-309, 1), "d.x = %.16e, expected 0\n", d.x); strcpy(num, "1e309"); ret = p__atodbl_l(&d, num, NULL); @@ -3007,6 +3533,10 @@ static void test__stricmp(void) ok(ret > 0, "_stricmp returned %d\n", ret); ret = _stricmp("\xa5", "\xb9"); ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret); if(!setlocale(LC_ALL, "polish")) { win_skip("stricmp tests\n"); @@ -3023,23 +3553,83 @@ static void test__stricmp(void) ok(ret == 0, "_stricmp returned %d\n", ret); ret = _stricmp("a", "\xb9"); ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret); + + ok(setlocale(LC_ALL, ".936") != NULL, "setlocale failed.\n"); + 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); + ret = _stricmp("a", "\xb9"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x82\xa0", "\x83\x41"); /* valid shift-jis characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x81\x00", "\x81\x01"); /* invalid for gbk and shift-jis */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret); + + ok(setlocale(LC_ALL, "Japanese_Japan.932") != NULL, "setlocale failed.\n"); + 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); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x82\xa0", "\x83\x41"); /* valid shift-jis characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x81\x00", "\x81\x01"); /* invalid for gbk and shift-jis */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\x82\xa0", "abc"); + 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 space[] = { ' ', 0 }; - static const WCHAR stock[] = { 0x3231, 0 }; /* PARENTHESIZED IDEOGRAPH STOCK */ - static const WCHAR cjk_1[] = { 0x4e00, 0 }; /* CJK Ideograph, First */ - 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 superscript1[] = { 0xb9, 0 }; /* SUPERSCRIPT ONE */ - static const WCHAR minus_0x91[] = { '-', 0x0e50, 'x', 0xff19, '1', 0 }; - static const WCHAR plus_071[] = { '+', 0x0e50, 0xff17, '1', 0 }; - static const WCHAR hex[] = { 0xff19, 'f', 0x0e59, 0xff46, 0 }; + static const struct { WCHAR str[24]; __int64 res; unsigned __int64 ures; int base; } tests[] = + { + { L"9", 9, 9, 10 }, + { L" ", 0, 0 }, + { L"-1234", -1234, -1234 }, + { L"\x09\x0a\x0b\x0c\x0d -123", -123, -123 }, + { L"\xa0\x2002\x2003\x2028\x3000 +44", 44, 44 }, + { { 0x3231 }, 0, 0 }, /* PARENTHESIZED IDEOGRAPH STOCK */ + { { 0x4e00 }, 0, 0 }, /* CJK Ideograph, First */ + { { 0x0bef }, 0, 0 }, /* TAMIL DIGIT NINE */ + { { 0x0e59 }, 9, 9 }, /* THAI DIGIT NINE */ + { { 0xff19 }, 9, 9 }, /* FULLWIDTH DIGIT NINE */ + { { 0x00b9 }, 0, 0 }, /* SUPERSCRIPT ONE */ + { { '-',0x0e50,'x',0xff19,'1' }, -0x91, -0x91 }, + { { '+',0x0e50,0xff17,'1' }, 071, 071 }, + { { 0xff19,'f',0x0e59,0xff46 }, 0x9f9, 0x9f9, 16 }, + { L"4294967295", 4294967295, 4294967295 }, + { L"4294967296", 4294967296, 4294967296 }, + { L"9223372036854775807", 9223372036854775807, 9223372036854775807 }, + { L"9223372036854775808", _I64_MAX, 9223372036854775808u }, + { L"18446744073709551615", _I64_MAX, _UI64_MAX }, + { L"18446744073709551616", _I64_MAX, _UI64_MAX }, + { L"-4294967295", -4294967295, -4294967295 }, + { L"-4294967296", -4294967296, -4294967296 }, + { L"-9223372036854775807", -9223372036854775807, -9223372036854775807 }, + { L"-9223372036854775808", _I64_MIN, 9223372036854775808u }, + { L"-18446744073709551615", _I64_MIN, 1 }, + { L"-18446744073709551616", _I64_MIN, 1 }, + }; static const WCHAR zeros[] = { 0x660, 0x6f0, 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xc66, 0xce6, 0xd66, 0xe50, 0xed0, 0xf20, 0x1040, 0x17e0, 0x1810, 0xff10 @@ -3055,51 +3645,16 @@ static void test__wcstoi64(void) return; } - res = p_wcstoi64(digit, NULL, 10); - ok(res == 9, "res != 9\n"); - res = p_wcstoi64(space, &endpos, 0); - ok(endpos == space, "endpos != space\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(cjk_1, NULL, 0); - ok(res == 0, "res != 0\n"); - 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); - ok(res == 9, "res != 9\n"); - res = p_wcstoi64(fullwidth, NULL, 10); - ok(res == 9, "res != 9\n"); - res = p_wcstoi64(superscript1, NULL, 10); - ok(res == 0, "res != 0\n"); - res = p_wcstoi64(hex, NULL, 16); - ok(res == 0x9f9, "res != 0x9f9\n"); - res = p_wcstoi64(minus_0x91, NULL, 0); - ok(res == -0x91, "res != -0x91\n"); - res = p_wcstoi64(plus_071, NULL, 0); - ok(res == 071, "res != 071\n"); - - ures = p_wcstoui64(digit, NULL, 10); - ok(ures == 9, "ures != 9\n"); - ures = p_wcstoui64(space, &endpos, 0); - ok(endpos == space, "endpos != space\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); - ok(ures == 9, "ures != 9\n"); - ures = p_wcstoui64(fullwidth, NULL, 10); - ok(ures == 9, "ures != 9\n"); - ures = p_wcstoui64(superscript1, NULL, 10); - ok(ures == 0, "ures != 0\n"); - ures = p_wcstoui64(hex, NULL, 16); - ok(ures == 0x9f9, "ures != 0x9f9\n"); - ures = p_wcstoui64(plus_071, NULL, 0); - ok(ures == 071, "ures != 071\n"); + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + res = p_wcstoi64( tests[i].str, &endpos, tests[i].base ); + ok( res == tests[i].res, "%u: %s res %s\n", + i, wine_dbgstr_w(tests[i].str), wine_dbgstr_longlong(res) ); + if (!res) ok( endpos == tests[i].str, "%u: wrong endpos %p/%p\n", i, endpos, tests[i].str ); + ures = p_wcstoui64( tests[i].str, &endpos, tests[i].base ); + ok( ures == tests[i].ures, "%u: %s res %s\n", + i, wine_dbgstr_w(tests[i].str), wine_dbgstr_longlong(ures) ); + } /* Test various unicode digits */ for (i = 0; i < ARRAY_SIZE(zeros); ++i) { @@ -3110,8 +3665,67 @@ static void test__wcstoi64(void) res = p_wcstoi64(tmp, NULL, 16); ok(res == 4, "with zero = U+%04X: got %d, expected 4\n", zeros[i], (int)res); } +} - return; +static void test__wcstol(void) +{ + static const struct { WCHAR str[24]; long res; unsigned long ures; int base; } tests[] = + { + { L"9", 9, 9, 10 }, + { L" ", 0, 0 }, + { L"-1234", -1234, -1234 }, + { L"\x09\x0a\x0b\x0c\x0d -123", -123, -123 }, + { L"\xa0\x2002\x2003\x2028\x3000 +44", 44, 44 }, + { { 0x3231 }, 0, 0 }, /* PARENTHESIZED IDEOGRAPH STOCK */ + { { 0x4e00 }, 0, 0 }, /* CJK Ideograph, First */ + { { 0x0bef }, 0, 0 }, /* TAMIL DIGIT NINE */ + { { 0x0e59 }, 9, 9 }, /* THAI DIGIT NINE */ + { { 0xff19 }, 9, 9 }, /* FULLWIDTH DIGIT NINE */ + { { 0x00b9 }, 0, 0 }, /* SUPERSCRIPT ONE */ + { { '-',0x0e50,'x',0xff19,'1' }, -0x91, -0x91 }, + { { '+',0x0e50,0xff17,'1' }, 071, 071 }, + { { 0xff19,'f',0x0e59,0xff46 }, 0x9f9, 0x9f9, 16 }, + { L"2147483647", 2147483647, 2147483647 }, + { L"2147483648", LONG_MAX, 2147483648 }, + { L"4294967295", LONG_MAX, 4294967295 }, + { L"4294967296", LONG_MAX, ULONG_MAX }, + { L"9223372036854775807", LONG_MAX, ULONG_MAX }, + { L"-2147483647", -2147483647, -2147483647 }, + { L"-2147483648", LONG_MIN, LONG_MIN }, + { L"-4294967295", LONG_MIN, 1 }, + { L"-4294967296", LONG_MIN, 1 }, + { L"-9223372036854775807", LONG_MIN, 1 }, + }; + static const WCHAR zeros[] = { + 0x660, 0x6f0, 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xc66, 0xce6, + 0xd66, 0xe50, 0xed0, 0xf20, 0x1040, 0x17e0, 0x1810, 0xff10 + }; + int i; + + long res; + unsigned long ures; + WCHAR *endpos; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + res = wcstol( tests[i].str, &endpos, tests[i].base ); + ok( res == tests[i].res, "%u: %s res %08lx\n", + i, wine_dbgstr_w(tests[i].str), res ); + if (!res) ok( endpos == tests[i].str, "%u: wrong endpos %p/%p\n", i, endpos, tests[i].str ); + ures = wcstoul( tests[i].str, &endpos, tests[i].base ); + ok( ures == tests[i].ures, "%u: %s res %08lx\n", + i, wine_dbgstr_w(tests[i].str), ures ); + } + + /* Test various unicode digits */ + for (i = 0; i < ARRAY_SIZE(zeros); ++i) { + WCHAR tmp[] = {zeros[i] + 4, zeros[i], zeros[i] + 5, 0}; + res = wcstol(tmp, NULL, 0); + ok(res == 405, "with zero = U+%04X: got %d, expected 405\n", zeros[i], (int)res); + tmp[1] = zeros[i] + 10; + res = wcstol(tmp, NULL, 16); + ok(res == 4, "with zero = U+%04X: got %d, expected 4\n", zeros[i], (int)res); + } } static void test_atoi(void) @@ -3153,13 +3767,13 @@ static void test_atof(void) double d; d = atof("0.0"); - ok(almost_equal(d, 0.0), "d = %lf\n", d); + ok(d == 0.0, "d = %lf\n", d); d = atof("1.0"); - ok(almost_equal(d, 1.0), "d = %lf\n", d); + ok(d == 1.0, "d = %lf\n", d); d = atof("-1.0"); - ok(almost_equal(d, -1.0), "d = %lf\n", d); + ok(d == -1.0, "d = %lf\n", d); if (!p__atof_l) { @@ -3169,12 +3783,12 @@ static void test_atof(void) errno = EBADF; d = atof(NULL); - ok(almost_equal(d, 0.0), "d = %lf\n", d); + ok(d == 0.0, "d = %lf\n", d); ok(errno == EINVAL, "errno = %x\n", errno); errno = EBADF; d = p__atof_l(NULL, NULL); - ok(almost_equal(d, 0.0), "d = %lf\n", d); + ok(d == 0.0, "d = %lf\n", d); ok(errno == EINVAL, "errno = %x\n", errno); } @@ -3311,7 +3925,7 @@ static void test__strnset_s(void) static void test__wcsnset_s(void) { - wchar_t text[] = { 't','e','x','t',0 }; + wchar_t text[] = L"text"; int r; if(!p__wcsnset_s) { @@ -3411,6 +4025,15 @@ static void test__mbscmp(void) ret = _mbscmp(b, a); ok(ret == 1, "got %d\n", ret); + + if (!p_mbscmp_l) + { + win_skip("_mbscmp_l tests\n"); + return; + } + + ret = p_mbscmp_l(a, b, NULL); + ok(ret == -1, "got %d\n", ret); } static void test__ismbclx(void) @@ -3550,6 +4173,7 @@ static void test__memicmp_l(void) static void test__strupr(void) { const char str[] = "123"; + const char *const_p; char str2[4]; char *mem, *p; DWORD prot; @@ -3568,6 +4192,10 @@ static void test__strupr(void) ok(p == mem, "_strupr returned %p\n", p); ok(!strcmp(mem, "123"), "mem = %s\n", mem); + const_p = "ALREADY_UPPERCASE"; + p = _strupr((char *)const_p); + ok(p == const_p, "_strupr returned %p\n", p); + if(!setlocale(LC_ALL, "english")) { VirtualFree(mem, sizeof(str), MEM_RELEASE); win_skip("English locale _strupr tests\n"); @@ -3614,6 +4242,9 @@ static void test__tcsncoll(void) { "English", "ABCe", "ABCf", 3, 0 }, { "English", "abcd", "ABCD", 10, -1 }, + { "English", "AB D", "AB-D", 4, 1 }, + { "English", "AB D", "AB'D", 4, 1 }, + { "C", "ABCD", "ABCD", 4, 0 }, { "C", "ABCD", "ABCD", 10, 0 }, @@ -3625,6 +4256,9 @@ static void test__tcsncoll(void) { "C", "ABCe", "ABCf", 3, 0 }, { "C", "abcd", "ABCD", 10, 1 }, + + { "C", "AB D", "AB-D", 4, -1 }, + { "C", "AB D", "AB'D", 4, -1 }, }; WCHAR str1W[16]; WCHAR str2W[16]; @@ -3651,11 +4285,14 @@ static void test__tcsncoll(void) ret = _strncoll(str1, str2, tests[i].count); if (!tests[i].exp) - ok(!ret, "expected 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(!ret, "expected 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); else if (tests[i].exp < 0) - ok(ret < 0, "expected < 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(ret < 0, "expected < 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); else - ok(ret > 0, "expected > 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(ret > 0, "expected > 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); memset(str1W, 0xee, sizeof(str1W)); len = mbstowcs(str1W, str1, ARRAY_SIZE(str1W)); @@ -3667,11 +4304,94 @@ static void test__tcsncoll(void) ret = _wcsncoll(str1W, str2W, tests[i].count); if (!tests[i].exp) - ok(!ret, "expected 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(!ret, "expected 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); else if (tests[i].exp < 0) - ok(ret < 0, "expected < 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(ret < 0, "expected < 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); else - ok(ret > 0, "expected > 0, got %d for %s, %s, %d\n", ret, str1, str2, (int)tests[i].count); + ok(ret > 0, "expected > 0, got %d for %s, %s, %d for locale %s\n", + ret, str1, str2, (int)tests[i].count, tests[i].locale); + } +} + +static void test__tcscoll(void) +{ + struct test { + const char *locale; + const char *str1; + const char *str2; + int exp; + }; + static const struct test tests[] = { + { "English", "ABCD", "ABCD", 0 }, + { "English", "ABC", "ABCD", -1 }, + { "English", "ABCD", "ABC", 1 }, + { "English", "ABCe", "ABCf", -1 }, + { "English", "abcd", "ABCD", -1 }, + { "English", "AB D", "AB-D", 1 }, + { "English", "AB D", "AB'D", 1 }, + + { "C", "ABCD", "ABCD", 0 }, + { "C", "ABC", "ABCD", -1 }, + { "C", "ABCD", "ABC", 1 }, + { "C", "ABCe", "ABCf", -1 }, + { "C", "abcd", "ABCD", 1 }, + { "C", "AB D", "AB-D", -1 }, + { "C", "AB D", "AB'D", -1 }, + }; + WCHAR str1W[16]; + WCHAR str2W[16]; + char str1[16]; + char str2[16]; + size_t len; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + if (!setlocale(LC_ALL, tests[i].locale)) + { + win_skip("%s locale _tcsncoll tests\n", tests[i].locale); + for (; i+1 < ARRAY_SIZE(tests); i++) + if (strcmp(tests[i].locale, tests[i+1].locale)) break; + continue; + } + + memset(str1, 0xee, sizeof(str1)); + strcpy(str1, tests[i].str1); + + memset(str2, 0xff, sizeof(str2)); + strcpy(str2, tests[i].str2); + + ret = strcoll(str1, str2); + if (!tests[i].exp) + ok(!ret, "expected 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); + else if (tests[i].exp < 0) + ok(ret < 0, "expected < 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); + else + ok(ret > 0, "expected > 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); + + memset(str1W, 0xee, sizeof(str1W)); + len = mbstowcs(str1W, str1, ARRAY_SIZE(str1W)); + str1W[len] = 0; + + memset(str2W, 0xff, sizeof(str2W)); + len = mbstowcs(str2W, str2, ARRAY_SIZE(str2W)); + str2W[len] = 0; + + ret = wcscoll(str1W, str2W); + if (!tests[i].exp) + ok(!ret, "expected 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); + else if (tests[i].exp < 0) + ok(ret < 0, "expected < 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); + else + ok(ret > 0, "expected > 0, got %d for %s, %s for locale %s\n", + ret, str1, str2, tests[i].locale); } } @@ -3856,6 +4576,454 @@ static void test_C_locale(void) } } +static void test_strstr(void) +{ + static char long_str[1024]; + const struct { + const char *haystack; + const char *needle; + int off; + } tests[] = { + { "", "", 0 }, + { "", "a", -1 }, + { "a", "", 0 }, + { "aabc", "abc", 1 }, + { "aaaa", "aaaa", 0 }, + { "simple", "simple", 0 }, + { "aaaaxaaaaxaaaa", "aaaaa", -1 }, + { "aaaaxaaaaxaaaaa", "aaaaa", 10 }, + { "abcabcdababcdabcdabde", "abcdabd", 13 }, + { "abababababcabababcababbba", "abababcaba", 4 }, + { long_str, long_str+1, 0 } + }; + const char *r, *exp; + int i; + + memset(long_str, 'a', sizeof(long_str)-1); + + for (i=0; ild) + 1]; + int i; + + for(i=0; ild); i++) + { + buf[2*i] = v->ld[i] / 16 + '0'; + if(buf[2*i] > '9') buf[2*i] -= 10 + '0' - 'a'; + buf[2*i+1] = v->ld[i] % 16 + '0'; + if(buf[2*i+1] > '9') buf[2*i+1] -= 10 + '0' - 'a'; + } + buf[2 * ARRAY_SIZE(v->ld)] = 0; + return buf; +} + +static void test___STRINGTOLD(void) +{ + static const struct { + const char *str; + int endptr; + int r; + _LDOUBLE v; + BOOL todo; + } tests[] = { + { "0", 1 }, + { "nan", 0, 4 }, + { "inf", 0, 4 }, + { "-0.0", 4, 0, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }} }, + { "1e0", 3, 0, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f }} }, + { "1.7976931348623158e+308", 23, 0, {{ 0xaf, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x43 }} }, + { "1.7976931348623159e+308", 23, 0, {{ 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x43 }} }, + { "3.65e-4951", 10, 0, {{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }} }, + { "1.82e-4951", 10, 0, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, TRUE }, + { "1e-99999", 8, 1, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }} }, + { "1.18e+4932", 10, 0, {{ 0x25, 0x75, 0x06, 0x68, 0x8a, 0xf1, 0xe7, 0xfd, 0xfe, 0x7f }} }, + { "1.19e+4932", 10, 2, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f }} }, + { "1e+99999", 8, 2, {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f }} }, + }; + + char *endptr; + _LDOUBLE v; + int i, r; + + for(i=0; i 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, 0); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + if (!p__create_locale) + win_skip("_create_locale isn't available.\n"); + else + { + locale = p__create_locale(LC_ALL, ".936"); + ok(locale != NULL, "Failed to create locale.\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = p__strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, locale); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, locale); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + p__free_locale(locale); + } + + if (!setlocale(LC_ALL, ".936")) + { + win_skip("Skip testing _strnicmp_l with 936 code page.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = p__strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, 0); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, 0); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + setlocale(LC_ALL, "C"); +} + +static void test_toupper(void) +{ + int ret; + + ok(setlocale(LC_ALL, "English_United States") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_toupper((signed char)0xf0); + ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_toupper(0xf0); + ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Polish") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_toupper((signed char)0xa5); + ok(ret == 0xa5, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_toupper((signed char)0xb9); + ok(ret == 0xa5, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Japanese_Japan.932") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_toupper((signed char)0xf0); + ok(ret == (signed char)0xf0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_toupper(0xf0); + ok(ret == 0xf0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Chinese_China.936") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_toupper((signed char)0xf0); + ok(ret == (signed char)0xf0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_toupper(0xf0); + ok(ret == 0xf0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + setlocale(LC_ALL, "C"); +} + START_TEST(string) { char mem[100]; @@ -3873,8 +5041,12 @@ START_TEST(string) SET(p_mbctype,"_mbctype"); SET(p__mb_cur_max,"__mb_cur_max"); SET(p_strcpy, "strcpy"); + SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); pstrcpy_s = (void *)GetProcAddress( hMsvcrt,"strcpy_s" ); pstrcat_s = (void *)GetProcAddress( hMsvcrt,"strcat_s" ); + p_strncpy_s = (void *)GetProcAddress( hMsvcrt, "strncpy_s" ); + p_strncat_s = (void *)GetProcAddress( hMsvcrt, "strncat_s" ); p_mbscat_s = (void*)GetProcAddress( hMsvcrt, "_mbscat_s" ); p_mbsnbcat_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcat_s" ); p_mbsnbcpy_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcpy_s" ); @@ -3890,6 +5062,7 @@ START_TEST(string) p_wcstoui64 = (void *)GetProcAddress(hMsvcrt, "_wcstoui64"); pmbstowcs_s = (void *)GetProcAddress(hMsvcrt, "mbstowcs_s"); pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s"); + p_wcstombs_s_l = (void *)GetProcAddress(hMsvcrt, "_wcstombs_s_l"); pwcsrtombs = (void *)GetProcAddress(hMsvcrt, "wcsrtombs"); p_gcvt_s = (void *)GetProcAddress(hMsvcrt, "_gcvt_s"); p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s"); @@ -3898,6 +5071,7 @@ START_TEST(string) p_wcslwr_s = (void*)GetProcAddress(hMsvcrt, "_wcslwr_s"); p_mbsupr_s = (void*)GetProcAddress(hMsvcrt, "_mbsupr_s"); p_mbslwr_s = (void*)GetProcAddress(hMsvcrt, "_mbslwr_s"); + p_btowc = (void*)GetProcAddress(hMsvcrt, "btowc"); p_wctob = (void*)GetProcAddress(hMsvcrt, "wctob"); p_wcrtomb = (void*)GetProcAddress(hMsvcrt, "wcrtomb"); p_wcrtomb_s = (void*)GetProcAddress(hMsvcrt, "wcrtomb_s"); @@ -3923,6 +5097,10 @@ START_TEST(string) p__memicmp = (void*)GetProcAddress(hMsvcrt, "_memicmp"); p__memicmp_l = (void*)GetProcAddress(hMsvcrt, "_memicmp_l"); p___strncnt = (void*)GetProcAddress(hMsvcrt, "__strncnt"); + p_mbsnextc_l = (void*)GetProcAddress(hMsvcrt, "_mbsnextc_l"); + p_mbscmp_l = (void*)GetProcAddress(hMsvcrt, "_mbscmp_l"); + p__strnicmp_l = (void*)GetProcAddress(hMsvcrt, "_strnicmp_l"); + p_toupper = (void*)GetProcAddress(hMsvcrt, "toupper"); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -3935,14 +5113,18 @@ START_TEST(string) /* run tolower tests first */ test_tolower(); test_swab(); + test_strcspn(); test_mbcp(); test_mbsspn(); test_mbsspnp(); test_strdup(); + test_wcsdup(); + test_strcmp(); test_strcpy_s(); test_memcpy_s(); test_memmove_s(); test_strcat_s(); + test_strncat_s(); test__mbscat_s(); test__mbsnbcpy_s(); test__mbscpy_s(); @@ -3963,6 +5145,7 @@ START_TEST(string) test__strtoi64(); test__strtod(); test_mbstowcs(); + test__wcstombs_s_l(); test_gcvt(); test__itoa_s(); test__strlwr_s(); @@ -3973,10 +5156,12 @@ START_TEST(string) test__mbsupr_s(); test__mbslwr_s(); test_wctob(); + test_btowc(); test_wctomb(); test__atodbl(); test__stricmp(); test__wcstoi64(); + test__wcstol(); test_atoi(); test_atol(); test_atof(); @@ -3991,7 +5176,21 @@ START_TEST(string) test__memicmp_l(); test__strupr(); test__tcsncoll(); + test__tcscoll(); test__tcsnicoll(); test___strncnt(); test_C_locale(); + test_strstr(); + test_iswdigit(); + test_wcscmp(); + test___STRINGTOLD(); + test_SpecialCasing(); + test__mbbtype(); + test_wcsncpy(); + test_mbsrev(); +#ifndef __REACTOS__ + test__tolower_l(); +#endif + test__strnicmp_l(); + test_toupper(); } diff --git a/modules/rostests/winetests/msvcrt/time.c b/modules/rostests/winetests/msvcrt/time.c index cf79e5971ec..aba911f30a4 100644 --- a/modules/rostests/winetests/msvcrt/time.c +++ b/modules/rostests/winetests/msvcrt/time.c @@ -36,10 +36,27 @@ #define MINSPERHOUR 60 #define HOURSPERDAY 24 +typedef struct { + const char *short_wday[7]; + const char *wday[7]; + const char *short_mon[12]; + const char *mon[12]; + const char *am; + const char *pm; + const char *short_date; + const char *date; + const char *time; + LCID lcid; + int unk; + int refcount; +} __lc_time_data; + static __time32_t (__cdecl *p_mkgmtime32)(struct tm*); static struct tm* (__cdecl *p_gmtime32)(__time32_t*); static struct tm* (__cdecl *p_gmtime)(time_t*); static errno_t (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*); +static struct tm* (__cdecl *p_gmtime64)(__time64_t*); +static errno_t (__cdecl *p_gmtime64_s)(struct tm*, __time64_t*); static errno_t (__cdecl *p_strtime_s)(char*,size_t); static errno_t (__cdecl *p_strdate_s)(char*,size_t); static errno_t (__cdecl *p_localtime32_s)(struct tm*, __time32_t*); @@ -50,6 +67,7 @@ static long* (__cdecl *p___p__dstbias)(void); static long* (__cdecl *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__Strftime)(char*, size_t, const char*, const struct tm*, void*); static size_t (__cdecl *p_wcsftime)(wchar_t *, size_t, const wchar_t *, const struct tm *); static char* (__cdecl *p_asctime)(const struct tm *); @@ -60,6 +78,8 @@ static void init(void) p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32"); p_gmtime = (void*)GetProcAddress(hmod, "gmtime"); p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s"); + p_gmtime64 = (void*)GetProcAddress(hmod, "_gmtime64"); + p_gmtime64_s = (void*)GetProcAddress(hmod, "_gmtime64_s"); p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32"); p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s"); p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s"); @@ -71,6 +91,7 @@ static void init(void) p__dstbias = (void*)GetProcAddress(hmod, "__dstbias"); p___p__timezone = (void*)GetProcAddress(hmod, "__p__timezone"); p_strftime = (void*)GetProcAddress(hmod, "strftime"); + p__Strftime = (void*)GetProcAddress(hmod, "_Strftime"); p_wcsftime = (void*)GetProcAddress(hmod, "wcsftime"); p_asctime = (void*)GetProcAddress(hmod, "asctime"); } @@ -134,21 +155,21 @@ static void test_gmtime(void) gmt_tm->tm_wday = gmt_tm->tm_yday = 0; gmt = p_mkgmtime32(gmt_tm); - ok(gmt == valid, "gmt = %u\n", gmt); + ok(gmt == valid, "gmt = %lu\n", gmt); ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); gmt_tm->tm_wday = gmt_tm->tm_yday = 0; gmt_tm->tm_isdst = -1; gmt = p_mkgmtime32(gmt_tm); - ok(gmt == valid, "gmt = %u\n", gmt); + ok(gmt == valid, "gmt = %lu\n", gmt); ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); gmt_tm->tm_wday = gmt_tm->tm_yday = 0; gmt_tm->tm_isdst = 1; gmt = p_mkgmtime32(gmt_tm); - ok(gmt == valid, "gmt = %u\n", gmt); + ok(gmt == valid, "gmt = %lu\n", gmt); ok(gmt_tm->tm_wday == 4, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); ok(gmt_tm->tm_yday == 0, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); @@ -161,13 +182,13 @@ static void test_gmtime(void) gmt_tm->tm_isdst = -1; gmt = p_mkgmtime32(gmt_tm); - ok(gmt == valid, "gmt = %u\n", gmt); + ok(gmt == valid, "gmt = %lu\n", gmt); ok(gmt_tm->tm_wday == 6, "gmt_tm->tm_wday = %d\n", gmt_tm->tm_wday); ok(gmt_tm->tm_yday == 2, "gmt_tm->tm_yday = %d\n", gmt_tm->tm_yday); gmt_tm->tm_isdst = 1; gmt = p_mkgmtime32(gmt_tm); - ok(gmt == valid, "gmt = %u\n", gmt); + ok(gmt == valid, "gmt = %lu\n", gmt); if(!p_gmtime32_s) { win_skip("Skipping _gmtime32_s tests\n"); @@ -191,6 +212,78 @@ static void test_gmtime(void) } } +static void test_gmtime64(void) +{ + struct tm *ptm, tm; + __time64_t t; + int ret; + + t = -1; + memset(&tm, 0xcc, sizeof(tm)); + ptm = p_gmtime64(&t); + if (!ptm) + { + skip("Old gmtime64 limits, skipping tests.\n"); + return; + } + ok(!!ptm, "got NULL.\n"); + ret = p_gmtime64_s(&tm, &t); + ok(!ret, "got %d.\n", ret); + ok(tm.tm_year == 69 && tm.tm_hour == 23 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + + t = -43200; + memset(&tm, 0xcc, sizeof(tm)); + ptm = p_gmtime64(&t); + ok(!!ptm, "got NULL.\n"); + ret = p_gmtime64_s(&tm, &t); + ok(!ret, "got %d.\n", ret); + ok(tm.tm_year == 69 && tm.tm_hour == 12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + ptm = p_gmtime32((__time32_t *)&t); + ok(!!ptm, "got NULL.\n"); + memset(&tm, 0xcc, sizeof(tm)); + ret = p_gmtime32_s(&tm, (__time32_t *)&t); + ok(!ret, "got %d.\n", ret); + todo_wine_if(tm.tm_year == 69 && tm.tm_hour == 12) + ok(tm.tm_year == 70 && tm.tm_hour == -12 && tm.tm_min == 0 && tm.tm_sec == 0, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + + t = -43201; + ptm = p_gmtime64(&t); + ok(!ptm, "got non-NULL.\n"); + memset(&tm, 0xcc, sizeof(tm)); + ret = p_gmtime64_s(&tm, &t); + ok(ret == EINVAL, "got %d.\n", ret); + ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + ptm = p_gmtime32((__time32_t *)&t); + ok(!ptm, "got NULL.\n"); + memset(&tm, 0xcc, sizeof(tm)); + ret = p_gmtime32_s(&tm, (__time32_t *)&t); + ok(ret == EINVAL, "got %d.\n", ret); + ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + + t = _MAX__TIME64_T + 46800; + memset(&tm, 0xcc, sizeof(tm)); + ptm = p_gmtime64(&t); + ok(!!ptm, "got NULL.\n"); + ret = p_gmtime64_s(&tm, &t); + ok(!ret, "got %d.\n", ret); + ok(tm.tm_year == 1101 && tm.tm_hour == 20 && tm.tm_min == 59 && tm.tm_sec == 59, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); + + t = _MAX__TIME64_T + 46801; + ptm = p_gmtime64(&t); + ok(!ptm, "got non-NULL.\n"); + memset(&tm, 0xcc, sizeof(tm)); + ret = p_gmtime64_s(&tm, &t); + ok(ret == EINVAL, "got %d.\n", ret); + ok(tm.tm_year == -1 && tm.tm_hour == -1 && tm.tm_min == -1 && tm.tm_sec == -1, "got %d, %d, %d, %d.\n", + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); +} + static void test_mktime(void) { TIME_ZONE_INFORMATION tzinfo; @@ -207,7 +300,7 @@ static void test_mktime(void) ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); WideCharToMultiByte( CP_ACP, 0, tzinfo.StandardName, -1, buffer, sizeof(buffer), NULL, NULL ); - trace( "bias %d std %d dst %d zone %s\n", + trace( "bias %ld std %ld dst %ld zone %s\n", tzinfo.Bias, tzinfo.StandardBias, tzinfo.DaylightBias, buffer ); /* Bias may be positive or negative, to use offset of one day */ my_tm = *localtime(&ref); /* retrieve current dst flag */ @@ -227,14 +320,14 @@ static void test_mktime(void) sav_tm = my_tm; local_time = mktime(&my_tm); - ok(local_time == ref, "mktime returned %u, expected %u\n", + ok(local_time == ref, "mktime returned %lu, expected %lu\n", (DWORD)local_time, (DWORD)ref); /* now test some unnormalized struct tm's */ my_tm = sav_tm; my_tm.tm_sec += 60; my_tm.tm_min -= 1; local_time = mktime(&my_tm); - ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + ok(local_time == ref, "Unnormalized mktime returned %lu, expected %lu\n", (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && @@ -248,7 +341,7 @@ static void test_mktime(void) my_tm.tm_min -= 60; my_tm.tm_hour += 1; local_time = mktime(&my_tm); - ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + ok(local_time == ref, "Unnormalized mktime returned %lu, expected %lu\n", (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && @@ -262,7 +355,7 @@ static void test_mktime(void) my_tm.tm_mon -= 12; my_tm.tm_year += 1; local_time = mktime(&my_tm); - ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + ok(local_time == ref, "Unnormalized mktime returned %lu, expected %lu\n", (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && @@ -276,7 +369,7 @@ static void test_mktime(void) my_tm.tm_mon += 12; my_tm.tm_year -= 1; local_time = mktime(&my_tm); - ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + ok(local_time == ref, "Unnormalized mktime returned %lu, expected %lu\n", (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && @@ -298,7 +391,7 @@ static void test_mktime(void) _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); putenv("TZ=GMT"); nulltime = mktime(&my_tm); - ok(nulltime == ref,"mktime returned 0x%08x\n",(DWORD)nulltime); + ok(nulltime == ref,"mktime returned 0x%08lx\n",(DWORD)nulltime); putenv(TZ_env); } @@ -425,13 +518,12 @@ static void test_wstrdate(void) { wchar_t date[16], * result; int month, day, year, count, len; - wchar_t format[] = { '%','0','2','d','/','%','0','2','d','/','%','0','2','d',0 }; result = _wstrdate(date); ok(result == date, "Wrong return value\n"); len = wcslen(date); ok(len == 8, "Wrong length: returned %d, should be 8\n", len); - count = swscanf(date, format, &month, &day, &year); + count = swscanf(date, L"%02d/%02d/%02d", &month, &day, &year); ok(count == 3, "Wrong format: count = %d, should be 3\n", count); } @@ -439,13 +531,12 @@ static void test_wstrtime(void) { wchar_t time[16], * result; int hour, minute, second, count, len; - wchar_t format[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',0 }; result = _wstrtime(time); ok(result == time, "Wrong return value\n"); len = wcslen(time); ok(len == 8, "Wrong length: returned %d, should be 8\n", len); - count = swscanf(time, format, &hour, &minute, &second); + count = swscanf(time, L"%02d:%02d:%02d", &hour, &minute, &second); ok(count == 3, "Wrong format: count = %d, should be 3\n", count); } @@ -575,26 +666,148 @@ static void test_daylight(void) return; } - if (!p___p__daylight) + /* Examine the returned pointer from __p__environ(), if available. */ + if (sizeof(void*) != sizeof(int)) + ok( !p___p__daylight, "___p__daylight() should be 32-bit only\n"); + else { - skip("__p__daylight not available\n"); - return; + ret1 = p__daylight(); + ret2 = p___p__daylight(); + ok(ret1 && ret1 == ret2, "got %p\n", ret1); } - - ret1 = p__daylight(); - ret2 = p___p__daylight(); - ok(ret1 && ret1 == ret2, "got %p\n", ret1); } static void test_strftime(void) { - static const wchar_t cW[] = { '%','c',0 }; - static const char expected[] = "01/01/70 00:00:00"; + const struct { + const char *format; + } tests_einval[] = { + {"%C"}, + {"%D"}, + {"%e"}, + {"%F"}, + {"%h"}, + {"%n"}, + {"%R"}, + {"%t"}, + {"%T"}, + {"%u"}, + }; + + const struct { + const char *format; + const char *ret; + struct tm tm; + BOOL todo; + } tests[] = { + {"e%#%e", "e%e", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%c", "01/01/70 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%c", "02/30/70 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, + {"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, + {"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, + {"%#x", "Thursday, January 01, 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }}, + {"%X", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%X", "14:00:00", { 0, 0, 14, 1, 0, 70, 4, 0, 0 }}, + {"%a", "Thu", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%A", "Thursday", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%b", "Jan", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%B", "January", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%d", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%#d", "1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%H", "00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%I", "12", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%j", "001", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%m", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%#M", "0", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%p", "AM", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%U", "00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%W", "00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }}, + {"%U", "01", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + {"%W", "00", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + {"%U", "53", { 0, 0, 0, 1, 0, 70, 0, 365, 0 }}, + {"%W", "52", { 0, 0, 0, 1, 0, 70, 0, 365, 0 }}, + }; + + const struct { + const char *format; + const char *ret; + const char *short_date; + const char *date; + const char *time; + struct tm tm; + BOOL todo; + } tests_td[] = { + { "%c", "x z", "x", "y", "z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#c", "y z", "x", "y", "z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "m1", 0, 0, "MMM", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "1", 0, 0, "h", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "01", 0, 0, "hh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "h01", 0, 0, "hhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "hh01", 0, 0, "hhhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "1", 0, 0, "H", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "01", 0, 0, "HH", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }}, + { "%X", "H13", 0, 0, "HHH", { 0, 0, 13, 1, 0, 70, 0, 0, 0 }}, + { "%X", "0", 0, 0, "m", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "00", 0, 0, "mm", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "0", 0, 0, "s", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "00", 0, 0, "ss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "s00", 0, 0, "sss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "t", 0, 0, "t", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "tt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "ttttttttt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "a", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "aaaaa", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "A", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%X", "tam", 0, 0, "AAAAA", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "1", "d", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "01", "dd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "d1", "ddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "day1", "dddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "dday1", "ddddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "1", "M", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "01", "MM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "m1", "MMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "mon1", "MMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "Mmon1", "MMMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "y", "y", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "70", "yy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "y70", "yyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "1970", "yyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "y1970", "yyyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%x", "ggggggggggg", "ggggggggggg", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "1", 0, "d", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "01", 0, "dd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "d1", 0, "ddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "day1", 0, "dddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "dday1", 0, "ddddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "1", 0, "M", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "01", 0, "MM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "m1", 0, "MMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "mon1", 0, "MMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "Mmon1", 0, "MMMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "y", 0, "y", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "70", 0, "yy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "y70", 0, "yyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "1970", 0, "yyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + { "%#x", "y1970", 0, "yyyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }}, + }; + + __lc_time_data time_data = { + { "d1", "d2", "d3", "d4", "d5", "d6", "d7" }, + { "day1", "day2", "day3", "day4", "day5", "day6", "day7" }, + { "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10", "m11", "m12" }, + { "mon1", "mon2", "mon3", "mon4", "mon5", "mon6", "mon7", "mon8", "mon9", "mon10", "mon11", "mon12" }, + "tam", "tpm" + }; time_t gmt; struct tm* gmt_tm; char buf[256], bufA[256]; WCHAR bufW[256]; long retA, retW; + int i; if (!p_strftime || !p_wcsftime || !p_gmtime) { @@ -608,55 +821,13 @@ static void test_strftime(void) gmt_tm = p_gmtime(&gmt); ok(gmt_tm != NULL, "gmtime failed\n"); - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%C", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%D", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%e", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%F", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%h", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%n", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%R", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%t", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%T", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); - - errno = 0xdeadbeef; - retA = p_strftime(bufA, 256, "%u", gmt_tm); - ok(retA == 0, "expected 0, got %ld\n", retA); - ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno); + for (i=0; itm_wday = 0; - retA = p_strftime(bufA, 256, "%U", gmt_tm); - ok(retA == 2, "expected 2, got %ld\n", retA); - ok(!strcmp(bufA, "01"), "got %s\n", bufA); - - retA = p_strftime(bufA, 256, "%W", gmt_tm); - ok(retA == 2, "expected 2, got %ld\n", retA); - ok(!strcmp(bufA, "00"), "got %s\n", bufA); - - gmt_tm->tm_yday = 365; - retA = p_strftime(bufA, 256, "%U", gmt_tm); - ok(retA == 2, "expected 2, got %ld\n", retA); - ok(!strcmp(bufA, "53"), "got %s\n", bufA); - - retA = p_strftime(bufA, 256, "%W", gmt_tm); - ok(retA == 2, "expected 2, got %ld\n", retA); - ok(!strcmp(bufA, "52"), "got %s\n", bufA); - - gmt_tm->tm_mon = 1; - gmt_tm->tm_mday = 30; - retA = p_strftime(bufA, 256, "%c", gmt_tm); - todo_wine { - ok(retA == 17, "expected 17, got %ld\n", retA); - ok(!strcmp(bufA, "02/30/70 00:00:00"), "got %s\n", bufA); - } - if(!setlocale(LC_ALL, "Japanese_Japan.932")) { win_skip("Japanese_Japan.932 locale not available\n"); return; @@ -806,6 +890,27 @@ static void test_strftime(void) retA = p_strftime(bufA, 256, "\x82%c", gmt_tm); ok(retA == 3, "expected 3, got %ld\n", retA); ok(!strcmp(bufA, "\x82%c"), "got %s\n", bufA); + + setlocale(LC_ALL, "C"); + if(!p__Strftime) { + win_skip("_Strftime is not available\n"); + return; + } + + /* TODO: find meaning of unk */ + time_data.unk = 1; + for (i=0; i