[MSVCRT_WINETEST]
authorThomas Faber <thomas.faber@reactos.org>
Sat, 5 Nov 2011 09:54:41 +0000 (09:54 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sat, 5 Nov 2011 09:54:41 +0000 (09:54 +0000)
- Sync to Wine 1.3.32

svn path=/trunk/; revision=54296

12 files changed:
rostests/winetests/msvcrt/cpp.c
rostests/winetests/msvcrt/data.c
rostests/winetests/msvcrt/environ.c
rostests/winetests/msvcrt/file.c
rostests/winetests/msvcrt/headers.c
rostests/winetests/msvcrt/locale.c
rostests/winetests/msvcrt/misc.c
rostests/winetests/msvcrt/msvcrt.h [new file with mode: 0644]
rostests/winetests/msvcrt/printf.c
rostests/winetests/msvcrt/scanf.c
rostests/winetests/msvcrt/string.c
rostests/winetests/msvcrt/time.c

index 40e11e1..bb6ba16 100644 (file)
@@ -180,7 +180,7 @@ static void* do_call_func2(void *func, void *_this, const void* arg)
 
 /* Some exports are only available in later versions */
 #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)
+#define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
 
 static void InitFunctionPtrs(void)
 {
@@ -190,8 +190,16 @@ static void InitFunctionPtrs(void)
   ok(hMsvcrt != 0, "GetModuleHandleA failed\n");
   if (hMsvcrt)
   {
-    SETNOFAIL(poperator_new, "??_U@YAPAXI@Z");
-    SETNOFAIL(poperator_delete, "??_V@YAXPAX@Z");
+    if (sizeof(void *) > sizeof(int))  /* 64-bit has different names */
+    {
+        SETNOFAIL(poperator_new, "??_U@YAPEAX_K@Z");
+        SETNOFAIL(poperator_delete, "??_V@YAXPEAX@Z");
+    }
+    else
+    {
+        SETNOFAIL(poperator_new, "??_U@YAPAXI@Z");
+        SETNOFAIL(poperator_delete, "??_V@YAXPAX@Z");
+    }
     SET(pmalloc, "malloc");
     SET(pfree, "free");
 
@@ -802,7 +810,8 @@ static void test_rtti(void)
   void *casted;
 
   if (bAncientVersion ||
-      !p__RTCastToVoid || !p__RTtypeid || !pexception_ctor || !pbad_typeid_ctor || !p__RTDynamicCast)
+      !p__RTCastToVoid || !p__RTtypeid || !pexception_ctor || !pbad_typeid_ctor
+      || !p__RTDynamicCast || !pexception_dtor || !pbad_typeid_dtor)
     return;
 
   call_func2(pexception_ctor, &e, &e_name);
@@ -826,6 +835,9 @@ static void test_rtti(void)
   /* dynamic_cast down */
   casted = p__RTDynamicCast(&e, 0, NULL, bti, 0);
   ok (casted == NULL, "Cast succeeded\n");
+
+  call_func1(pexception_dtor, &e);
+  call_func1(pbad_typeid_dtor, &b);
 }
 
 struct _demangle {
@@ -856,7 +868,8 @@ static void test_demangle_datatype(void)
            ok(name != NULL && !strcmp(name,demangle[i].result), "Got name \"%s\" for %d\n", name, i);
        else
            todo_wine ok(name != NULL && !strcmp(name,demangle[i].result), "Got name %s for %d\n", name, i);
-             
+        if(name)
+            pfree(name);
     }
 }
 
@@ -1038,6 +1051,14 @@ static void test_demangle(void)
 /* 116 */ {"?vswprintf@@YAHPAGIPBGPAD@Z", "int __cdecl vswprintf(unsigned short *,unsigned int,unsigned short const *,char *)"},
 /* 117 */ {"?vswprintf@@YAHPA_WIPB_WPAD@Z", "int __cdecl vswprintf(wchar_t *,unsigned int,wchar_t const *,char *)"},
 /* 118 */ {"?swprintf@@YAHPA_WIPB_WZZ", "int __cdecl swprintf(wchar_t *,unsigned int,wchar_t const *,...)"},
+/* 119 */ {"??Xstd@@YAAEAV?$complex@M@0@AEAV10@AEBV10@@Z", "class std::complex<float> & __ptr64 __cdecl std::operator*=(class std::complex<float> & __ptr64,class std::complex<float> const & __ptr64)"},
+/* 120 */ {"?_Doraise@bad_cast@std@@MEBAXXZ", "protected: virtual void __cdecl std::bad_cast::_Doraise(void)const __ptr64"},
+/* 121 */ {"??$?DM@std@@YA?AV?$complex@M@0@ABMABV10@@Z",
+           "class std::complex<float> __cdecl std::operator*<float>(float const &,class std::complex<float> const &)",
+           "??$?DM@std@@YA?AV?$complex@M@0@ABMABV10@@Z"},
+/* 122 */ {"?_R2@?BN@???$_Fabs@N@std@@YANAEBV?$complex@N@1@PEAH@Z@4NB",
+           "double const `double __cdecl std::_Fabs<double>(class std::complex<double> const & __ptr64,int * __ptr64)'::`29'::_R2",
+           "?_R2@?BN@???$_Fabs@N@std@@YANAEBV?$complex@N@1@PEAH@Z@4NB"},
 
     };
     int i, num_test = (sizeof(test)/sizeof(test[0]));
index 7061124..c20be18 100644 (file)
@@ -34,6 +34,8 @@
 typedef void (__cdecl *_INITTERMFUN)(void);
 static void (__cdecl *p_initterm)(_INITTERMFUN *start, _INITTERMFUN *end);
 
+static int (__cdecl *p_get_pgmptr)(char **p);
+
 static int callbacked;
 
 static void __cdecl initcallback(void)
@@ -108,6 +110,20 @@ static void test_initvar( HMODULE hmsvcrt )
             osplatform, osvi.dwPlatformId);
 }
 
+static void test_get_pgmptr(void)
+{
+    char *pgm = NULL;
+    int res;
+
+    if (!p_get_pgmptr)
+        return;
+
+    res = p_get_pgmptr(&pgm);
+
+    ok( res == 0, "Wrong _get_pgmptr return value %d expected 0\n", res);
+    ok( pgm != NULL, "_get_pgmptr returned a NULL pointer\n" );
+}
+
 START_TEST(data)
 {
     HMODULE hmsvcrt;
@@ -116,7 +132,11 @@ START_TEST(data)
     if (!hmsvcrt)
         hmsvcrt = GetModuleHandleA("msvcrtd.dll");
     if (hmsvcrt)
+    {
         p_initterm=(void*)GetProcAddress(hmsvcrt, "_initterm");
+        p_get_pgmptr=(void*)GetProcAddress(hmsvcrt, "_get_pgmptr");
+    }
     test_initterm();
     test_initvar(hmsvcrt);
+    test_get_pgmptr();
 }
index 336238c..fdfe81f 100644 (file)
@@ -42,6 +42,25 @@ 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 char ***p_environ;
+static WCHAR ***p_wenviron;
+
+static void init(void)
+{
+    HMODULE hmod = GetModuleHandleA("msvcrt.dll");
+
+    p__p__environ = (void *)GetProcAddress(hmod, "__p__environ");
+    p__p__wenviron = (void *)GetProcAddress(hmod, "__p__wenviron");
+    p_environ = (void *)GetProcAddress(hmod, "_environ");
+    p_wenviron = (void *)GetProcAddress(hmod, "_wenviron");
+}
+
 static void test_system(void)
 {
     int ret = system(NULL);
@@ -51,7 +70,145 @@ static void test_system(void)
     ok(ret == 0, "Expected system to return 0, got %d\n", ret);
 }
 
-START_TEST(environ)
+static void test__environ(void)
+{
+    int argc;
+    char **argv, **envp = NULL;
+    int i, 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" );
+
+    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" );
+    }
+    else
+        win_skip( "__p__environ() 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;
+    }
+
+    for (i = 0; ; i++)
+    {
+        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;
+        }
+    }
+}
+
+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;
+
+    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;
+    }
+
+    /* 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" );
+    }
+    else
+        win_skip( "__p__wenviron() 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( envp != NULL, "Expected initial environment block pointer to be non-NULL\n" );
+    if (!envp)
+    {
+        skip( "Initial environment block pointer is not valid\n" );
+        return;
+    }
+
+    /* 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" );
+
+    /* _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( *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)
+    {
+        skip( "Initial environment block pointer is not valid\n" );
+        return;
+    }
+
+    /* Examine the returned pointer from __p__wenviron(),
+     * if available, after _wenviron is initialized. */
+    if (p__p__wenviron)
+    {
+        ok( *p__p__wenviron() == *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)
 {
     ok( _putenv("cat=") == 0, "_putenv failed on deletion of nonexistent environment variable\n" );
     ok( _putenv("cat=dog") == 0, "failed setting cat=dog\n" );
@@ -63,6 +220,16 @@ START_TEST(environ)
     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" );
+}
+
+START_TEST(environ)
+{
+    init();
 
+    /* The environ tests should always be run first, as they assume
+     * that the process has not manipulated the environment. */
+    test__environ();
+    test__wenviron();
+    test_environment_manipulation();
     test_system();
 }
index ef7b28d..e7b7353 100644 (file)
 
 static HANDLE proc_handles[2];
 
+static int (__cdecl *p_fopen_s)(FILE**, const char*, const char*);
+static int (__cdecl *p__wfopen_s)(FILE**, const wchar_t*, const wchar_t*);
+
+static void init(void)
+{
+    HMODULE hmod = GetModuleHandleA("msvcrt.dll");
+
+    p_fopen_s = (void*)GetProcAddress(hmod, "fopen_s");
+    p__wfopen_s = (void*)GetProcAddress(hmod, "_wfopen_s");
+}
+
 static void test_filbuf( void )
 {
     FILE *fp;
@@ -95,54 +106,59 @@ static void test_fileops( void )
     int fd;
     FILE *file;
     fpos_t pos;
-    int i, c;
+    int i, c, bufmode;
+    static const int bufmodes[] = {_IOFBF,_IONBF};
 
     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
     write (fd, outbuffer, sizeof (outbuffer));
     close (fd);
 
-    fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
-    file = fdopen (fd, "rb");
-    ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error\n");
-    ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected\n");
-    ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF\n");
-    ok(feof(file) !=0,"feof doesn't signal EOF\n");
-    rewind(file);
-    ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected\n");
-    ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size\n");
-    ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
-    ok(strlen(buffer) == 1,"fgets dropped chars\n");
-    ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars\n");
-
-    rewind(file);
-    for (i = 0, c = EOF; i < sizeof(outbuffer); i++)
+    for (bufmode=0; bufmode < sizeof(bufmodes)/sizeof(bufmodes[0]); bufmode++)
     {
-        ok((c = fgetc(file)) == outbuffer[i], "fgetc returned wrong data\n");
+        fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
+        file = fdopen (fd, "rb");
+        setvbuf(file,NULL,bufmodes[bufmode],2048);
+        ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(feof(file) !=0,"feof doesn't signal EOF for bufmode=%x\n", bufmodes[bufmode]);
+        rewind(file);
+        ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(strlen(buffer) == 1,"fgets dropped chars for bufmode=%x\n", bufmodes[bufmode]);
+        ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars for bufmode=%x\n", bufmodes[bufmode]);
+
+        rewind(file);
+        for (i = 0; i < sizeof(outbuffer); i++)
+        {
+            ok(fgetc(file) == outbuffer[i], "fgetc returned wrong data for bufmode=%x\n", bufmodes[bufmode]);
+        }
+        ok((c = fgetc(file)) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(feof(file), "feof did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(feof(file), "feof after ungetc(EOF) did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgetc(file) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        c = outbuffer[sizeof(outbuffer) - 1];
+        ok(ungetc(c, file) == c, "ungetc did not return its input for bufmode=%x\n", bufmodes[bufmode]);
+        ok(!feof(file), "feof after ungetc returned EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(c == outbuffer[sizeof(outbuffer) - 1],
+           "getc did not return ungetc'd data for bufmode=%x\n", bufmodes[bufmode]);
+        ok(!feof(file), "feof after getc returned EOF prematurely for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgetc(file) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+        ok(feof(file), "feof after getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
+
+        rewind(file);
+        ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(pos == 0, "Unexpected result of fgetpos %x%08x for bufmode=%x\n", (DWORD)(pos >> 32), (DWORD)pos, bufmodes[bufmode]);
+        pos = sizeof (outbuffer);
+        ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
+        ok(pos == sizeof (outbuffer), "Unexpected result of fgetpos %x%08x for bufmode=%x\n", (DWORD)(pos >> 32), (DWORD)pos, bufmodes[bufmode]);
+
+        fclose (file);
     }
-    ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
-    ok(feof(file), "feof did not return EOF\n");
-    ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF\n");
-    ok(feof(file), "feof after ungetc(EOF) did not return EOF\n");
-    ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
-    c = outbuffer[sizeof(outbuffer) - 1];
-    ok(ungetc(c, file) == c, "ungetc did not return its input\n");
-    ok(!feof(file), "feof after ungetc returned EOF\n");
-    ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF\n");
-    ok(c == outbuffer[sizeof(outbuffer) - 1],
-       "getc did not return ungetc'd data\n");
-    ok(!feof(file), "feof after getc returned EOF prematurely\n");
-    ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
-    ok(feof(file), "feof after getc did not return EOF\n");
-
-    rewind(file);
-    ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
-    ok(pos == 0, "Unexpected result of fgetpos %x%08x\n", (DWORD)(pos >> 32), (DWORD)pos);
-    pos = sizeof (outbuffer);
-    ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected\n");
-    ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
-    ok(pos == sizeof (outbuffer), "Unexpected result of fgetpos %x%08x\n", (DWORD)(pos >> 32), (DWORD)pos);
-
-    fclose (file);
     fd = open ("fdopen.tst", O_RDONLY | O_TEXT);
     file = fdopen (fd, "rt"); /* open in TEXT mode */
     ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) !=0,"fgetws failed unexpected\n");
@@ -342,17 +358,21 @@ static void test_asciimode(void)
 
     fp = fopen("ascii.tst", "r");
     c= fgetc(fp);
+    ok(c == '0', "fgetc failed, expected '0', got '%c'\n", c);
     c= fgetc(fp);
+    ok(c == '\n', "fgetc failed, expected '\\n', got '%c'\n", c);
     fseek(fp,0,SEEK_CUR);
     for(i=1; i<10; i++) {
        ok((j = ftell(fp)) == i*3, "ftell fails in TEXT mode\n");
        fseek(fp,0,SEEK_CUR);
        ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek failed in line %d\n", i);
        c= fgetc(fp);
+        ok(c == '\n', "fgetc failed, expected '\\n', got '%c'\n", c);
     }
     /* Show that fseek doesn't skip \\r !*/
     rewind(fp);
     c= fgetc(fp);
+    ok(c == '0', "fgetc failed, expected '0', got '%c'\n", c);
     fseek(fp, 2 ,SEEK_CUR);
     for(i=1; i<10; i++) {
        ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek with pos Offset failed in line %d\n", i);
@@ -360,6 +380,7 @@ static void test_asciimode(void)
     }
     fseek(fp, 9*3 ,SEEK_SET);
     c = fgetc(fp);
+    ok(c == '9', "fgetc failed, expected '9', got '%c'\n", c);
     fseek(fp, -4 ,SEEK_CUR);
     for(i= 8; i>=0; i--) {
        ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek with neg Offset failed in line %d\n", i);
@@ -1201,6 +1222,82 @@ static void test_fopen_fclose_fcloseall( void )
     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
 }
 
+static void test_fopen_s( void )
+{
+    const char name[] = "empty1";
+    char buff[16];
+    FILE *file;
+    int ret;
+    int len;
+
+    if (!p_fopen_s)
+    {
+        win_skip("Skipping fopen_s test\n");
+        return;
+    }
+    /* testing fopen_s */
+    ret = p_fopen_s(&file, name, "w");
+    ok(ret == 0, "fopen_s failed with %d\n", ret);
+    ok(file != 0, "fopen_s failed to return value\n");
+    fwrite(name, sizeof(name), 1, file);
+
+    ret = fclose(file);
+    ok(ret != EOF, "File failed to close\n");
+
+    file = fopen(name, "r");
+    ok(file != 0, "fopen failed\n");
+    len = fread(buff, 1, sizeof(name), file);
+    ok(len == sizeof(name), "File length is %d\n", len);
+    buff[sizeof(name)] = '\0';
+    ok(strcmp(name, buff) == 0, "File content mismatch! Got %s, expected %s\n", buff, name);
+
+    ret = fclose(file);
+    ok(ret != EOF, "File failed to close\n");
+
+    ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name);
+}
+
+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;
+    int len;
+
+    if (!p__wfopen_s)
+    {
+        win_skip("Skipping _wfopen_s test\n");
+        return;
+    }
+    /* testing _wfopen_s */
+    ret = p__wfopen_s(&file, wname, wmode);
+    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);
+
+    ret = fclose(file);
+    ok(ret != EOF, "File failed to close\n");
+
+    file = fopen(name, "r");
+    ok(file != 0, "fopen failed\n");
+    len = fread(buff, 1, sizeof(name), file);
+    ok(len == sizeof(name), "File length is %d\n", len);
+    buff[sizeof(name)] = '\0';
+    ok(strcmp(name, buff) == 0, "File content mismatch! Got %s, expected %s\n", buff, name);
+
+    ret = fclose(file);
+    ok(ret != EOF, "File failed to close\n");
+
+    ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name);
+}
+
 static void test_get_osfhandle(void)
 {
     int fd;
@@ -1213,7 +1310,7 @@ static void test_get_osfhandle(void)
     WriteFile(handle, "bar", 3, &bytes_written, NULL);
     _close(fd);
     fd = _open(fname, _O_RDONLY, 0);
-    ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
+    ok(fd != -1, "Couldn't open '%s' after _get_osfhandle()\n", fname);
 
     _close(fd);
     _unlink(fname);
@@ -1229,13 +1326,15 @@ static void test_stat(void)
 {
     int fd;
     int pipes[2];
+    int ret;
     struct stat buf;
 
     /* Tests for a file */
     fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
     if (fd >= 0)
     {
-        ok(fstat(fd, &buf) == 0, "fstat failed: errno=%d\n", errno);
+        ret = fstat(fd, &buf);
+        ok(!ret, "fstat failed: errno=%d\n", errno);
         ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
         ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
         ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
@@ -1243,7 +1342,8 @@ static void test_stat(void)
         ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
         ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size);
 
-        ok(stat("stat.tst", &buf) == 0, "stat failed: errno=%d\n", errno);
+        ret = stat("stat.tst", &buf);
+        ok(!ret, "stat failed: errno=%d\n", errno);
         ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
         ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
         ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
@@ -1259,7 +1359,8 @@ static void test_stat(void)
     /* Tests for a char device */
     if (_dup2(0, 10) == 0)
     {
-        ok(fstat(10, &buf) == 0, "fstat(stdin) failed: errno=%d\n", errno);
+        ret = fstat(10, &buf);
+        ok(!ret, "fstat(stdin) failed: errno=%d\n", errno);
         if ((buf.st_mode & _S_IFMT) == _S_IFCHR)
         {
             ok(buf.st_mode == _S_IFCHR, "bad st_mode=%06o\n", buf.st_mode);
@@ -1277,7 +1378,8 @@ static void test_stat(void)
     /* Tests for pipes */
     if (_pipe(pipes, 1024, O_BINARY) == 0)
     {
-        ok(fstat(pipes[0], &buf) == 0, "fstat(pipe) failed: errno=%d\n", errno);
+        ret = fstat(pipes[0], &buf);
+        ok(!ret, "fstat(pipe) failed: errno=%d\n", errno);
         ok(buf.st_mode == _S_IFIFO, "bad st_mode=%06o\n", buf.st_mode);
         ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", buf.st_dev, pipes[0]);
         ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", buf.st_rdev, pipes[0]);
@@ -1307,7 +1409,8 @@ static void test_pipes_child(int argc, char** args)
     }
 
     fd=atoi(args[3]);
-    ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
+    i=close(fd);
+    ok(!i, "unable to close %d: %d\n", fd, errno);
 
     fd=atoi(args[4]);
 
@@ -1319,7 +1422,8 @@ static void test_pipes_child(int argc, char** args)
            Sleep(100);
     }
 
-    ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
+    i=close(fd);
+    ok(!i, "unable to close %d: %d\n", fd, errno);
 }
 
 static void test_pipes(const char* selfname)
@@ -1347,7 +1451,8 @@ static void test_pipes(const char* selfname)
     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
     arg_v[5] = NULL;
     proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
-    ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
+    i=close(pipes[1]);
+    ok(!i, "unable to close %d: %d\n", pipes[1], errno);
 
     for (i=0; i<N_TEST_MESSAGES; i++) {
        r=read(pipes[0], buf, sizeof(buf)-1);
@@ -1359,7 +1464,8 @@ static void test_pipes(const char* selfname)
 
     r=read(pipes[0], buf, sizeof(buf)-1);
     ok(r == 0, "expected to read 0 bytes, got %d\n", r);
-    ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno);
+    i=close(pipes[0]);
+    ok(!i, "unable to close %d: %d\n", pipes[0], errno);
 
     /* Test reading from a pipe with fread() */
     if (_pipe(pipes, 1024, O_BINARY) < 0)
@@ -1375,7 +1481,8 @@ static void test_pipes(const char* selfname)
     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
     arg_v[5] = NULL;
     proc_handles[1] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
-    ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
+    i=close(pipes[1]);
+    ok(!i, "unable to close %d: %d\n", pipes[1], errno);
     file=fdopen(pipes[0], "r");
 
     /* In blocking mode, fread will keep calling read() until it gets
@@ -1398,7 +1505,8 @@ static void test_pipes(const char* selfname)
     ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
     ok(feof(file), "feof() is false!\n");
 
-    ok(fclose(file) == 0, "unable to close the pipe: %d\n", errno);
+    i=fclose(file);
+    ok(!i, "unable to close the pipe: %d\n", errno);
 }
 
 static void test_unlink(void)
@@ -1424,6 +1532,8 @@ START_TEST(file)
     int arg_c;
     char** arg_v;
 
+    init();
+
     arg_c = winetest_get_mainargs( &arg_v );
 
     /* testing low-level I/O */
@@ -1450,6 +1560,8 @@ START_TEST(file)
     test_filbuf();
     test_fdopen();
     test_fopen_fclose_fcloseall();
+    test_fopen_s();
+    test__wfopen_s();
     test_fileops();
     test_asciimode();
     test_asciimode2();
index c39948d..7c102b4 100644 (file)
@@ -260,6 +260,7 @@ static void test_structs(void)
     CHECK_FIELD(_stat64, st_atime);
     CHECK_FIELD(_stat64, st_mtime);
     CHECK_FIELD(_stat64, st_ctime);
+    CHECK_SIZE(_CRT_FLOAT);
 }
 
 /************* Checking defines ***************/
@@ -339,6 +340,8 @@ static void test_defines(void)
     CHECK_DEF(_FREEENTRY);
     CHECK_DEF(_USEDENTRY);
     CHECK_DEF(_OUT_TO_DEFAULT);
+    CHECK_DEF(_OUT_TO_STDERR);
+    CHECK_DEF(_OUT_TO_MSGBOX);
     CHECK_DEF(_REPORT_ERRMODE);
     CHECK_DEF(_UPPER);
     CHECK_DEF(_LOWER);
@@ -425,7 +428,11 @@ static void test_defines(void)
     CHECK_DEF(_FPE_STACKOVERFLOW);
     CHECK_DEF(_FPE_STACKUNDERFLOW);
     CHECK_DEF(_FPE_EXPLICITGEN);
-#ifdef __i386__
+    CHECK_DEF(_MCW_EM);
+    CHECK_DEF(_MCW_IC);
+    CHECK_DEF(_MCW_RC);
+    CHECK_DEF(_MCW_PC);
+    CHECK_DEF(_MCW_DN);
     CHECK_DEF(_EM_INVALID);
     CHECK_DEF(_EM_DENORMAL);
     CHECK_DEF(_EM_ZERODIVIDE);
@@ -441,7 +448,16 @@ static void test_defines(void)
     CHECK_DEF(_PC_24);
     CHECK_DEF(_PC_53);
     CHECK_DEF(_PC_64);
-#endif
+    CHECK_DEF(_DN_SAVE);
+    CHECK_DEF(_DN_FLUSH);
+    CHECK_DEF(_DN_FLUSH_OPERANDS_SAVE_RESULTS);
+    CHECK_DEF(_DN_SAVE_OPERANDS_FLUSH_RESULTS);
+    CHECK_DEF(_EM_AMBIGUOUS);
+    CHECK_DEF(_OVERFLOW);
+    CHECK_DEF(_UNDERFLOW);
+    CHECK_DEF(_WRITE_ABORT_MSG);
+    CHECK_DEF(_CALL_REPORTFAULT);
+    CHECK_DEF(_TWO_DIGIT_EXPONENT);
 }
 
 #endif /* __WINE_USE_MSVCRT */
index cf51c4c..0e8d0dd 100644 (file)
@@ -110,31 +110,32 @@ static void test_setlocale(void)
     ret = setlocale(LC_ALL, "chinese");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
+        ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "chinese-simplified");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
-        || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret);
+        ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
+        || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))
+        || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "chinese-traditional");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
+        ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "chs");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
+        ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")
         || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "cht");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
+        ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950")
         || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "csy");
@@ -389,12 +390,14 @@ static void test_setlocale(void)
     ret = setlocale(LC_ALL, "italian-swiss");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        ok(!strcmp(ret, "Italian_Switzerland.1252") || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
+        ok(!strcmp(ret, "Italian_Switzerland.1252")
+        || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "its");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        ok(!strcmp(ret, "Italian_Switzerland.1252") || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
+        ok(!strcmp(ret, "Italian_Switzerland.1252")
+        || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "japanese");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
@@ -430,30 +433,33 @@ static void test_setlocale(void)
     ret = setlocale(LC_ALL, "non");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok((!strcmp( ret, "Norwegian-Nynorsk_Norway.1252"))
-        || broken(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252"))
-        || broken(!strcmp(ret, "Norwegian_Norway.1252"))
-        || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")), "ret = %s\n", ret);
+        ok(!strcmp( ret, "Norwegian-Nynorsk_Norway.1252")
+        || !strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")
+        || broken(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252"))
+        || broken(!strcmp(ret, "Norwegian_Norway.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "nor");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        ok(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252")
+        ok(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252")
+        || !strcmp(ret, "Norwegian (Bokmal)_Norway.1252")
         || broken(!strcmp(ret, "Norwegian_Norway.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "norwegian-bokmal");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        ok(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252")
+        ok(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252")
+        || !strcmp(ret, "Norwegian (Bokmal)_Norway.1252")
         || broken(!strcmp(ret, "Norwegian_Norway.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "norwegian-nynorsk");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Norwegian-Nynorsk_Norway.1252")
+        ok(!strcmp(ret, "Norwegian-Nynorsk_Norway.1252")
+        || !strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")
         || broken(!strcmp(ret, "Norwegian_Norway.1252"))
-        || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))
-        || broken(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252")), "ret = %s\n", ret);
+        || broken(!strcmp(ret, "Norwegian (Bokmal)_Norway.1252"))
+        || broken(!strcmp(ret, "Norwegian (Bokm\xe5l)_Norway.1252")), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "plk");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
@@ -520,8 +526,8 @@ static void test_setlocale(void)
     ret = setlocale(LC_ALL, "spanish-modern");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
     if(ret)
-        todo_wine ok(!strcmp(ret, "Spanish - Modern Sort_Spain.1252")
-        || broken(!strcmp(ret, "Spanish_Spain.1252")), "ret = %s\n", ret);
+        ok(!strcmp(ret, "Spanish - Modern Sort_Spain.1252")
+           || !strcmp(ret, "Spanish_Spain.1252"), "ret = %s\n", ret);
 
     ret = setlocale(LC_ALL, "sve");
     ok(ret != NULL || broken (ret == NULL), "ret == NULL\n");
index a7135c0..7135248 100644 (file)
 
 #include "wine/test.h"
 #include <errno.h>
-// #include "msvcrt.h"
+#include "msvcrt.h"
 
 static int (__cdecl *prand_s)(unsigned int *);
-static int (__cdecl *pmemcpy_s)(void *, size_t, void*, size_t);
+static int (__cdecl *pmemcpy_s)(void *, MSVCRT_size_t, void*, MSVCRT_size_t);
 static int (__cdecl *pI10_OUTPUT)(long double, int, int, void*);
+static int (__cdecl *pstrerror_s)(char *, MSVCRT_size_t, int);
+static 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 init(void)
 {
@@ -33,6 +38,11 @@ static void init(void)
     prand_s = (void *)GetProcAddress(hmod, "rand_s");
     pmemcpy_s = (void*)GetProcAddress(hmod, "memcpy_s");
     pI10_OUTPUT = (void*)GetProcAddress(hmod, "$I10_OUTPUT");
+    pstrerror_s = (void *)GetProcAddress(hmod, "strerror_s");
+    p_get_doserrno = (void *)GetProcAddress(hmod, "_get_doserrno");
+    p_get_errno = (void *)GetProcAddress(hmod, "_get_errno");
+    p_set_doserrno = (void *)GetProcAddress(hmod, "_set_doserrno");
+    p_set_errno = (void *)GetProcAddress(hmod, "_set_errno");
 }
 
 static void test_rand_s(void)
@@ -160,17 +170,28 @@ static const I10_OUTPUT_test I10_OUTPUT_tests[] = {
 static void test_I10_OUTPUT(void)
 {
     I10_OUTPUT_data out;
-    int i, j, ret;
+    int i, j = sizeof(long double), ret;
 
     if(!pI10_OUTPUT) {
         win_skip("I10_OUTPUT not available\n");
         return;
     }
+    if (j != 12)
+        trace("sizeof(long double) = %d on this machine\n", j);
 
     for(i=0; i<sizeof(I10_OUTPUT_tests)/sizeof(I10_OUTPUT_test); i++) {
         memset(out.str, '#', sizeof(out.str));
 
-        ret = pI10_OUTPUT(I10_OUTPUT_tests[i].d, I10_OUTPUT_tests[i].size, I10_OUTPUT_tests[i].flags, &out);
+        if (sizeof(long double) == 12)
+            ret = pI10_OUTPUT(I10_OUTPUT_tests[i].d, I10_OUTPUT_tests[i].size, I10_OUTPUT_tests[i].flags, &out);
+        else {
+            /* MS' "long double" is an 80 bit FP that takes 12 bytes*/
+            typedef struct { ULONG x80[3]; } uld; /* same calling convention */
+            union { long double ld; uld ld12; } fp80;
+            int (__cdecl *pI10_OUTPUT12)(uld, int, int, void*) = (void*)pI10_OUTPUT;
+            fp80.ld = I10_OUTPUT_tests[i].d;
+            ret = pI10_OUTPUT12(fp80.ld12, I10_OUTPUT_tests[i].size, I10_OUTPUT_tests[i].flags, &out);
+        }
         ok(ret == I10_OUTPUT_tests[i].ret, "%d: ret = %d\n", i, ret);
         ok(out.pos == I10_OUTPUT_tests[i].out.pos, "%d: out.pos = %hd\n", i, out.pos);
         ok(out.sign == I10_OUTPUT_tests[i].out.sign, "%d: out.size = %c\n", i, out.sign);
@@ -192,6 +213,155 @@ static void test_I10_OUTPUT(void)
     }
 }
 
+static void test_strerror_s(void)
+{
+    int ret;
+    char buf[256];
+
+    if (!pstrerror_s)
+    {
+        win_skip("strerror_s is not available\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = pstrerror_s(NULL, 0, 0);
+    ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = pstrerror_s(NULL, sizeof(buf), 0);
+    ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(buf, 'X', sizeof(buf));
+    errno = EBADF;
+    ret = pstrerror_s(buf, 0, 0);
+    ok(ret == EINVAL, "Expected strerror_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buf[0] == 'X', "Expected output buffer to be untouched\n");
+
+    memset(buf, 'X', sizeof(buf));
+    ret = pstrerror_s(buf, 1, 0);
+    ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
+    ok(strlen(buf) == 0, "Expected output buffer to be null terminated\n");
+
+    memset(buf, 'X', sizeof(buf));
+    ret = pstrerror_s(buf, 2, 0);
+    ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
+    ok(strlen(buf) == 1, "Expected output buffer to be truncated\n");
+
+    memset(buf, 'X', sizeof(buf));
+    ret = pstrerror_s(buf, sizeof(buf), 0);
+    ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
+
+    memset(buf, 'X', sizeof(buf));
+    ret = pstrerror_s(buf, sizeof(buf), -1);
+    ok(ret == 0, "Expected strerror_s to return 0, got %d\n", ret);
+}
+
+static void test__get_doserrno(void)
+{
+    int ret, out;
+
+    if (!p_get_doserrno)
+    {
+        win_skip("_get_doserrno is not available\n");
+        return;
+    }
+
+    _doserrno = ERROR_INVALID_CMM;
+    errno = EBADF;
+    ret = p_get_doserrno(NULL);
+    ok(ret == EINVAL, "Expected _get_doserrno to return EINVAL, got %d\n", ret);
+    ok(_doserrno == ERROR_INVALID_CMM, "Expected _doserrno to be ERROR_INVALID_CMM, got %d\n", _doserrno);
+    ok(errno == EBADF, "Expected errno to be EBADF, got %d\n", errno);
+
+    _doserrno = ERROR_INVALID_CMM;
+    errno = EBADF;
+    out = 0xdeadbeef;
+    ret = p_get_doserrno(&out);
+    ok(ret == 0, "Expected _get_doserrno to return 0, got %d\n", ret);
+    ok(out == ERROR_INVALID_CMM, "Expected output variable to be ERROR_INVAID_CMM, got %d\n", out);
+}
+
+static void test__get_errno(void)
+{
+    int ret, out;
+
+    if (!p_get_errno)
+    {
+        win_skip("_get_errno is not available\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_get_errno(NULL);
+    ok(ret == EINVAL, "Expected _get_errno to return EINVAL, got %d\n", ret);
+    ok(errno == EBADF, "Expected errno to be EBADF, got %d\n", errno);
+
+    errno = EBADF;
+    out = 0xdeadbeef;
+    ret = p_get_errno(&out);
+    ok(ret == 0, "Expected _get_errno to return 0, got %d\n", ret);
+    ok(out == EBADF, "Expected output variable to be EBADF, got %d\n", out);
+}
+
+static void test__set_doserrno(void)
+{
+    int ret;
+
+    if (!p_set_doserrno)
+    {
+        win_skip("_set_doserrno is not available\n");
+        return;
+    }
+
+    _doserrno = ERROR_INVALID_CMM;
+    ret = p_set_doserrno(ERROR_FILE_NOT_FOUND);
+    ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
+    ok(_doserrno == ERROR_FILE_NOT_FOUND,
+       "Expected _doserrno to be ERROR_FILE_NOT_FOUND, got %d\n", _doserrno);
+
+    _doserrno = ERROR_INVALID_CMM;
+    ret = p_set_doserrno(-1);
+    ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
+    ok(_doserrno == -1,
+       "Expected _doserrno to be -1, got %d\n", _doserrno);
+
+    _doserrno = ERROR_INVALID_CMM;
+    ret = p_set_doserrno(0xdeadbeef);
+    ok(ret == 0, "Expected _set_doserrno to return 0, got %d\n", ret);
+    ok(_doserrno == 0xdeadbeef,
+       "Expected _doserrno to be 0xdeadbeef, got %d\n", _doserrno);
+}
+
+static void test__set_errno(void)
+{
+    int ret;
+
+    if (!p_set_errno)
+    {
+        win_skip("_set_errno is not available\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_set_errno(EINVAL);
+    ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_set_errno(-1);
+    ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
+    ok(errno == -1, "Expected errno to be -1, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_set_errno(0xdeadbeef);
+    ok(ret == 0, "Expected _set_errno to return 0, got %d\n", ret);
+    ok(errno == 0xdeadbeef, "Expected errno to be 0xdeadbeef, got %d\n", errno);
+}
+
 START_TEST(misc)
 {
     init();
@@ -199,4 +369,9 @@ START_TEST(misc)
     test_rand_s();
     test_memcpy_s();
     test_I10_OUTPUT();
+    test_strerror_s();
+    test__get_doserrno();
+    test__get_errno();
+    test__set_doserrno();
+    test__set_errno();
 }
diff --git a/rostests/winetests/msvcrt/msvcrt.h b/rostests/winetests/msvcrt/msvcrt.h
new file mode 100644 (file)
index 0000000..66f6bd0
--- /dev/null
@@ -0,0 +1,969 @@
+/*
+ * Copyright 2001 Jon Griffiths
+ * Copyright 2004 Dimitrie O. Paun
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES
+ *   Naming conventions
+ *     - Symbols are prefixed with MSVCRT_ if they conflict
+ *        with libc symbols
+ *      - Internal symbols are usually prefixed by msvcrt_.
+ *      - Exported symbols that are not present in the public
+ *        headers are usually kept the same as the original.
+ *   Other conventions
+ *      - To avoid conflicts with the standard C library,
+ *        no msvcrt headers are included in the implementation.
+ *      - Instead, symbols are duplicated here, prefixed with 
+ *        MSVCRT_, as explained above.
+ *      - To avoid inconsistencies, a test for each symbol is
+ *        added into tests/headers.c. Please always add a
+ *        corresponding test when you add a new symbol!
+ */
+
+#ifndef __WINE_MSVCRT_H
+#define __WINE_MSVCRT_H
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+
+#define MSVCRT_LONG_MAX    0x7fffffffL
+#define MSVCRT_ULONG_MAX   0xffffffffUL
+#define MSVCRT_I64_MAX    (((__int64)0x7fffffff << 32) | 0xffffffff)
+#define MSVCRT_I64_MIN    (-MSVCRT_I64_MAX-1)
+#define MSVCRT_UI64_MAX   (((unsigned __int64)0xffffffff << 32) | 0xffffffff)
+
+#define MSVCRT__MAX_DRIVE  3
+#define MSVCRT__MAX_DIR    256
+#define MSVCRT__MAX_FNAME  256
+#define MSVCRT__MAX_EXT    256
+
+typedef unsigned short MSVCRT_wchar_t;
+typedef unsigned short MSVCRT_wint_t;
+typedef unsigned short MSVCRT_wctype_t;
+typedef unsigned short MSVCRT__ino_t;
+typedef unsigned int   MSVCRT__fsize_t;
+typedef int            MSVCRT_long;
+typedef unsigned int   MSVCRT_ulong;
+#ifdef _WIN64
+typedef unsigned __int64 MSVCRT_size_t;
+typedef __int64 MSVCRT_intptr_t;
+typedef unsigned __int64 MSVCRT_uintptr_t;
+#else
+typedef unsigned long MSVCRT_size_t;
+typedef long MSVCRT_intptr_t;
+typedef unsigned long MSVCRT_uintptr_t;
+#endif
+typedef unsigned int   MSVCRT__dev_t;
+typedef int MSVCRT__off_t;
+typedef int MSVCRT_clock_t;
+typedef int MSVCRT___time32_t;
+typedef __int64 DECLSPEC_ALIGN(8) MSVCRT___time64_t;
+typedef __int64 DECLSPEC_ALIGN(8) MSVCRT_fpos_t;
+typedef int MSVCRT_mbstate_t;
+
+typedef void (__cdecl *MSVCRT_terminate_handler)(void);
+typedef void (__cdecl *MSVCRT_terminate_function)(void);
+typedef void (__cdecl *MSVCRT_unexpected_handler)(void);
+typedef void (__cdecl *MSVCRT_unexpected_function)(void);
+typedef void (__cdecl *MSVCRT__se_translator_function)(unsigned int code, struct _EXCEPTION_POINTERS *info);
+typedef void (__cdecl *MSVCRT__beginthread_start_routine_t)(void *);
+typedef unsigned int (__stdcall *MSVCRT__beginthreadex_start_routine_t)(void *);
+typedef int (__cdecl *MSVCRT__onexit_t)(void);
+typedef void (__cdecl *MSVCRT_invalid_parameter_handler)(const MSVCRT_wchar_t*, const MSVCRT_wchar_t*, const MSVCRT_wchar_t*, unsigned, MSVCRT_uintptr_t);
+typedef void (__cdecl *MSVCRT_purecall_handler)(void);
+typedef void (__cdecl *MSVCRT_security_error_handler)(int, void *);
+
+typedef struct {ULONG x80[3];} MSVCRT__LDOUBLE; /* Intel 80 bit FP format has sizeof() 12 */
+
+struct MSVCRT_tm {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+};
+
+typedef struct MSVCRT_tagLC_ID {
+    unsigned short wLanguage;
+    unsigned short wCountry;
+    unsigned short wCodePage;
+} MSVCRT_LC_ID, *MSVCRT_LPLC_ID;
+
+typedef struct MSVCRT_threadlocaleinfostruct {
+    int refcount;
+    unsigned int lc_codepage;
+    unsigned int lc_collate_cp;
+    MSVCRT_ulong lc_handle[6];
+    MSVCRT_LC_ID lc_id[6];
+    struct {
+        char *locale;
+        wchar_t *wlocale;
+        int *refcount;
+        int *wrefcount;
+    } lc_category[6];
+    int lc_clike;
+    int mb_cur_max;
+    int *lconv_intl_refcount;
+    int *lconv_num_refcount;
+    int *lconv_mon_refcount;
+    struct MSVCRT_lconv *lconv;
+    int *ctype1_refcount;
+    unsigned short *ctype1;
+    unsigned short *pctype;
+    unsigned char *pclmap;
+    unsigned char *pcumap;
+    struct MSVCRT___lc_time_data *lc_time_curr;
+} MSVCRT_threadlocinfo;
+
+typedef struct MSVCRT_threadmbcinfostruct {
+    int refcount;
+    int mbcodepage;
+    int ismbcodepage;
+    int mblcid;
+    unsigned short mbulinfo[6];
+    unsigned char mbctype[257];
+    unsigned char mbcasemap[256];
+} MSVCRT_threadmbcinfo;
+
+typedef struct MSVCRT_threadlocaleinfostruct *MSVCRT_pthreadlocinfo;
+typedef struct MSVCRT_threadmbcinfostruct *MSVCRT_pthreadmbcinfo;
+
+typedef struct MSVCRT_localeinfo_struct
+{
+    MSVCRT_pthreadlocinfo locinfo;
+    MSVCRT_pthreadmbcinfo mbcinfo;
+} MSVCRT__locale_tstruct, *MSVCRT__locale_t;
+
+
+/* TLS data */
+extern DWORD msvcrt_tls_index;
+
+/* Keep in sync with msvcr90/tests/msvcr90.c */
+struct __thread_data {
+    DWORD                           tid;
+    HANDLE                          handle;
+    int                             thread_errno;
+    MSVCRT_ulong                    thread_doserrno;
+    int                             unk1;
+    unsigned int                    random_seed;        /* seed for rand() */
+    char                           *strtok_next;        /* next ptr for strtok() */
+    MSVCRT_wchar_t                 *wcstok_next;        /* next ptr for wcstok() */
+    unsigned char                  *mbstok_next;        /* next ptr for mbstok() */
+    char                           *strerror_buffer;    /* buffer for strerror */
+    MSVCRT_wchar_t                 *wcserror_buffer;    /* buffer for wcserror */
+    char                           *tmpnam_buffer;      /* buffer for tmpname() */
+    MSVCRT_wchar_t                 *wtmpnam_buffer;     /* buffer for wtmpname() */
+    void                           *unk2[2];
+    char                           *asctime_buffer;     /* buffer for asctime */
+    MSVCRT_wchar_t                 *wasctime_buffer;    /* buffer for wasctime */
+    struct MSVCRT_tm               *time_buffer;        /* buffer for localtime/gmtime */
+    char                           *efcvt_buffer;       /* buffer for ecvt/fcvt */
+    int                             unk3[2];
+    void                           *unk4[4];
+    int                             fpecode;
+    MSVCRT_pthreadmbcinfo           mbcinfo;
+    MSVCRT_pthreadlocinfo           locinfo;
+    BOOL                            have_locale;
+    int                             unk5[1];
+    MSVCRT_terminate_function       terminate_handler;
+    MSVCRT_unexpected_function      unexpected_handler;
+    MSVCRT__se_translator_function  se_translator;
+    void                           *unk6[3];
+    int                             unk7;
+    EXCEPTION_RECORD               *exc_record;
+    void                           *unk8[100];
+};
+
+typedef struct __thread_data thread_data_t;
+
+extern thread_data_t *msvcrt_get_thread_data(void);
+
+LCID MSVCRT_locale_to_LCID(const char *);
+extern MSVCRT__locale_t MSVCRT_locale;
+extern int MSVCRT___lc_codepage;
+extern int MSVCRT___lc_collate_cp;
+extern WORD MSVCRT__ctype [257];
+
+void   msvcrt_set_errno(int);
+
+void __cdecl _purecall(void);
+void __cdecl _amsg_exit(int errnum);
+
+extern char **MSVCRT__environ;
+extern MSVCRT_wchar_t **MSVCRT__wenviron;
+
+extern char ** msvcrt_SnapshotOfEnvironmentA(char **);
+extern MSVCRT_wchar_t ** msvcrt_SnapshotOfEnvironmentW(MSVCRT_wchar_t **);
+
+MSVCRT_wchar_t *msvcrt_wstrdupa(const char *);
+
+/* FIXME: This should be declared in new.h but it's not an extern "C" so
+ * it would not be much use anyway. Even for Winelib applications.
+ */
+int __cdecl MSVCRT__set_new_mode(int mode);
+
+void* __cdecl MSVCRT_operator_new(MSVCRT_size_t);
+void __cdecl MSVCRT_operator_delete(void*);
+
+typedef void* (__cdecl *malloc_func_t)(MSVCRT_size_t);
+typedef void  (__cdecl *free_func_t)(void*);
+
+extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t,unsigned short int);
+extern char* __cdecl __unDNameEx(char *,const char*,int,malloc_func_t,free_func_t,void *,unsigned short int);
+
+/* Setup and teardown multi threaded locks */
+extern void msvcrt_init_mt_locks(void);
+extern void msvcrt_free_mt_locks(void);
+
+extern BOOL msvcrt_init_locale(void);
+extern void msvcrt_init_math(void);
+extern void msvcrt_init_io(void);
+extern void msvcrt_free_io(void);
+extern void msvcrt_init_console(void);
+extern void msvcrt_free_console(void);
+extern void msvcrt_init_args(void);
+extern void msvcrt_free_args(void);
+extern void msvcrt_init_signals(void);
+extern void msvcrt_free_signals(void);
+
+extern unsigned msvcrt_create_io_inherit_block(WORD*, BYTE**);
+
+extern unsigned int __cdecl _control87(unsigned int, unsigned int);
+
+/* run-time error codes */
+#define _RT_STACK       0
+#define _RT_NULLPTR     1
+#define _RT_FLOAT       2
+#define _RT_INTDIV      3
+#define _RT_EXECMEM     5
+#define _RT_EXECFORM    6
+#define _RT_EXECENV     7
+#define _RT_SPACEARG    8
+#define _RT_SPACEENV    9
+#define _RT_ABORT       10
+#define _RT_NPTR        12
+#define _RT_FPTR        13
+#define _RT_BREAK       14
+#define _RT_INT         15
+#define _RT_THREAD      16
+#define _RT_LOCK        17
+#define _RT_HEAP        18
+#define _RT_OPENCON     19
+#define _RT_QWIN        20
+#define _RT_NOMAIN      21
+#define _RT_NONCONT     22
+#define _RT_INVALDISP   23
+#define _RT_ONEXIT      24
+#define _RT_PUREVIRT    25
+#define _RT_STDIOINIT   26
+#define _RT_LOWIOINIT   27
+#define _RT_HEAPINIT    28
+#define _RT_DOMAIN      120
+#define _RT_SING        121
+#define _RT_TLOSS       122
+#define _RT_CRNL        252
+#define _RT_BANNER      255
+
+struct MSVCRT___timeb32 {
+    MSVCRT___time32_t  time;
+    unsigned short millitm;
+    short          timezone;
+    short          dstflag;
+};
+
+struct MSVCRT___timeb64 {
+    MSVCRT___time64_t time;
+    unsigned short millitm;
+    short          timezone;
+    short          dstflag;
+};
+
+struct MSVCRT__iobuf {
+  char* _ptr;
+  int   _cnt;
+  char* _base;
+  int   _flag;
+  int   _file;
+  int   _charbuf;
+  int   _bufsiz;
+  char* _tmpfname;
+};
+
+typedef struct MSVCRT__iobuf MSVCRT_FILE;
+
+struct MSVCRT_lconv {
+    char* decimal_point;
+    char* thousands_sep;
+    char* grouping;
+    char* int_curr_symbol;
+    char* currency_symbol;
+    char* mon_decimal_point;
+    char* mon_thousands_sep;
+    char* mon_grouping;
+    char* positive_sign;
+    char* negative_sign;
+    char int_frac_digits;
+    char frac_digits;
+    char p_cs_precedes;
+    char p_sep_by_space;
+    char n_cs_precedes;
+    char n_sep_by_space;
+    char p_sign_posn;
+    char n_sign_posn;
+};
+
+struct MSVCRT__exception {
+  int     type;
+  char*   name;
+  double  arg1;
+  double  arg2;
+  double  retval;
+};
+
+struct MSVCRT__complex {
+  double x;      /* Real part */
+  double y;      /* Imaginary part */
+};
+
+typedef struct MSVCRT__div_t {
+    int quot;  /* quotient */
+    int rem;   /* remainder */
+} MSVCRT_div_t;
+
+typedef struct MSVCRT__ldiv_t {
+    MSVCRT_long quot;  /* quotient */
+    MSVCRT_long rem;   /* remainder */
+} MSVCRT_ldiv_t;
+
+struct MSVCRT__heapinfo {
+  int*           _pentry;
+  MSVCRT_size_t  _size;
+  int            _useflag;
+};
+
+#ifdef __i386__
+struct MSVCRT___JUMP_BUFFER {
+    unsigned long Ebp;
+    unsigned long Ebx;
+    unsigned long Edi;
+    unsigned long Esi;
+    unsigned long Esp;
+    unsigned long Eip;
+    unsigned long Registration;
+    unsigned long TryLevel;
+    /* Start of new struct members */
+    unsigned long Cookie;
+    unsigned long UnwindFunc;
+    unsigned long UnwindData[6];
+};
+#elif defined(__x86_64__)
+struct MSVCRT__SETJMP_FLOAT128
+{
+    unsigned __int64 DECLSPEC_ALIGN(16) Part[2];
+};
+struct MSVCRT___JUMP_BUFFER
+{
+    unsigned __int64 Frame;
+    unsigned __int64 Rbx;
+    unsigned __int64 Rsp;
+    unsigned __int64 Rbp;
+    unsigned __int64 Rsi;
+    unsigned __int64 Rdi;
+    unsigned __int64 R12;
+    unsigned __int64 R13;
+    unsigned __int64 R14;
+    unsigned __int64 R15;
+    unsigned __int64 Rip;
+    unsigned __int64 Spare;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm6;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm7;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm8;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm9;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm10;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm11;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm12;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm13;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm14;
+    struct MSVCRT__SETJMP_FLOAT128 Xmm15;
+};
+#endif /* __i386__ */
+
+struct MSVCRT__diskfree_t {
+  unsigned int total_clusters;
+  unsigned int avail_clusters;
+  unsigned int sectors_per_cluster;
+  unsigned int bytes_per_sector;
+};
+
+struct MSVCRT__finddata32_t {
+  unsigned int      attrib;
+  MSVCRT___time32_t time_create;
+  MSVCRT___time32_t time_access;
+  MSVCRT___time32_t time_write;
+  MSVCRT__fsize_t   size;
+  char              name[260];
+};
+
+struct MSVCRT__finddata32i64_t {
+  unsigned int      attrib;
+  MSVCRT___time32_t time_create;
+  MSVCRT___time32_t time_access;
+  MSVCRT___time32_t time_write;
+  __int64 DECLSPEC_ALIGN(8) size;
+  char              name[260];
+};
+
+struct MSVCRT__finddata64i32_t {
+  unsigned int      attrib;
+  MSVCRT___time64_t time_create;
+  MSVCRT___time64_t time_access;
+  MSVCRT___time64_t time_write;
+  MSVCRT__fsize_t   size;
+  char              name[260];
+};
+
+struct MSVCRT__finddata64_t {
+  unsigned int      attrib;
+  MSVCRT___time64_t time_create;
+  MSVCRT___time64_t time_access;
+  MSVCRT___time64_t time_write;
+  __int64 DECLSPEC_ALIGN(8) size;
+  char              name[260];
+};
+
+struct MSVCRT__wfinddata32_t {
+  unsigned int      attrib;
+  MSVCRT___time32_t time_create;
+  MSVCRT___time32_t time_access;
+  MSVCRT___time32_t time_write;
+  MSVCRT__fsize_t   size;
+  MSVCRT_wchar_t    name[260];
+};
+
+struct MSVCRT__wfinddata32i64_t {
+  unsigned int      attrib;
+  MSVCRT___time32_t time_create;
+  MSVCRT___time32_t time_access;
+  MSVCRT___time32_t time_write;
+  __int64 DECLSPEC_ALIGN(8) size;
+  MSVCRT_wchar_t    name[260];
+};
+
+struct MSVCRT__wfinddata64i32_t {
+  unsigned int      attrib;
+  MSVCRT___time64_t time_create;
+  MSVCRT___time64_t time_access;
+  MSVCRT___time64_t time_write;
+  MSVCRT__fsize_t   size;
+  MSVCRT_wchar_t    name[260];
+};
+
+struct MSVCRT__wfinddata64_t {
+  unsigned int      attrib;
+  MSVCRT___time64_t time_create;
+  MSVCRT___time64_t time_access;
+  MSVCRT___time64_t time_write;
+  __int64 DECLSPEC_ALIGN(8) size;
+  MSVCRT_wchar_t    name[260];
+};
+
+struct MSVCRT___utimbuf32
+{
+    MSVCRT___time32_t actime;
+    MSVCRT___time32_t modtime;
+};
+
+struct MSVCRT___utimbuf64
+{
+    MSVCRT___time64_t actime;
+    MSVCRT___time64_t modtime;
+};
+
+/* for FreeBSD */
+#undef st_atime
+#undef st_ctime
+#undef st_mtime
+
+struct MSVCRT__stat32 {
+  MSVCRT__dev_t     st_dev;
+  MSVCRT__ino_t     st_ino;
+  unsigned short    st_mode;
+  short             st_nlink;
+  short             st_uid;
+  short             st_gid;
+  MSVCRT__dev_t     st_rdev;
+  MSVCRT__off_t     st_size;
+  MSVCRT___time32_t st_atime;
+  MSVCRT___time32_t st_mtime;
+  MSVCRT___time32_t st_ctime;
+};
+
+struct MSVCRT__stat32i64 {
+  MSVCRT__dev_t     st_dev;
+  MSVCRT__ino_t     st_ino;
+  unsigned short    st_mode;
+  short             st_nlink;
+  short             st_uid;
+  short             st_gid;
+  MSVCRT__dev_t     st_rdev;
+  __int64 DECLSPEC_ALIGN(8) st_size;
+  MSVCRT___time32_t st_atime;
+  MSVCRT___time32_t st_mtime;
+  MSVCRT___time32_t st_ctime;
+};
+
+struct MSVCRT__stat64i32 {
+  MSVCRT__dev_t     st_dev;
+  MSVCRT__ino_t     st_ino;
+  unsigned short    st_mode;
+  short             st_nlink;
+  short             st_uid;
+  short             st_gid;
+  MSVCRT__dev_t     st_rdev;
+  MSVCRT__off_t     st_size;
+  MSVCRT___time64_t st_atime;
+  MSVCRT___time64_t st_mtime;
+  MSVCRT___time64_t st_ctime;
+};
+
+struct MSVCRT__stat64 {
+  MSVCRT__dev_t     st_dev;
+  MSVCRT__ino_t     st_ino;
+  unsigned short    st_mode;
+  short             st_nlink;
+  short             st_uid;
+  short             st_gid;
+  MSVCRT__dev_t     st_rdev;
+  __int64 DECLSPEC_ALIGN(8) st_size;
+  MSVCRT___time64_t st_atime;
+  MSVCRT___time64_t st_mtime;
+  MSVCRT___time64_t st_ctime;
+};
+
+#ifdef _WIN64
+#define MSVCRT__finddata_t     MSVCRT__finddata64i32_t
+#define MSVCRT__finddatai64_t  MSVCRT__finddata64_t
+#define MSVCRT__wfinddata_t    MSVCRT__wfinddata64i32_t
+#define MSVCRT__wfinddatai64_t MSVCRT__wfinddata64_t
+#define MSVCRT__stat           MSVCRT__stat64i32
+#define MSVCRT__stati64        MSVCRT__stat64
+#else
+#define MSVCRT__finddata_t     MSVCRT__finddata32_t
+#define MSVCRT__finddatai64_t  MSVCRT__finddata32i64_t
+#define MSVCRT__wfinddata_t    MSVCRT__wfinddata32_t
+#define MSVCRT__wfinddatai64_t MSVCRT__wfinddata32i64_t
+#define MSVCRT__stat           MSVCRT__stat32
+#define MSVCRT__stati64        MSVCRT__stat32i64
+#endif
+
+#define MSVCRT_WEOF (MSVCRT_wint_t)(0xFFFF)
+#define MSVCRT_EOF       (-1)
+#define MSVCRT_TMP_MAX   0x7fff
+#define MSVCRT_RAND_MAX  0x7fff
+#define MSVCRT_BUFSIZ    512
+
+#define MSVCRT_STDIN_FILENO  0
+#define MSVCRT_STDOUT_FILENO 1
+#define MSVCRT_STDERR_FILENO 2
+
+/* more file._flag flags, but these conflict with Unix */
+#define MSVCRT__IOFBF    0x0000
+#define MSVCRT__IONBF    0x0004
+#define MSVCRT__IOLBF    0x0040
+
+#define MSVCRT_FILENAME_MAX 260
+#define MSVCRT_DRIVE_MAX    3
+#define MSVCRT_FNAME_MAX    256
+#define MSVCRT_DIR_MAX      256
+#define MSVCRT_EXT_MAX      256
+#define MSVCRT_PATH_MAX     260
+#define MSVCRT_stdin       (MSVCRT__iob+MSVCRT_STDIN_FILENO)
+#define MSVCRT_stdout      (MSVCRT__iob+MSVCRT_STDOUT_FILENO)
+#define MSVCRT_stderr      (MSVCRT__iob+MSVCRT_STDERR_FILENO)
+
+#define MSVCRT__P_WAIT    0
+#define MSVCRT__P_NOWAIT  1
+#define MSVCRT__P_OVERLAY 2
+#define MSVCRT__P_NOWAITO 3
+#define MSVCRT__P_DETACH  4
+
+#define MSVCRT_EPERM   1
+#define MSVCRT_ENOENT  2
+#define MSVCRT_ESRCH   3
+#define MSVCRT_EINTR   4
+#define MSVCRT_EIO     5
+#define MSVCRT_ENXIO   6
+#define MSVCRT_E2BIG   7
+#define MSVCRT_ENOEXEC 8
+#define MSVCRT_EBADF   9
+#define MSVCRT_ECHILD  10
+#define MSVCRT_EAGAIN  11
+#define MSVCRT_ENOMEM  12
+#define MSVCRT_EACCES  13
+#define MSVCRT_EFAULT  14
+#define MSVCRT_EBUSY   16
+#define MSVCRT_EEXIST  17
+#define MSVCRT_EXDEV   18
+#define MSVCRT_ENODEV  19
+#define MSVCRT_ENOTDIR 20
+#define MSVCRT_EISDIR  21
+#define MSVCRT_EINVAL  22
+#define MSVCRT_ENFILE  23
+#define MSVCRT_EMFILE  24
+#define MSVCRT_ENOTTY  25
+#define MSVCRT_EFBIG   27
+#define MSVCRT_ENOSPC  28
+#define MSVCRT_ESPIPE  29
+#define MSVCRT_EROFS   30
+#define MSVCRT_EMLINK  31
+#define MSVCRT_EPIPE   32
+#define MSVCRT_EDOM    33
+#define MSVCRT_ERANGE  34
+#define MSVCRT_EDEADLK 36
+#define MSVCRT_EDEADLOCK MSVCRT_EDEADLK
+#define MSVCRT_ENAMETOOLONG 38
+#define MSVCRT_ENOLCK  39
+#define MSVCRT_ENOSYS  40
+#define MSVCRT_ENOTEMPTY 41
+#define MSVCRT_EILSEQ    42
+#define MSVCRT_STRUNCATE 80
+
+#define MSVCRT_LC_ALL          0
+#define MSVCRT_LC_COLLATE      1
+#define MSVCRT_LC_CTYPE        2
+#define MSVCRT_LC_MONETARY     3
+#define MSVCRT_LC_NUMERIC      4
+#define MSVCRT_LC_TIME         5
+#define MSVCRT_LC_MIN          MSVCRT_LC_ALL
+#define MSVCRT_LC_MAX          MSVCRT_LC_TIME
+
+#define MSVCRT__HEAPEMPTY      -1
+#define MSVCRT__HEAPOK         -2
+#define MSVCRT__HEAPBADBEGIN   -3
+#define MSVCRT__HEAPBADNODE    -4
+#define MSVCRT__HEAPEND        -5
+#define MSVCRT__HEAPBADPTR     -6
+
+#define MSVCRT__FREEENTRY      0
+#define MSVCRT__USEDENTRY      1
+
+#define MSVCRT__OUT_TO_DEFAULT 0
+#define MSVCRT__OUT_TO_STDERR  1
+#define MSVCRT__OUT_TO_MSGBOX  2
+#define MSVCRT__REPORT_ERRMODE 3
+
+/* ASCII char classification table - binary compatible */
+#define MSVCRT__UPPER    0x0001  /* C1_UPPER */
+#define MSVCRT__LOWER    0x0002  /* C1_LOWER */
+#define MSVCRT__DIGIT    0x0004  /* C1_DIGIT */
+#define MSVCRT__SPACE    0x0008  /* C1_SPACE */
+#define MSVCRT__PUNCT    0x0010  /* C1_PUNCT */
+#define MSVCRT__CONTROL  0x0020  /* C1_CNTRL */
+#define MSVCRT__BLANK    0x0040  /* C1_BLANK */
+#define MSVCRT__HEX      0x0080  /* C1_XDIGIT */
+#define MSVCRT__LEADBYTE 0x8000
+#define MSVCRT__ALPHA   (0x0100|MSVCRT__UPPER|MSVCRT__LOWER)  /* (C1_ALPHA|_UPPER|_LOWER) */
+
+#define MSVCRT__IOREAD   0x0001
+#define MSVCRT__IOWRT    0x0002
+#define MSVCRT__IOMYBUF  0x0008
+#define MSVCRT__IOEOF    0x0010
+#define MSVCRT__IOERR    0x0020
+#define MSVCRT__IOSTRG   0x0040
+#define MSVCRT__IORW     0x0080
+
+#define MSVCRT__S_IEXEC  0x0040
+#define MSVCRT__S_IWRITE 0x0080
+#define MSVCRT__S_IREAD  0x0100
+#define MSVCRT__S_IFIFO  0x1000
+#define MSVCRT__S_IFCHR  0x2000
+#define MSVCRT__S_IFDIR  0x4000
+#define MSVCRT__S_IFREG  0x8000
+#define MSVCRT__S_IFMT   0xF000
+
+#define MSVCRT__LK_UNLCK  0
+#define MSVCRT__LK_LOCK   1
+#define MSVCRT__LK_NBLCK  2
+#define MSVCRT__LK_RLCK   3
+#define MSVCRT__LK_NBRLCK 4
+
+#define        MSVCRT__SH_COMPAT       0x00    /* Compatibility */
+#define        MSVCRT__SH_DENYRW       0x10    /* Deny read/write */
+#define        MSVCRT__SH_DENYWR       0x20    /* Deny write */
+#define        MSVCRT__SH_DENYRD       0x30    /* Deny read */
+#define        MSVCRT__SH_DENYNO       0x40    /* Deny nothing */
+
+#define MSVCRT__O_RDONLY        0
+#define MSVCRT__O_WRONLY        1
+#define MSVCRT__O_RDWR          2
+#define MSVCRT__O_ACCMODE       (MSVCRT__O_RDONLY|MSVCRT__O_WRONLY|MSVCRT__O_RDWR)
+#define MSVCRT__O_APPEND        0x0008
+#define MSVCRT__O_RANDOM        0x0010
+#define MSVCRT__O_SEQUENTIAL    0x0020
+#define MSVCRT__O_TEMPORARY     0x0040
+#define MSVCRT__O_NOINHERIT     0x0080
+#define MSVCRT__O_CREAT         0x0100
+#define MSVCRT__O_TRUNC         0x0200
+#define MSVCRT__O_EXCL          0x0400
+#define MSVCRT__O_SHORT_LIVED   0x1000
+#define MSVCRT__O_TEXT          0x4000
+#define MSVCRT__O_BINARY        0x8000
+#define MSVCRT__O_RAW           MSVCRT__O_BINARY
+
+/* _statusfp bit flags */
+#define MSVCRT__SW_INEXACT      0x00000001 /* inexact (precision) */
+#define MSVCRT__SW_UNDERFLOW    0x00000002 /* underflow */
+#define MSVCRT__SW_OVERFLOW     0x00000004 /* overflow */
+#define MSVCRT__SW_ZERODIVIDE   0x00000008 /* zero divide */
+#define MSVCRT__SW_INVALID      0x00000010 /* invalid */
+
+#define MSVCRT__SW_UNEMULATED     0x00000040  /* unemulated instruction */
+#define MSVCRT__SW_SQRTNEG        0x00000080  /* square root of a neg number */
+#define MSVCRT__SW_STACKOVERFLOW  0x00000200  /* FP stack overflow */
+#define MSVCRT__SW_STACKUNDERFLOW 0x00000400  /* FP stack underflow */
+
+#define MSVCRT__SW_DENORMAL     0x00080000 /* denormal status bit */
+
+/* fpclass constants */
+#define MSVCRT__FPCLASS_SNAN 0x0001  /* Signaling "Not a Number" */
+#define MSVCRT__FPCLASS_QNAN 0x0002  /* Quiet "Not a Number" */
+#define MSVCRT__FPCLASS_NINF 0x0004  /* Negative Infinity */
+#define MSVCRT__FPCLASS_NN   0x0008  /* Negative Normal */
+#define MSVCRT__FPCLASS_ND   0x0010  /* Negative Denormal */
+#define MSVCRT__FPCLASS_NZ   0x0020  /* Negative Zero */
+#define MSVCRT__FPCLASS_PZ   0x0040  /* Positive Zero */
+#define MSVCRT__FPCLASS_PD   0x0080  /* Positive Denormal */
+#define MSVCRT__FPCLASS_PN   0x0100  /* Positive Normal */
+#define MSVCRT__FPCLASS_PINF 0x0200  /* Positive Infinity */
+
+#define MSVCRT__MCW_EM        0x0008001f
+#define MSVCRT__MCW_IC        0x00040000
+#define MSVCRT__MCW_RC        0x00000300
+#define MSVCRT__MCW_PC        0x00030000
+#define MSVCRT__MCW_DN        0x03000000
+
+#define MSVCRT__EM_INVALID    0x00000010
+#define MSVCRT__EM_DENORMAL   0x00080000
+#define MSVCRT__EM_ZERODIVIDE 0x00000008
+#define MSVCRT__EM_OVERFLOW   0x00000004
+#define MSVCRT__EM_UNDERFLOW  0x00000002
+#define MSVCRT__EM_INEXACT    0x00000001
+#define MSVCRT__IC_AFFINE     0x00040000
+#define MSVCRT__IC_PROJECTIVE 0x00000000
+#define MSVCRT__RC_CHOP       0x00000300
+#define MSVCRT__RC_UP         0x00000200
+#define MSVCRT__RC_DOWN       0x00000100
+#define MSVCRT__RC_NEAR       0x00000000
+#define MSVCRT__PC_24         0x00020000
+#define MSVCRT__PC_53         0x00010000
+#define MSVCRT__PC_64         0x00000000
+#define MSVCRT__DN_SAVE       0x00000000
+#define MSVCRT__DN_FLUSH      0x01000000
+#define MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS 0x02000000
+#define MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS 0x03000000
+#define MSVCRT__EM_AMBIGUOUS  0x80000000
+
+#define MSVCRT_CLOCKS_PER_SEC 1000
+
+/* signals */
+#define MSVCRT_SIGINT   2
+#define MSVCRT_SIGILL   4
+#define MSVCRT_SIGFPE   8
+#define MSVCRT_SIGSEGV  11
+#define MSVCRT_SIGTERM  15
+#define MSVCRT_SIGBREAK 21
+#define MSVCRT_SIGABRT  22
+#define MSVCRT_NSIG     (MSVCRT_SIGABRT + 1)
+
+typedef void (__cdecl *MSVCRT___sighandler_t)(int);
+
+#define MSVCRT_SIG_DFL ((MSVCRT___sighandler_t)0)
+#define MSVCRT_SIG_IGN ((MSVCRT___sighandler_t)1)
+#define MSVCRT_SIG_ERR ((MSVCRT___sighandler_t)-1)
+
+#define MSVCRT__FPE_INVALID            0x81
+#define MSVCRT__FPE_DENORMAL           0x82
+#define MSVCRT__FPE_ZERODIVIDE         0x83
+#define MSVCRT__FPE_OVERFLOW           0x84
+#define MSVCRT__FPE_UNDERFLOW          0x85
+#define MSVCRT__FPE_INEXACT            0x86
+#define MSVCRT__FPE_UNEMULATED         0x87
+#define MSVCRT__FPE_SQRTNEG            0x88
+#define MSVCRT__FPE_STACKOVERFLOW      0x8a
+#define MSVCRT__FPE_STACKUNDERFLOW     0x8b
+#define MSVCRT__FPE_EXPLICITGEN        0x8c
+
+#define _MS     0x01
+#define _MP     0x02
+#define _M1     0x04
+#define _M2     0x08
+
+#define _SBUP   0x10
+#define _SBLOW  0x20
+
+#define _MBC_SINGLE     0
+#define _MBC_LEAD       1
+#define _MBC_TRAIL      2
+#define _MBC_ILLEGAL    -1
+
+#define _MB_CP_SBCS     0
+#define _MB_CP_OEM      -2
+#define _MB_CP_ANSI     -3
+#define _MB_CP_LOCALE   -4
+
+#define MSVCRT__TRUNCATE ((MSVCRT_size_t)-1)
+
+#define _MAX__TIME64_T    (((MSVCRT___time64_t)0x00000007 << 32) | 0x93406FFF)
+
+/* _set_abort_behavior codes */
+#define MSVCRT__WRITE_ABORT_MSG    1
+#define MSVCRT__CALL_REPORTFAULT   2
+
+/* _get_output_format return code */
+#define MSVCRT__TWO_DIGIT_EXPONENT 0x1
+
+void  __cdecl    MSVCRT_free(void*);
+void* __cdecl    MSVCRT_malloc(MSVCRT_size_t);
+void* __cdecl    MSVCRT_calloc(MSVCRT_size_t,MSVCRT_size_t);
+void* __cdecl    MSVCRT_realloc(void*,MSVCRT_size_t);
+
+int __cdecl      MSVCRT_iswalpha(MSVCRT_wint_t);
+int __cdecl      MSVCRT_iswspace(MSVCRT_wint_t);
+int __cdecl      MSVCRT_iswdigit(MSVCRT_wint_t);
+int __cdecl      MSVCRT_isleadbyte(int);
+int __cdecl      MSVCRT__isleadbyte_l(int, MSVCRT__locale_t);
+
+void __cdecl     MSVCRT__lock_file(MSVCRT_FILE*);
+void __cdecl     MSVCRT__unlock_file(MSVCRT_FILE*);
+int __cdecl      MSVCRT_fgetc(MSVCRT_FILE*);
+int __cdecl      MSVCRT_ungetc(int,MSVCRT_FILE*);
+MSVCRT_wint_t __cdecl MSVCRT_fgetwc(MSVCRT_FILE*);
+MSVCRT_wint_t __cdecl MSVCRT_ungetwc(MSVCRT_wint_t,MSVCRT_FILE*);
+void __cdecl     MSVCRT__exit(int);
+void __cdecl     MSVCRT_abort(void);
+MSVCRT_ulong* __cdecl MSVCRT___doserrno(void);
+int* __cdecl     MSVCRT__errno(void);
+char* __cdecl    MSVCRT_getenv(const char*);
+int __cdecl      MSVCRT_fclose(MSVCRT_FILE*);
+void __cdecl     MSVCRT_terminate(void);
+MSVCRT_FILE* __cdecl MSVCRT__iob_func(void);
+MSVCRT_clock_t __cdecl MSVCRT_clock(void);
+MSVCRT___time32_t __cdecl MSVCRT__time32(MSVCRT___time32_t*);
+MSVCRT___time64_t __cdecl MSVCRT__time64(MSVCRT___time64_t*);
+MSVCRT_FILE*   __cdecl MSVCRT__fdopen(int, const char *);
+MSVCRT_FILE*   __cdecl MSVCRT__wfdopen(int, const MSVCRT_wchar_t *);
+int            __cdecl MSVCRT_vsnprintf(char *str, MSVCRT_size_t len, const char *format, __ms_va_list valist);
+int            __cdecl MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
+                                       const MSVCRT_wchar_t *format, __ms_va_list valist );
+int            __cdecl MSVCRT__snwprintf(MSVCRT_wchar_t*, unsigned int, const MSVCRT_wchar_t*, ...);
+int            __cdecl MSVCRT_sprintf(char*,const char*,...);
+int            __cdecl MSVCRT__scprintf(const char*,...);
+int            __cdecl MSVCRT_raise(int sig);
+
+#define MSVCRT__ENABLE_PER_THREAD_LOCALE 1
+#define MSVCRT__DISABLE_PER_THREAD_LOCALE 2
+
+extern MSVCRT__locale_t MSVCRT_locale;
+MSVCRT_pthreadlocinfo get_locinfo(void);
+MSVCRT_pthreadmbcinfo get_mbcinfo(void);
+void __cdecl MSVCRT__free_locale(MSVCRT__locale_t);
+void free_locinfo(MSVCRT_pthreadlocinfo);
+void free_mbcinfo(MSVCRT_pthreadmbcinfo);
+int _setmbcp_l(int, LCID, MSVCRT_pthreadmbcinfo);
+
+#ifndef __WINE_MSVCRT_TEST
+int            __cdecl MSVCRT__write(int,const void*,unsigned int);
+int            __cdecl _getch(void);
+int            __cdecl _ismbblead(unsigned int);
+int            __cdecl _ismbstrail(const unsigned char* start, const unsigned char* str);
+MSVCRT_size_t  __cdecl MSVCRT_mbstowcs(MSVCRT_wchar_t*,const char*,MSVCRT_size_t);
+MSVCRT_intptr_t __cdecl MSVCRT__spawnve(int,const char*,const char* const *,const char* const *);
+MSVCRT_intptr_t __cdecl MSVRT__spawnvpe(int,const char*,const char* const *,const char* const *);
+MSVCRT_intptr_t __cdecl MSVCRT__wspawnve(int,const MSVCRT_wchar_t*,const MSVCRT_wchar_t* const *,const MSVCRT_wchar_t* const *);
+MSVCRT_intptr_t __cdecl MSVCRT__wspawnvpe(int,const MSVCRT_wchar_t*,const MSVCRT_wchar_t* const *,const MSVCRT_wchar_t* const *);
+void __cdecl     MSVCRT__searchenv(const char*,const char*,char*);
+int __cdecl      MSVCRT__getdrive(void);
+char* __cdecl    MSVCRT__strdup(const char*);
+char* __cdecl    MSVCRT__strnset(char*,int,MSVCRT_size_t);
+char* __cdecl    _strset(char*,int);
+int __cdecl      _ungetch(int);
+int __cdecl      _cputs(const char*);
+int __cdecl      _cprintf(const char*,...);
+int __cdecl      _cwprintf(const MSVCRT_wchar_t*,...);
+char*** __cdecl  MSVCRT___p__environ(void);
+int*    __cdecl  __p___mb_cur_max(void);
+unsigned int*  __cdecl __p__fmode(void);
+MSVCRT_wchar_t* __cdecl MSVCRT__wcsdup(const MSVCRT_wchar_t*);
+MSVCRT_wchar_t*** __cdecl MSVCRT___p__wenviron(void);
+char*   __cdecl MSVCRT__strdate(char* date);
+char*   __cdecl MSVCRT__strtime(char* date);
+int     __cdecl _setmbcp(int);
+int     __cdecl MSVCRT__close(int);
+int     __cdecl MSVCRT__dup(int);
+int     __cdecl MSVCRT__dup2(int, int);
+int     __cdecl MSVCRT__pipe(int *, unsigned int, int);
+MSVCRT_wchar_t* __cdecl MSVCRT__wgetenv(const MSVCRT_wchar_t*);
+void __cdecl    MSVCRT__wsearchenv(const MSVCRT_wchar_t*, const MSVCRT_wchar_t*, MSVCRT_wchar_t*);
+MSVCRT_intptr_t __cdecl MSVCRT__spawnvpe(int, const char*, const char* const*, const char* const*);
+void __cdecl MSVCRT__invalid_parameter(const MSVCRT_wchar_t *expr, const MSVCRT_wchar_t *func,
+                                       const MSVCRT_wchar_t *file, unsigned int line, MSVCRT_uintptr_t arg);
+int __cdecl      MSVCRT__toupper_l(int,MSVCRT__locale_t);
+int __cdecl      MSVCRT__tolower_l(int,MSVCRT__locale_t);
+
+/* Maybe one day we'll enable the invalid parameter handlers with the full set of information (msvcrXXd)
+ *      #define MSVCRT_INVALID_PMT(x) MSVCRT_call_invalid_parameter_handler(x, __FUNCTION__, __FILE__, __LINE__, 0)
+ *      #define MSVCRT_CHECK_PMT(x)   ((x) ? TRUE : MSVCRT_INVALID_PMT(#x),FALSE)
+ * Until this is done, just keep the same semantics for CHECK_PMT(), but without generating / sending
+ * any information
+ * NB : MSVCRT_call_invalid_parameter_handler is a wrapper around MSVCRT__invalid_parameter in order
+ * to do the Ansi to Unicode transformation
+ */
+#define MSVCRT_INVALID_PMT(x) MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0)
+#define MSVCRT_CHECK_PMT(x)   ((x) || (MSVCRT_INVALID_PMT(0),FALSE))
+#endif
+
+#define MSVCRT__ARGMAX 100
+typedef int (*puts_clbk_a)(void*, int, const char*);
+typedef int (*puts_clbk_w)(void*, int, const MSVCRT_wchar_t*);
+typedef union _printf_arg
+{
+    void *get_ptr;
+    int get_int;
+    LONGLONG get_longlong;
+    double get_double;
+} printf_arg;
+typedef printf_arg (*args_clbk)(void*, int, int, __ms_va_list*);
+int pf_printf_a(puts_clbk_a, void*, const char*, MSVCRT__locale_t,
+        BOOL, BOOL, args_clbk, void*, __ms_va_list*);
+int pf_printf_w(puts_clbk_w, void*, const MSVCRT_wchar_t*, MSVCRT__locale_t,
+        BOOL, BOOL, args_clbk, void*, __ms_va_list*);
+printf_arg arg_clbk_valist(void*, int, int, __ms_va_list*);
+
+#define MSVCRT__OVERFLOW  3
+#define MSVCRT__UNDERFLOW 4
+
+typedef struct
+{
+    float f;
+} MSVCRT__CRT_FLOAT;
+
+#endif /* __WINE_MSVCRT_H */
index 19e21f9..978b512 100644 (file)
@@ -26,6 +26,7 @@
 #define _CRT_NON_CONFORMING_SWPRINTFS
  
 #include <stdio.h>
+#include <errno.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -38,6 +39,22 @@ static int (__cdecl *p__vscwprintf)(const wchar_t *format, __ms_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);
+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,
+                                int ndigits, int *decpt, int *sign);
+static unsigned int (__cdecl *p__get_output_format)(void);
+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__vswprintf_l)(wchar_t *str, const wchar_t *format,
+                                     void *locale, __ms_va_list valist);
+static int (__cdecl *p__vswprintf_c)(wchar_t *str, size_t size, const wchar_t *format,
+                                     __ms_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);
+static int (__cdecl *p__vswprintf_p_l)(wchar_t *str, size_t size, const wchar_t *format,
+                                       void *locale, __ms_va_list valist);
 
 static void init( void )
 {
@@ -46,6 +63,16 @@ static void init( void )
     p__vscprintf = (void *)GetProcAddress(hmod, "_vscprintf");
     p__vscwprintf = (void *)GetProcAddress(hmod, "_vscwprintf");
     p__vsnwprintf_s = (void *)GetProcAddress(hmod, "_vsnwprintf_s");
+    p__ecvt_s = (void *)GetProcAddress(hmod, "_ecvt_s");
+    p__fcvt_s = (void *)GetProcAddress(hmod, "_fcvt_s");
+    p__get_output_format = (void *)GetProcAddress(hmod, "_get_output_format");
+    p__vsprintf_p = (void*)GetProcAddress(hmod, "_vsprintf_p");
+    p_vswprintf = (void*)GetProcAddress(hmod, "vswprintf");
+    p__vswprintf = (void*)GetProcAddress(hmod, "_vswprintf");
+    p__vswprintf_l = (void*)GetProcAddress(hmod, "_vswprintf_l");
+    p__vswprintf_c = (void*)GetProcAddress(hmod, "_vswprintf_c");
+    p__vswprintf_c_l = (void*)GetProcAddress(hmod, "_vswprintf_c_l");
+    p__vswprintf_p_l = (void*)GetProcAddress(hmod, "_vswprintf_p_l");
 }
 
 static void test_sprintf( void )
@@ -616,6 +643,41 @@ static void test_snprintf (void)
     };
 }
 
+static void test_fprintf(void)
+{
+    static char file_name[] = "fprintf.tst";
+    FILE *fp = fopen(file_name, "wb");
+    char buf[1024];
+    int ret;
+
+    ret = fprintf(fp, "simple test\n");
+    ok(ret == 12, "ret = %d\n", ret);
+    ret = ftell(fp);
+    ok(ret == 12, "ftell returned %d\n", ret);
+
+    ret = fprintf(fp, "contains%cnull\n", '\0');
+    ok(ret == 14, "ret = %d\n", ret);
+    ret = ftell(fp);
+    ok(ret == 26, "ftell returned %d\n", ret);
+
+    fclose(fp);
+
+    fp = fopen(file_name, "rb");
+    ret = fscanf(fp, "%[^\n] ", buf);
+    ok(ret == 1, "ret = %d\n", ret);
+    ret = ftell(fp);
+    ok(ret == 12, "ftell returned %d\n", ret);
+    ok(!strcmp(buf, "simple test"), "buf = %s\n", buf);
+
+    fgets(buf, sizeof(buf), fp);
+    ret = ftell(fp);
+    ok(ret == 26, "ret = %d\n", ret);
+    ok(!memcmp(buf, "contains\0null\n", 14), "buf = %s\n", buf);
+
+    fclose(fp);
+    unlink(file_name);
+}
+
 static void test_fcvt(void)
 {
     char *str;
@@ -713,6 +775,8 @@ static void test_fcvt(void)
     ok( 0 == sign, "sign wrong\n");
 }
 
+/* Don't test nrdigits < 0, msvcrt on Win9x and NT4 will corrupt memory by
+ * writing outside allocated memory */
 static struct {
     double value;
     int nrdigits;
@@ -725,7 +789,6 @@ static struct {
     {          45.0,   2,        "45",           "4500",          2,      2,      0 },
     /* Numbers less than 1.0 with different precisions */
     {        0.0001,   1,         "1",               "",         -3,     -3,     0 },
-    {        0.0001, -10,          "",               "",         -3,     -3,     0 },
     {        0.0001,  10,"1000000000",        "1000000",         -3,     -3,     0 },
     /* Basic sign test */
     {     -111.0001,   5,     "11100",       "11100010",          3,      3,     1 },
@@ -753,7 +816,7 @@ static struct {
     {           0.4,   0,          "",               "",          0,      0,     0 },
     {          0.49,   0,          "",               "",          0,      0,     0 },
     {          0.51,   0,          "",              "1",          1,      1,     0 },
-    /* ask ridiculous amunt of precision, ruin formatting this table */
+    /* ask for ridiculous precision, ruin formatting this table */
     {           1.0,  30, "100000000000000000000000000000",
                       "1000000000000000000000000000000",          1,      1,      0},
     {           123456789012345678901.0,  30, "123456789012345680000000000000",
@@ -765,7 +828,8 @@ static struct {
 static void test_xcvt(void)
 {
     char *str;
-    int i, decpt, sign;
+    int i, decpt, sign, err;
+
     for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
         decpt = sign = 100;
         str = _ecvt( test_cvt_testcases[i].value,
@@ -778,6 +842,9 @@ static void test_xcvt(void)
         ok( decpt == test_cvt_testcases[i].expdecpt_e,
                 "_ecvt() decimal point wrong, got %d expected %d\n", decpt,
                 test_cvt_testcases[i].expdecpt_e);
+        ok( sign == test_cvt_testcases[i].expsign,
+                "_ecvt() sign wrong, got %d expected %d\n", sign,
+                test_cvt_testcases[i].expsign);
     }
     for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
         decpt = sign = 100;
@@ -792,9 +859,76 @@ static void test_xcvt(void)
                 "_fcvt() decimal point wrong, got %d expected %d\n", decpt,
                 test_cvt_testcases[i].expdecpt_f);
         ok( sign == test_cvt_testcases[i].expsign,
-                "_ecvt() sign wrong, got %d expected %d\n", sign,
+                "_fcvt() sign wrong, got %d expected %d\n", sign,
                 test_cvt_testcases[i].expsign);
     }
+
+    if (p__ecvt_s)
+    {
+        str = malloc(1024);
+        for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
+            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,
+                  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,
+                    test_cvt_testcases[i].expdecpt_e);
+            ok( sign == test_cvt_testcases[i].expsign,
+                    "_ecvt_s() sign wrong, got %d expected %d\n", sign,
+                    test_cvt_testcases[i].expsign);
+        }
+        free(str);
+    }
+    else
+        win_skip("_ecvt_s not available\n");
+
+    if (p__fcvt_s)
+    {
+        int i;
+
+        str = malloc(1024);
+
+        /* invalid arguments */
+        err = p__fcvt_s(NULL, 0, 0.0, 0, &i, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        err = p__fcvt_s(str, 0, 0.0, 0, &i, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        str[0] = ' ';
+        str[1] = 0;
+        err = p__fcvt_s(str, -1, 0.0, 0, &i, &i);
+        ok(err == 0, "got %d, expected 0\n", err);
+        ok(str[0] == 0, "got %c, expected 0\n", str[0]);
+        ok(str[1] == 0, "got %c, expected 0\n", str[1]);
+
+        err = p__fcvt_s(str, 1, 0.0, 0, NULL, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        err = p__fcvt_s(str, 1, 0.0, 0, &i, NULL);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        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,
+                  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,
+                    test_cvt_testcases[i].expdecpt_f);
+            ok( sign == test_cvt_testcases[i].expsign,
+                    "_fcvt_s() sign wrong, got %d expected %d\n", sign,
+                    test_cvt_testcases[i].expsign);
+        }
+        free(str);
+    }
+    else
+        win_skip("_fcvt_s not available\n");
 }
 
 static int __cdecl _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...)
@@ -825,6 +959,112 @@ static void test_vsnwprintf(void)
     ok( !strcmp(buf, "onetwothree"), "got %s expected 'onetwothree'\n", buf );
 }
 
+static int __cdecl vswprintf_wrapper(wchar_t *str, const wchar_t *format, ...)
+{
+    int ret;
+    __ms_va_list valist;
+    __ms_va_start(valist, format);
+    ret = p_vswprintf(str, format, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static int __cdecl _vswprintf_wrapper(wchar_t *str, const wchar_t *format, ...)
+{
+    int ret;
+    __ms_va_list valist;
+    __ms_va_start(valist, format);
+    ret = p__vswprintf(str, format, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static int __cdecl _vswprintf_l_wrapper(wchar_t *str, const wchar_t *format, void *locale, ...)
+{
+    int ret;
+    __ms_va_list valist;
+    __ms_va_start(valist, locale);
+    ret = p__vswprintf_l(str, format, locale, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static int __cdecl _vswprintf_c_wrapper(wchar_t *str, size_t size, const wchar_t *format, ...)
+{
+    int ret;
+    __ms_va_list valist;
+    __ms_va_start(valist, format);
+    ret = p__vswprintf_c(str, size, format, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static int __cdecl _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);
+    ret = p__vswprintf_c_l(str, size, format, locale, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static int __cdecl _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);
+    ret = p__vswprintf_p_l(str, size, format, locale, valist);
+    __ms_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
+            || !p__vswprintf_c_l || !p__vswprintf_p_l)
+    {
+        win_skip("_vswprintf or vswprintf not available\n");
+        return;
+    }
+
+    ret = vswprintf_wrapper(buf, format, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+
+    memset(buf, 0, sizeof(buf));
+    ret = _vswprintf_wrapper(buf, format, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+
+    memset(buf, 0, sizeof(buf));
+    ret = _vswprintf_l_wrapper(buf, format, NULL, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+
+    memset(buf, 0, sizeof(buf));
+    ret = _vswprintf_c_wrapper(buf, 20, format, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+
+    memset(buf, 0, sizeof(buf));
+    ret = _vswprintf_c_l_wrapper(buf, 20, format, NULL, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+
+    memset(buf, 0, sizeof(buf));
+    ret = _vswprintf_p_l_wrapper(buf, 20, format, NULL, number, 123);
+    ok(ret == 10, "got %d, expected 10\n", ret);
+    ok(!memcmp(buf, out, sizeof(out)), "buf = %s\n", wine_dbgstr_w(buf));
+}
+
 static int __cdecl _vscprintf_wrapper(const char *format, ...)
 {
     int ret;
@@ -934,6 +1174,61 @@ static void test_vsnwprintf_s(void)
     ok( !wcscmp(out1, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
 }
 
+static int __cdecl _vsprintf_p_wrapper(char *str, size_t sizeOfBuffer,
+                                 const char *format, ...)
+{
+    int ret;
+    __ms_va_list valist;
+    __ms_va_start(valist, format);
+    ret = p__vsprintf_p(str, sizeOfBuffer, format, valist);
+    __ms_va_end(valist);
+    return ret;
+}
+
+static void test_vsprintf_p(void)
+{
+    char buf[1024];
+    int ret;
+
+    if(!p__vsprintf_p) {
+        win_skip("vsprintf_p not available\n");
+        return;
+    }
+
+    ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%s %d", "test", 1234);
+    ok(ret == 9, "ret = %d\n", ret);
+    ok(!memcmp(buf, "test 1234", 10), "buf = %s\n", buf);
+
+    ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%1$d", 1234, "additional param");
+    ok(ret == 4, "ret = %d\n", ret);
+    ok(!memcmp(buf, "1234", 5), "buf = %s\n", buf);
+
+    ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%2$s %1$d", 1234, "test");
+    ok(ret == 9, "ret = %d\n", ret);
+    ok(!memcmp(buf, "test 1234", 10), "buf = %s\n", buf);
+
+    ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%2$*3$s %2$.*1$s", 2, "test", 3);
+    ok(ret == 7, "ret = %d\n", ret);
+    ok(!memcmp(buf, "test te", 8), "buf = %s\n", buf);
+
+    /* Following test invokes invalid parameter handler */
+    /* ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%d %1$d", 1234); */
+}
+
+static void test__get_output_format(void)
+{
+    unsigned int ret;
+
+    if (!p__get_output_format)
+    {
+        win_skip("_get_output_format not available\n");
+        return;
+    }
+
+    ret = p__get_output_format();
+    ok(ret == 0, "got %d\n", ret);
+}
+
 START_TEST(printf)
 {
     init();
@@ -941,10 +1236,14 @@ START_TEST(printf)
     test_sprintf();
     test_swprintf();
     test_snprintf();
+    test_fprintf();
     test_fcvt();
     test_xcvt();
     test_vsnwprintf();
     test_vscprintf();
     test_vscwprintf();
+    test_vswprintf();
     test_vsnwprintf_s();
+    test_vsprintf_p();
+    test__get_output_format();
 }
index e9cb987..cbfb184 100644 (file)
@@ -93,11 +93,14 @@ static void test_sscanf( void )
 
     /* Check float */
     ret = sprintf(buffer,"%f %f",res1, res2);
+    ok( ret == 20, "expected 20, got %u\n", ret);
     ret = sscanf(buffer,"%f%f",&res11, &res12);
+    ok( ret == 2, "expected 2, got %u\n", ret);
     ok( (res11 == res1) && (res12 == res2), "Error reading floats\n");
 
     /* check strings */
     ret = sprintf(buffer," %s", pname);
+    ok( ret == 26, "expected 26, got %u\n", ret);
     ret = sscanf(buffer,"%*c%[^\n]",buffer1);
     ok( ret == 1, "Error with format \"%s\"\n","%*c%[^\n]");
     ok( strncmp(pname,buffer1,strlen(buffer1)) == 0, "Error with \"%s\" \"%s\"\n",pname, buffer1);
@@ -112,6 +115,7 @@ static void test_sscanf( void )
 
     /* check digits */
     ret = sprintf(buffer,"%d:%d:%d",hour,min,sec);
+    ok( ret == 8, "expected 8, got %u\n", ret);
     ret = sscanf(buffer,"%d%n",&number,&number_so_far);
     ok(ret == 1 , "problem with format arg \"%%d%%n\"\n");
     ok(number == hour,"Read wrong arg %d instead of %d\n",number, hour);
index b70d777..b6c4738 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "wine/test.h"
 #include "winbase.h"
+#include "winnls.h"
 #include <string.h>
 #include <mbstring.h>
 #include <stdlib.h>
@@ -29,6 +30,9 @@
 #include <errno.h>
 #include <limits.h>
 
+/* ReactOS */
+typedef unsigned int __msvcrt_ulong;
+
 static char *buf_to_string(const unsigned char *bin, int len, int nr)
 {
     static char buf[2][1024];
@@ -43,6 +47,13 @@ static char *buf_to_string(const unsigned char *bin, int len, int nr)
     return buf[nr];
 }
 
+static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
+        const wchar_t *function, const wchar_t *file,
+        unsigned line, uintptr_t arg)
+{
+    /* we just ignore handler calls */
+}
+
 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
 #define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); }
 
@@ -50,21 +61,35 @@ static void* (__cdecl *pmemcpy)(void *, const void *, size_t n);
 static int* (__cdecl *pmemcmp)(void *, const void *, size_t n);
 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_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);
 static int (__cdecl *p_wcscpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc);
+static int (__cdecl *p_wcsncpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc, size_t count);
+static int (__cdecl *p_wcsncat_s)(wchar_t *dst, size_t elem, const wchar_t *src, size_t count);
 static int (__cdecl *p_wcsupr_s)(wchar_t *str, size_t size);
 static size_t (__cdecl *p_strnlen)(const char *, size_t);
 static __int64 (__cdecl *p_strtoi64)(const char *, char **, int);
 static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int);
 static int (__cdecl *pwcstombs_s)(size_t*,char*,size_t,const wchar_t*,size_t);
 static int (__cdecl *pmbstowcs_s)(size_t*,wchar_t*,size_t,const char*,size_t);
+static size_t (__cdecl *pwcsrtombs)(char*, const wchar_t**, size_t, int*);
+static errno_t (__cdecl *p_gcvt_s)(char*,size_t,double,int);
+static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int);
+static errno_t (__cdecl *p_strlwr_s)(char*,size_t);
+static errno_t (__cdecl *p_ultoa_s)(__msvcrt_ulong,char*,size_t,int);
 static int *p__mb_cur_max;
 static unsigned char *p_mbctype;
+static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler);
+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 int (__cdecl *p_tolower)(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)
 
-HMODULE hMsvcrt;
+static HMODULE hMsvcrt;
 
 static void test_swab( void ) {
     char original[]  = "BADCFEHGJILKNMPORQTSVUXWZY@#";
@@ -180,6 +205,7 @@ static void test_mbcp(void)
     unsigned char *mbsonlylead = (unsigned char *)"\xb0\0\xb1\xb2 \xb3";
     unsigned char buf[16];
     int step;
+    CPINFO cp_info;
 
     /* _mbtype tests */
 
@@ -343,13 +369,14 @@ static void test_mbcp(void)
      * we hope the current locale to be SBCS because setlocale(LC_ALL, ".1252") seems not to work yet
      * (as of Wine 0.9.43)
      */
-    if (*p__mb_cur_max == 1)
+    GetCPInfo(GetACP(), &cp_info);
+    if (cp_info.MaxCharSize == 1)
     {
         expect_eq(mblen((char *)mbstring, 3), 1, int, "%x");
         expect_eq(_mbstrlen((char *)mbstring2), 7, int, "%d");
     }
     else
-        skip("Current locale has double-byte charset - could leave to false positives\n");
+        skip("Current locale has double-byte charset - could lead to false positives\n");
 
     _setmbcp(1361);
     expect_eq(_ismbblead(0x80), 0, int, "%d");
@@ -592,7 +619,7 @@ static void test_wcscpy_s(void)
 
     if(!p_wcscpy_s)
     {
-        skip("wcscpy_s not found\n");
+        win_skip("wcscpy_s not found\n");
         return;
     }
 
@@ -625,6 +652,39 @@ static void test_wcscpy_s(void)
     ret = p_wcscpy_s(szDestShort, 8, szLongText);
     ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret);
     ok(szDestShort[0] == 0, "szDestShort[0] not 0\n");
+
+    if(!p_wcsncpy_s)
+    {
+        win_skip("wcsncpy_s not found\n");
+        return;
+    }
+
+    ret = p_wcsncpy_s(NULL, 18, szLongText, sizeof(szLongText)/sizeof(WCHAR));
+    ok(ret == EINVAL, "p_wcsncpy_s expect EINVAL got %d\n", ret);
+
+    szDest[0] = 'A';
+    ret = p_wcsncpy_s(szDest, 18, NULL, 1);
+    ok(ret == EINVAL, "expected EINVAL got %d\n", ret);
+    ok(szDest[0] == 0, "szDest[0] not 0\n");
+
+    szDest[0] = 'A';
+    ret = p_wcsncpy_s(szDest, 18, NULL, 0);
+    ok(ret == 0, "expected ERROR_SUCCESS got %d\n", ret);
+    ok(szDest[0] == 0, "szDest[0] not 0\n");
+
+    szDest[0] = 'A';
+    ret = p_wcsncpy_s(szDest, 0, szLongText, sizeof(szLongText)/sizeof(WCHAR));
+    ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret);
+    ok(szDest[0] == 0 || ret == EINVAL, "szDest[0] not 0\n");
+
+    ret = p_wcsncpy_s(szDest, 18, szLongText, sizeof(szLongText)/sizeof(WCHAR));
+    ok(ret == 0, "expected 0 got %d\n", ret);
+    ok(lstrcmpW(szDest, szLongText) == 0, "szDest != szLongText\n");
+
+    szDest[0] = 'A';
+    ret = p_wcsncpy_s(szDestShort, 8, szLongText, sizeof(szLongText)/sizeof(WCHAR));
+    ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret);
+    ok(szDestShort[0] == 0, "szDestShort[0] not 0\n");
 }
 
 static void test__wcsupr_s(void)
@@ -714,6 +774,93 @@ static void test__wcsupr_s(void)
     ok(!wcscmp(testBuffer, expectedString), "Expected the string to be fully upper-case\n");
 }
 
+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};
+    WCHAR buffer[2*sizeof(mixedString)/sizeof(WCHAR)];
+    int ret;
+
+    if (!p_wcslwr_s)
+    {
+        win_skip("_wcslwr_s not found\n");
+        return;
+    }
+
+    /* Test NULL input string and invalid size. */
+    errno = EBADF;
+    ret = p_wcslwr_s(NULL, 0);
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno);
+
+    /* Test NULL input string and valid size. */
+    errno = EBADF;
+    ret = p_wcslwr_s(NULL, sizeof(buffer)/sizeof(wchar_t));
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno);
+
+    /* Test empty string with zero size. */
+    errno = EBADF;
+    buffer[0] = 'a';
+    ret = p_wcslwr_s(buffer, 0);
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno);
+    ok(buffer[0] == 0, "expected empty string\n");
+
+    /* Test empty string with size of one. */
+    buffer[0] = 0;
+    ret = p_wcslwr_s(buffer, 1);
+    ok(ret == 0, "got %d\n", ret);
+    ok(buffer[0] == 0, "expected buffer to be unchanged\n");
+
+    /* Test one-byte buffer with zero size. */
+    errno = EBADF;
+    buffer[0] = 'x';
+    ret = p_wcslwr_s(buffer, 0);
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "expected empty string\n");
+
+    /* Test one-byte buffer with size of one. */
+    errno = EBADF;
+    buffer[0] = 'x';
+    ret = p_wcslwr_s(buffer, 1);
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "expected empty string\n");
+
+    /* Test invalid size. */
+    wcscpy(buffer, mixedString);
+    errno = EBADF;
+    ret = p_wcslwr_s(buffer, 0);
+    ok(ret == EINVAL, "Expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "expected empty string\n");
+
+    /* Test normal string uppercasing. */
+    wcscpy(buffer, mixedString);
+    ret = p_wcslwr_s(buffer, sizeof(mixedString)/sizeof(WCHAR));
+    ok(ret == 0, "expected 0, got %d\n", ret);
+    ok(!wcscmp(buffer, expectedString), "expected lowercase\n");
+
+    /* Test uppercasing with a shorter buffer size count. */
+    wcscpy(buffer, mixedString);
+    errno = EBADF;
+    ret = p_wcslwr_s(buffer, sizeof(mixedString)/sizeof(WCHAR) - 1);
+    ok(ret == EINVAL, "expected EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "expected empty string\n");
+
+    /* Test uppercasing with a longer buffer size count. */
+    wcscpy(buffer, mixedString);
+    ret = p_wcslwr_s(buffer, sizeof(buffer)/sizeof(WCHAR));
+    ok(ret == 0, "expected 0, got %d\n", ret);
+    ok(!wcscmp(buffer, expectedString), "expected lowercase\n");
+}
+
 static void test_mbcjisjms(void)
 {
     /* List of value-pairs to test. The test assumes the last pair to be {0, ..} */
@@ -1096,33 +1243,38 @@ static void test__strtod(void)
     const char double4[] = ".21e12";
     const char double5[] = "214353e-3";
     const char overflow[] = "1d9999999999999999999";
+    const char white_chars[] = "  d10";
 
     char *end;
     double d;
 
     d = strtod(double1, &end);
     ok(almost_equal(d, 12.1), "d = %lf\n", d);
-    ok(end == double1+4, "incorrect end (%d)\n", end-double1);
+    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", end-double2);
+    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", end-double3);
+    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", end-double4);
+    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", end-double5);
+    ok(end == double5+9, "incorrect end (%d)\n", (int)(end-double5));
 
     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));
+
     /* Set locale with non '.' decimal point (',') */
     if(!setlocale(LC_ALL, "Polish")) {
         win_skip("system with limited locales\n");
@@ -1154,9 +1306,9 @@ static void test__strtod(void)
     ok(almost_equal(d, 0.1e-4736L), "d = %lf\n", d);
 
     errno = 0xdeadbeef;
-    d = strtod(overflow, &end);
+    strtod(overflow, &end);
     ok(errno == ERANGE, "errno = %x\n", errno);
-    ok(end == overflow+21, "incorrect end (%d)\n", end-overflow);
+    ok(end == overflow+21, "incorrect end (%d)\n", (int)(end-overflow));
 
     errno = 0xdeadbeef;
     strtod("-1d309", NULL);
@@ -1170,6 +1322,7 @@ static void test_mbstowcs(void)
     static const char mSimple[] = "text";
     static const char mHiragana[] = { 0x82,0xa0,0x82,0xa1,0 };
 
+    const wchar_t *pwstr;
     wchar_t wOut[6];
     char mOut[6];
     size_t ret;
@@ -1179,22 +1332,22 @@ static void test_mbstowcs(void)
     mOut[4] = '!'; mOut[5] = '\0';
 
     ret = mbstowcs(NULL, mSimple, 0);
-    ok(ret == 4, "ret = %d\n", ret);
+    ok(ret == 4, "mbstowcs did not return 4\n");
 
     ret = mbstowcs(wOut, mSimple, 4);
-    ok(ret == 4, "ret = %d\n", ret);
+    ok(ret == 4, "mbstowcs did not return 4\n");
     ok(!memcmp(wOut, wSimple, 4*sizeof(wchar_t)), "wOut = %s\n", wine_dbgstr_w(wOut));
     ok(wOut[4] == '!', "wOut[4] != \'!\'\n");
 
     ret = wcstombs(NULL, wSimple, 0);
-    ok(ret == 4, "ret = %d\n", ret);
+    ok(ret == 4, "wcstombs did not return 4\n");
 
     ret = wcstombs(mOut, wSimple, 6);
-    ok(ret == 4, "ret = %d\n", ret);
+    ok(ret == 4, "wcstombs did not return 4\n");
     ok(!memcmp(mOut, mSimple, 5*sizeof(char)), "mOut = %s\n", mOut);
 
     ret = wcstombs(mOut, wSimple, 2);
-    ok(ret == 2, "ret = %d\n", ret);
+    ok(ret == 2, "wcstombs did not return 2\n");
     ok(!memcmp(mOut, mSimple, 5*sizeof(char)), "mOut = %s\n", mOut);
 
     if(!setlocale(LC_ALL, "Japanese_Japan.932")) {
@@ -1203,37 +1356,692 @@ static void test_mbstowcs(void)
     }
 
     ret = mbstowcs(wOut, mHiragana, 6);
-    ok(ret == 2, "ret = %d\n", ret);
+    ok(ret == 2, "mbstowcs did not return 2\n");
     ok(!memcmp(wOut, wHiragana, sizeof(wHiragana)), "wOut = %s\n", wine_dbgstr_w(wOut));
 
     ret = wcstombs(mOut, wHiragana, 6);
-    ok(ret == 4, "ret = %d\n", ret);
+    ok(ret == 4, "wcstombs did not return 4\n");
     ok(!memcmp(mOut, mHiragana, sizeof(mHiragana)), "mOut = %s\n", mOut);
 
     if(!pmbstowcs_s || !pwcstombs_s) {
+        setlocale(LC_ALL, "C");
         win_skip("mbstowcs_s or wcstombs_s not available\n");
         return;
     }
 
     err = pmbstowcs_s(&ret, wOut, 6, mSimple, _TRUNCATE);
     ok(err == 0, "err = %d\n", err);
-    ok(ret == 5, "ret = %d\n", (int)ret);
+    ok(ret == 5, "mbstowcs_s did not return 5\n");
     ok(!memcmp(wOut, wSimple, sizeof(wSimple)), "wOut = %s\n", wine_dbgstr_w(wOut));
 
     err = pmbstowcs_s(&ret, wOut, 6, mHiragana, _TRUNCATE);
     ok(err == 0, "err = %d\n", err);
-    ok(ret == 3, "ret = %d\n", (int)ret);
+    ok(ret == 3, "mbstowcs_s did not return 3\n");
     ok(!memcmp(wOut, wHiragana, sizeof(wHiragana)), "wOut = %s\n", wine_dbgstr_w(wOut));
 
+    err = pmbstowcs_s(&ret, NULL, 0, mHiragana, 1);
+    ok(err == 0, "err = %d\n", err);
+    ok(ret == 3, "mbstowcs_s did not return 3\n");
+
     err = pwcstombs_s(&ret, mOut, 6, wSimple, _TRUNCATE);
     ok(err == 0, "err = %d\n", err);
-    ok(ret == 5, "ret = %d\n", (int)ret);
+    ok(ret == 5, "wcstombs_s did not return 5\n");
     ok(!memcmp(mOut, mSimple, sizeof(mSimple)), "mOut = %s\n", mOut);
 
     err = pwcstombs_s(&ret, mOut, 6, wHiragana, _TRUNCATE);
     ok(err == 0, "err = %d\n", err);
-    ok(ret == 5, "ret = %d\n", (int)ret);
+    ok(ret == 5, "wcstombs_s did not return 5\n");
     ok(!memcmp(mOut, mHiragana, sizeof(mHiragana)), "mOut = %s\n", mOut);
+
+    err = pwcstombs_s(&ret, NULL, 0, wHiragana, 1);
+    ok(err == 0, "err = %d\n", err);
+    ok(ret == 5, "wcstombs_s did not return 5\n");
+
+    if(!pwcsrtombs) {
+        setlocale(LC_ALL, "C");
+        win_skip("wcsrtombs not available\n");
+        return;
+    }
+
+    pwstr = wSimple;
+    err = -3;
+    ret = pwcsrtombs(mOut, &pwstr, 4, &err);
+    ok(ret == 4, "wcsrtombs did not return 4\n");
+    ok(err == 0, "err = %d\n", err);
+    ok(pwstr == wSimple+4, "pwstr = %p (wszSimple = %p)\n", pwstr, wSimple);
+    ok(!memcmp(mOut, mSimple, ret), "mOut = %s\n", mOut);
+
+    pwstr = wSimple;
+    ret = pwcsrtombs(mOut, &pwstr, 5, NULL);
+    ok(ret == 4, "wcsrtombs did not return 4\n");
+    ok(pwstr == NULL, "pwstr != NULL\n");
+    ok(!memcmp(mOut, mSimple, sizeof(mSimple)), "mOut = %s\n", mOut);
+
+    setlocale(LC_ALL, "C");
+}
+
+static void test_gcvt(void)
+{
+    char buf[1024], *res;
+    errno_t err;
+
+    if(!p_gcvt_s) {
+        win_skip("Skipping _gcvt tests\n");
+        return;
+    }
+
+    errno = 0;
+    res = _gcvt(1.2, -1, buf);
+    ok(res == NULL, "res != NULL\n");
+    ok(errno == ERANGE, "errno = %d\n", errno);
+
+    errno = 0;
+    res = _gcvt(1.2, 5, NULL);
+    ok(res == NULL, "res != NULL\n");
+    ok(errno == EINVAL, "errno = %d\n", errno);
+
+    res = gcvt(1.2, 5, buf);
+    ok(res == buf, "res != buf\n");
+    ok(!strcmp(buf, "1.2"), "buf = %s\n", buf);
+
+    buf[0] = 'x';
+    err = p_gcvt_s(buf, 5, 1.2, 10);
+    ok(err == ERANGE, "err = %d\n", err);
+    ok(buf[0] == '\0', "buf[0] = %c\n", buf[0]);
+
+    buf[0] = 'x';
+    err = p_gcvt_s(buf, 4, 123456, 2);
+    ok(err == ERANGE, "err = %d\n", err);
+    ok(buf[0] == '\0', "buf[0] = %c\n", buf[0]);
+}
+
+static void test__itoa_s(void)
+{
+    errno_t ret;
+    char buffer[33];
+
+    if (!p_itoa_s)
+    {
+        win_skip("Skipping _itoa_s tests\n");
+        return;
+    }
+
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+                "Invalid parameter handler was already set\n");
+
+    errno = EBADF;
+    ret = p_itoa_s(0, NULL, 0, 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(0, buffer, 0, 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(0, buffer, sizeof(buffer), 0);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(0, buffer, sizeof(buffer), 64);
+    ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(12345678, buffer, 4, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(buffer, "\000765", 4),
+       "Expected the output buffer to be null terminated with truncated output\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(12345678, buffer, 8, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(buffer, "\0007654321", 8),
+       "Expected the output buffer to be null terminated with truncated output\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_itoa_s(-12345678, buffer, 9, 10);
+    ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(buffer, "\00087654321", 9),
+       "Expected the output buffer to be null terminated with truncated output\n");
+
+    ret = p_itoa_s(12345678, buffer, 9, 10);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "12345678"),
+       "Expected output buffer string to be \"12345678\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(43690, buffer, sizeof(buffer), 2);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "1010101010101010"),
+       "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(1092009, buffer, sizeof(buffer), 36);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "nell"),
+       "Expected output buffer string to be \"nell\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(5704, buffer, sizeof(buffer), 18);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "hag"),
+       "Expected output buffer string to be \"hag\", got \"%s\"\n",
+       buffer);
+
+    ret = p_itoa_s(-12345678, buffer, sizeof(buffer), 10);
+    ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "-12345678"),
+       "Expected output buffer string to be \"-12345678\", got \"%s\"\n",
+       buffer);
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+                "Cannot reset invalid parameter handler\n");
+}
+
+static void test__strlwr_s(void)
+{
+    errno_t ret;
+    char buffer[20];
+
+    if (!p_strlwr_s)
+    {
+        win_skip("Skipping _strlwr_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_strlwr_s(NULL, 0);
+    ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_strlwr_s(NULL, sizeof(buffer));
+    ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_strlwr_s(buffer, 0);
+    ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    strcpy(buffer, "GoRrIsTeR");
+    errno = EBADF;
+    ret = p_strlwr_s(buffer, 5);
+    ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(!memcmp(buffer, "\0oRrIsTeR", sizeof("\0oRrIsTeR")),
+       "Expected the output buffer to be \"gorrIsTeR\"\n");
+
+    strcpy(buffer, "GoRrIsTeR");
+    errno = EBADF;
+    ret = p_strlwr_s(buffer, sizeof("GoRrIsTeR") - 1);
+    ok(ret == EINVAL, "Expected _strlwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(!memcmp(buffer, "\0oRrIsTeR", sizeof("\0oRrIsTeR")),
+       "Expected the output buffer to be \"gorrIsTeR\"\n");
+
+    strcpy(buffer, "GoRrIsTeR");
+    ret = p_strlwr_s(buffer, sizeof("GoRrIsTeR"));
+    ok(ret == 0, "Expected _strlwr_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "gorrister"),
+       "Expected the output buffer to be \"gorrister\", got \"%s\"\n",
+       buffer);
+
+    memcpy(buffer, "GoRrIsTeR\0ELLEN", sizeof("GoRrIsTeR\0ELLEN"));
+    ret = p_strlwr_s(buffer, sizeof(buffer));
+    ok(ret == 0, "Expected _strlwr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "gorrister\0ELLEN", sizeof("gorrister\0ELLEN")),
+       "Expected the output buffer to be \"gorrister\\0ELLEN\", got \"%s\"\n",
+       buffer);
+}
+
+static void test_wcsncat_s(void)
+{
+    static wchar_t abcW[] = {'a','b','c',0};
+    int ret;
+    wchar_t dst[4];
+    wchar_t src[4];
+
+    if (!p_wcsncat_s)
+    {
+        win_skip("skipping wcsncat_s tests\n");
+        return;
+    }
+
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+                "Invalid parameter handler was already set\n");
+
+    memcpy(src, abcW, sizeof(abcW));
+    dst[0] = 0;
+    ret = p_wcsncat_s(NULL, 4, src, 4);
+    ok(ret == EINVAL, "err = %d\n", ret);
+    ret = p_wcsncat_s(dst, 0, src, 4);
+    ok(ret == EINVAL, "err = %d\n", ret);
+    ret = p_wcsncat_s(dst, 0, src, _TRUNCATE);
+    ok(ret == EINVAL, "err = %d\n", ret);
+    ret = p_wcsncat_s(dst, 4, NULL, 0);
+    ok(ret == 0, "err = %d\n", ret);
+
+    dst[0] = 0;
+    ret = p_wcsncat_s(dst, 2, src, 4);
+    ok(ret == ERANGE, "err = %d\n", ret);
+
+    dst[0] = 0;
+    ret = p_wcsncat_s(dst, 2, src, _TRUNCATE);
+    ok(ret == STRUNCATE, "err = %d\n", ret);
+    ok(dst[0] == 'a' && dst[1] == 0, "dst is %s\n", wine_dbgstr_w(dst));
+
+    memcpy(dst, abcW, sizeof(abcW));
+    dst[3] = 'd';
+    ret = p_wcsncat_s(dst, 4, src, 4);
+    ok(ret == EINVAL, "err = %d\n", ret);
+
+    if (p_set_invalid_parameter_handler)
+        ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+                "Cannot reset invalid parameter handler\n");
+}
+
+static void test__mbsnbcat_s(void)
+{
+    unsigned char dest[16];
+    const unsigned char first[] = "dinosaur";
+    const unsigned char second[] = "duck";
+    int ret;
+
+    if (!p_mbsnbcat_s)
+    {
+        win_skip("Skipping _mbsnbcat_s tests\n");
+        return;
+    }
+
+    /* Test invalid arguments. */
+    ret = p_mbsnbcat_s(NULL, 0, NULL, 0);
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+
+    errno = EBADF;
+    ret = p_mbsnbcat_s(NULL, 10, NULL, 0);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_mbsnbcat_s(NULL, 0, NULL, 10);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(dest, 'X', sizeof(dest));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, 0, NULL, 0);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
+
+    memset(dest, 'X', sizeof(dest));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, 0, second, 0);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(dest[0] == 'X', "Expected the output buffer to be untouched\n");
+
+    memset(dest, 'X', sizeof(dest));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, sizeof(dest), NULL, 0);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(dest[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(dest, 'X', sizeof(dest));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, sizeof(dest), NULL, 10);
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(dest[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(dest, 'X', sizeof(dest));
+    dest[0] = '\0';
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second));
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, second, sizeof(second)),
+       "Expected the output buffer string to be \"duck\"\n");
+
+    /* Test source truncation behavior. */
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, 0);
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, first, sizeof(first)),
+       "Expected the output buffer string to be \"dinosaur\"\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second));
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
+       "Expected the output buffer string to be \"dinosaurduck\"\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) + 1);
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
+       "Expected the output buffer string to be \"dinosaurduck\"\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) - 1);
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, "dinosaurduck", sizeof("dinosaurduck")),
+       "Expected the output buffer string to be \"dinosaurduck\"\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    ret = p_mbsnbcat_s(dest, sizeof(dest), second, sizeof(second) - 2);
+    ok(ret == 0, "Expected _mbsnbcat_s to return 0, got %d\n", ret);
+    ok(!memcmp(dest, "dinosaurduc", sizeof("dinosaurduc")),
+       "Expected the output buffer string to be \"dinosaurduc\"\n");
+
+    /* Test destination truncation behavior. */
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, sizeof(first) - 1, second, sizeof(second));
+    ok(ret == EINVAL, "Expected _mbsnbcat_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(!memcmp(dest, "\0inosaur", sizeof("\0inosaur") - 1),
+       "Expected the output buffer string to be \"\\0inosaur\" without ending null terminator\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, sizeof(first), second, sizeof(second));
+    ok(ret == ERANGE, "Expected _mbsnbcat_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(dest, "\0inosaurd", sizeof("\0inosaurd") - 1),
+       "Expected the output buffer string to be \"\\0inosaurd\" without ending null terminator\n");
+
+    memset(dest, 'X', sizeof(dest));
+    memcpy(dest, first, sizeof(first));
+    errno = EBADF;
+    ret = p_mbsnbcat_s(dest, sizeof(first) + 1, second, sizeof(second));
+    ok(ret == ERANGE, "Expected _mbsnbcat_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(dest, "\0inosaurdu", sizeof("\0inosaurdu") - 1),
+       "Expected the output buffer string to be \"\\0inosaurdu\" without ending null terminator\n");
+}
+
+static void test__mbsupr_s(void)
+{
+    errno_t ret;
+    unsigned char buffer[20];
+
+    if (!p_mbsupr_s)
+    {
+        win_skip("Skipping _mbsupr_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_mbsupr_s(NULL, 0);
+    ok(ret == 0, "Expected _mbsupr_s to return 0, got %d\n", ret);
+
+    errno = EBADF;
+    ret = p_mbsupr_s(NULL, sizeof(buffer));
+    ok(ret == EINVAL, "Expected _mbsupr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_mbsupr_s(buffer, 0);
+    ok(ret == EINVAL, "Expected _mbsupr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memcpy(buffer, "abcdefgh", sizeof("abcdefgh"));
+    errno = EBADF;
+    ret = p_mbsupr_s(buffer, sizeof("abcdefgh"));
+    ok(ret == 0, "Expected _mbsupr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "ABCDEFGH", sizeof("ABCDEFGH")),
+       "Expected the output buffer to be \"ABCDEFGH\", got \"%s\"\n",
+       buffer);
+
+    memcpy(buffer, "abcdefgh", sizeof("abcdefgh"));
+    errno = EBADF;
+    ret = p_mbsupr_s(buffer, sizeof(buffer));
+    ok(ret == 0, "Expected _mbsupr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "ABCDEFGH", sizeof("ABCDEFGH")),
+       "Expected the output buffer to be \"ABCDEFGH\", got \"%s\"\n",
+       buffer);
+
+    memcpy(buffer, "abcdefgh", sizeof("abcdefgh"));
+    errno = EBADF;
+    ret = p_mbsupr_s(buffer, 4);
+    ok(ret == EINVAL, "Expected _mbsupr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memcpy(buffer, "abcdefgh\0ijklmnop", sizeof("abcdefgh\0ijklmnop"));
+    errno = EBADF;
+    ret = p_mbsupr_s(buffer, sizeof(buffer));
+    ok(ret == 0, "Expected _mbsupr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "ABCDEFGH\0ijklmnop", sizeof("ABCDEFGH\0ijklmnop")),
+       "Expected the output buffer to be \"ABCDEFGH\\0ijklmnop\", got \"%s\"\n",
+       buffer);
+
+}
+
+static void test__mbslwr_s(void)
+{
+    errno_t ret;
+    unsigned char buffer[20];
+
+    if (!p_mbslwr_s)
+    {
+        win_skip("Skipping _mbslwr_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_mbslwr_s(NULL, 0);
+    ok(ret == 0, "Expected _mbslwr_s to return 0, got %d\n", ret);
+
+    errno = EBADF;
+    ret = p_mbslwr_s(NULL, sizeof(buffer));
+    ok(ret == EINVAL, "Expected _mbslwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    ret = p_mbslwr_s(buffer, 0);
+    ok(ret == EINVAL, "Expected _mbslwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memcpy(buffer, "ABCDEFGH", sizeof("ABCDEFGH"));
+    errno = EBADF;
+    ret = p_mbslwr_s(buffer, sizeof("ABCDEFGH"));
+    ok(ret == 0, "Expected _mbslwr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "abcdefgh", sizeof("abcdefgh")),
+       "Expected the output buffer to be \"abcdefgh\", got \"%s\"\n",
+       buffer);
+
+    memcpy(buffer, "ABCDEFGH", sizeof("ABCDEFGH"));
+    errno = EBADF;
+    ret = p_mbslwr_s(buffer, sizeof(buffer));
+    ok(ret == 0, "Expected _mbslwr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "abcdefgh", sizeof("abcdefgh")),
+       "Expected the output buffer to be \"abcdefgh\", got \"%s\"\n",
+       buffer);
+
+    memcpy(buffer, "ABCDEFGH", sizeof("ABCDEFGH"));
+    errno = EBADF;
+    ret = p_mbslwr_s(buffer, 4);
+    ok(ret == EINVAL, "Expected _mbslwr_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memcpy(buffer, "ABCDEFGH\0IJKLMNOP", sizeof("ABCDEFGH\0IJKLMNOP"));
+    errno = EBADF;
+    ret = p_mbslwr_s(buffer, sizeof(buffer));
+    ok(ret == 0, "Expected _mbslwr_s to return 0, got %d\n", ret);
+    ok(!memcmp(buffer, "abcdefgh\0IJKLMNOP", sizeof("abcdefgh\0IJKLMNOP")),
+       "Expected the output buffer to be \"abcdefgh\\0IJKLMNOP\", got \"%s\"\n",
+       buffer);
+}
+
+static void test__ultoa_s(void)
+{
+    errno_t ret;
+    char buffer[33];
+
+    if (!p_ultoa_s)
+    {
+        win_skip("Skipping _ultoa_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    ret = p_ultoa_s(0, NULL, 0, 0);
+    ok(ret == EINVAL, "Expected _ultoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_ultoa_s(0, buffer, 0, 0);
+    ok(ret == EINVAL, "Expected _ultoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_ultoa_s(0, buffer, sizeof(buffer), 0);
+    ok(ret == EINVAL, "Expected _ultoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_ultoa_s(0, buffer, sizeof(buffer), 64);
+    ok(ret == EINVAL, "Expected _ultoa_s to return EINVAL, got %d\n", ret);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_ultoa_s(12345678, buffer, 4, 10);
+    ok(ret == ERANGE, "Expected _ultoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(buffer, "\000765", 4),
+       "Expected the output buffer to be null terminated with truncated output\n");
+
+    memset(buffer, 'X', sizeof(buffer));
+    errno = EBADF;
+    ret = p_ultoa_s(12345678, buffer, 8, 10);
+    ok(ret == ERANGE, "Expected _ultoa_s to return ERANGE, got %d\n", ret);
+    ok(errno == ERANGE, "Expected errno to be ERANGE, got %d\n", errno);
+    ok(!memcmp(buffer, "\0007654321", 8),
+       "Expected the output buffer to be null terminated with truncated output\n");
+
+    ret = p_ultoa_s(12345678, buffer, 9, 10);
+    ok(ret == 0, "Expected _ultoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "12345678"),
+       "Expected output buffer string to be \"12345678\", got \"%s\"\n",
+       buffer);
+
+    ret = p_ultoa_s(43690, buffer, sizeof(buffer), 2);
+    ok(ret == 0, "Expected _ultoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "1010101010101010"),
+       "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n",
+       buffer);
+
+    ret = p_ultoa_s(1092009, buffer, sizeof(buffer), 36);
+    ok(ret == 0, "Expected _ultoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "nell"),
+       "Expected output buffer string to be \"nell\", got \"%s\"\n",
+       buffer);
+
+    ret = p_ultoa_s(5704, buffer, sizeof(buffer), 18);
+    ok(ret == 0, "Expected _ultoa_s to return 0, got %d\n", ret);
+    ok(!strcmp(buffer, "hag"),
+       "Expected output buffer string to be \"hag\", got \"%s\"\n",
+       buffer);
+}
+
+static void test_wctob(void)
+{
+    int ret;
+
+    if(!p_wctob || !setlocale(LC_ALL, "chinese-traditional")) {
+        win_skip("Skipping wctob tests\n");
+        return;
+    }
+
+    ret = p_wctob(0x8141);
+    ok(ret == EOF, "ret = %x\n", ret);
+
+    ret = p_wctob(0x81);
+    ok(ret == EOF, "ret = %x\n", ret);
+
+    ret = p_wctob(0xe0);
+    ok(ret == 0x61, "ret = %x\n", ret);
+
+    _setmbcp(1250);
+    ret = p_wctob(0x81);
+    ok(ret == EOF, "ret = %x\n", ret);
+
+    setlocale(LC_ALL, "C");
+    ret = p_wctob(0x8141);
+    ok(ret == EOF, "ret = %x\n", ret);
+
+    ret = p_wctob(0x81);
+    ok(ret == (int)(char)0x81, "ret = %x\n", ret);
+
+    ret = p_wctob(0xe0);
+    ok(ret == (int)(char)0xe0, "ret = %x\n", ret);
+}
+
+static void test_tolower(void)
+{
+    int ret;
+
+    ret = p_tolower(0x41);
+    ok(ret == 0x61, "ret = %x\n", ret);
+
+    ret = p_tolower(0xF4);
+    ok(ret == 0xF4, "ret = %x\n", ret);
+
+    ret = p_tolower((char)0xF4);
+    ok(ret==0xF4/*Vista+*/ || ret==(char)0xF4, "ret = %x\n", ret);
+
+    /* is it using different locale (CP_ACP) for negative values?? */
+    /* current implementation matches msvcr90 behaviour */
+    ret = p_tolower((char)0xD0);
+    todo_wine ok(ret==0xF0/*Vista+*/ || ret==(char)0xD0, "ret = %x\n", ret);
+
+    ret = p_tolower(0xD0);
+    ok(ret == 0xD0, "ret = %x\n", ret);
+
+    if(!setlocale(LC_ALL, "us")) {
+        win_skip("skipping tolower tests that depends on locale\n");
+        return;
+    }
+
+    ret = p_tolower((char)0xD0);
+    ok(ret == 0xF0, "ret = %x\n", ret);
+
+    ret = p_tolower(0xD0);
+    ok(ret == 0xF0, "ret = %x\n", ret);
+
+    setlocale(LC_ALL, "C");
 }
 
 START_TEST(string)
@@ -1252,14 +2060,28 @@ START_TEST(string)
     SET(p__mb_cur_max,"__mb_cur_max");
     pstrcpy_s = (void *)GetProcAddress( hMsvcrt,"strcpy_s" );
     pstrcat_s = (void *)GetProcAddress( hMsvcrt,"strcat_s" );
+    p_mbsnbcat_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcat_s" );
     p_mbsnbcpy_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcpy_s" );
     p_wcscpy_s = (void *)GetProcAddress( hMsvcrt,"wcscpy_s" );
+    p_wcsncpy_s = (void *)GetProcAddress( hMsvcrt,"wcsncpy_s" );
+    p_wcsncat_s = (void *)GetProcAddress( hMsvcrt,"wcsncat_s" );
     p_wcsupr_s = (void *)GetProcAddress( hMsvcrt,"_wcsupr_s" );
     p_strnlen = (void *)GetProcAddress( hMsvcrt,"strnlen" );
-    p_strtoi64 = (void *) GetProcAddress(hMsvcrt, "_strtoi64");
-    p_strtoui64 = (void *) GetProcAddress(hMsvcrt, "_strtoui64");
-    pmbstowcs_s = (void *) GetProcAddress(hMsvcrt, "mbstowcs_s");
-    pwcstombs_s = (void *) GetProcAddress(hMsvcrt, "wcstombs_s");
+    p_strtoi64 = (void *)GetProcAddress(hMsvcrt, "_strtoi64");
+    p_strtoui64 = (void *)GetProcAddress(hMsvcrt, "_strtoui64");
+    pmbstowcs_s = (void *)GetProcAddress(hMsvcrt, "mbstowcs_s");
+    pwcstombs_s = (void *)GetProcAddress(hMsvcrt, "wcstombs_s");
+    pwcsrtombs = (void *)GetProcAddress(hMsvcrt, "wcsrtombs");
+    p_gcvt_s = (void *)GetProcAddress(hMsvcrt, "_gcvt_s");
+    p_itoa_s = (void *)GetProcAddress(hMsvcrt, "_itoa_s");
+    p_strlwr_s = (void *)GetProcAddress(hMsvcrt, "_strlwr_s");
+    p_ultoa_s = (void *)GetProcAddress(hMsvcrt, "_ultoa_s");
+    p_set_invalid_parameter_handler = (void *) GetProcAddress(hMsvcrt, "_set_invalid_parameter_handler");
+    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_wctob = (void*)GetProcAddress(hMsvcrt, "wctob");
+    p_tolower = (void*)GetProcAddress(hMsvcrt, "tolower");
 
     /* MSVCRT memcpy behaves like memmove for overlapping moves,
        MFC42 CString::Insert seems to rely on that behaviour */
@@ -1293,4 +2115,15 @@ START_TEST(string)
     test__strtoi64();
     test__strtod();
     test_mbstowcs();
+    test_gcvt();
+    test__itoa_s();
+    test__strlwr_s();
+    test_wcsncat_s();
+    test__mbsnbcat_s();
+    test__ultoa_s();
+    test__wcslwr_s();
+    test__mbsupr_s();
+    test__mbslwr_s();
+    test_wctob();
+    test_tolower();
 }
index 7f0a80b..950042c 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <stdlib.h> /*setenv*/
 #include <stdio.h> /*printf*/
+#include <errno.h>
+
+#define _MAX__TIME64_T     (((__time64_t)0x00000007 << 32) | 0x93406FFF)
 
 #define SECSPERDAY         86400
 #define SECSPERHOUR        3600
 #define MINSPERHOUR        60
 #define HOURSPERDAY        24
 
+static __time32_t (__cdecl *p_mkgmtime32)(struct tm*);
+static struct tm* (__cdecl *p_gmtime32)(__time32_t*);
+static errno_t    (__cdecl *p_gmtime32_s)(struct tm*, __time32_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*);
+static errno_t    (__cdecl *p_localtime64_s)(struct tm*, __time64_t*);
+static int*       (__cdecl *p__daylight)(void);
+static int*       (__cdecl *p___p__daylight)(void);
+
+static void init(void)
+{
+    HMODULE hmod = GetModuleHandleA("msvcrt.dll");
+
+    p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32");
+    p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s");
+    p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
+    p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
+    p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s");
+    p_localtime32_s = (void*)GetProcAddress(hmod, "_localtime32_s");
+    p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s");
+    p__daylight = (void*)GetProcAddress(hmod, "__daylight");
+    p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight");
+}
+
 static int get_test_year(time_t *start)
 {
     time_t now = time(NULL);
@@ -54,19 +82,22 @@ static void test_ctime(void)
 }
 static void test_gmtime(void)
 {
-    static __time32_t (__cdecl *p_mkgmtime32)(struct tm*);
-    static struct tm* (__cdecl *p_gmtime32)(__time32_t*);
-
-    HMODULE hmod = GetModuleHandleA("msvcrt.dll");
     __time32_t valid, gmt;
-    struct tm* gmt_tm;
+    struct tm* gmt_tm, gmt_tm_s;
+    errno_t err;
 
-    p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32");
     if(!p_gmtime32) {
         win_skip("Skipping _gmtime32 tests\n");
         return;
     }
 
+    gmt_tm = p_gmtime32(NULL);
+    ok(gmt_tm == NULL, "gmt_tm != NULL\n");
+
+    gmt = -1;
+    gmt_tm = p_gmtime32(&gmt);
+    ok(gmt_tm == NULL, "gmt_tm != NULL\n");
+
     gmt = valid = 0;
     gmt_tm = p_gmtime32(&gmt);
     if(!gmt_tm) {
@@ -81,7 +112,6 @@ static void test_gmtime(void)
             gmt_tm->tm_year, gmt_tm->tm_mon, gmt_tm->tm_yday, gmt_tm->tm_mday, gmt_tm->tm_wday,
             gmt_tm->tm_hour, gmt_tm->tm_min, gmt_tm->tm_sec, gmt_tm->tm_isdst);
 
-    p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
     if(!p_mkgmtime32) {
         win_skip("Skipping _mkgmtime32 tests\n");
         return;
@@ -123,6 +153,24 @@ static void test_gmtime(void)
     gmt_tm->tm_isdst = 1;
     gmt = p_mkgmtime32(gmt_tm);
     ok(gmt == valid, "gmt = %u\n", gmt);
+
+    if(!p_gmtime32_s) {
+        win_skip("Skipping _gmtime32_s tests\n");
+        return;
+    }
+
+    errno = 0;
+    gmt = 0;
+    err = p_gmtime32_s(NULL, &gmt);
+    ok(err == EINVAL, "err = %d\n", err);
+    ok(errno == EINVAL, "errno = %d\n", errno);
+
+    errno = 0;
+    gmt = -1;
+    err = p_gmtime32_s(&gmt_tm_s, &gmt);
+    ok(err == EINVAL, "err = %d\n", err);
+    ok(errno == EINVAL, "errno = %d\n", errno);
+    ok(gmt_tm_s.tm_year == -1, "tm_year = %d\n", gmt_tm_s.tm_year);
 }
 
 static void test_mktime(void)
@@ -287,6 +335,7 @@ static void test_strdate(void)
 {
     char date[16], * result;
     int month, day, year, count, len;
+    errno_t err;
 
     result = _strdate(date);
     ok(result == date, "Wrong return value\n");
@@ -294,12 +343,34 @@ static void test_strdate(void)
     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
     count = sscanf(date, "%02d/%02d/%02d", &month, &day, &year);
     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
+
+    if(!p_strdate_s) {
+        win_skip("Skipping _strdate_s tests\n");
+        return;
+    }
+
+    errno = 0;
+    err = p_strdate_s(NULL, 1);
+    ok(err == EINVAL, "err = %d\n", err);
+    ok(errno == EINVAL, "errno = %d\n", errno);
+
+    date[0] = 'x';
+    date[1] = 'x';
+    err = p_strdate_s(date, 8);
+    ok(err == ERANGE, "err = %d\n", err);
+    ok(errno == ERANGE, "errno = %d\n", errno);
+    ok(date[0] == '\0', "date[0] != '\\0'\n");
+    ok(date[1] == 'x', "date[1] != 'x'\n");
+
+    err = p_strdate_s(date, 9);
+    ok(err == 0, "err = %x\n", err);
 }
 
 static void test_strtime(void)
 {
     char time[16], * result;
     int hour, minute, second, count, len;
+    errno_t err;
 
     result = _strtime(time);
     ok(result == time, "Wrong return value\n");
@@ -307,6 +378,29 @@ static void test_strtime(void)
     ok(len == 8, "Wrong length: returned %d, should be 8\n", len);
     count = sscanf(time, "%02d:%02d:%02d", &hour, &minute, &second);
     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
+
+    if(!p_strtime_s) {
+        win_skip("Skipping _strtime_s tests\n");
+        return;
+    }
+
+    errno = 0;
+    err = p_strtime_s(NULL, 0);
+    ok(err == EINVAL, "err = %d\n", err);
+    ok(errno == EINVAL, "errno = %d\n", errno);
+
+    err = p_strtime_s(NULL, 1);
+    ok(err == EINVAL, "err = %d\n", err);
+    ok(errno == EINVAL, "errno = %d\n", errno);
+
+    time[0] = 'x';
+    err = p_strtime_s(time, 8);
+    ok(err == ERANGE, "err = %d\n", err);
+    ok(errno == ERANGE, "errno = %d\n", errno);
+    ok(time[0] == '\0', "time[0] != '\\0'\n");
+
+    err = p_strtime_s(time, 9);
+    ok(err == 0, "err = %x\n", err);
 }
 
 static void test_wstrdate(void)
@@ -337,8 +431,147 @@ static void test_wstrtime(void)
     ok(count == 3, "Wrong format: count = %d, should be 3\n", count);
 }
 
+static void test_localtime32_s(void)
+{
+    struct tm tm;
+    __time32_t time;
+    errno_t err;
+
+    if (!p_localtime32_s)
+    {
+        win_skip("Skipping _localtime32_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    err = p_localtime32_s(NULL, NULL);
+    ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    time = 0x12345678;
+    err = p_localtime32_s(NULL, &time);
+    ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(&tm, 0, sizeof(tm));
+    errno = EBADF;
+    err = p_localtime32_s(&tm, NULL);
+    ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
+       tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
+       tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
+       "Expected tm structure members to be initialized to -1, got "
+       "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
+       tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
+       tm.tm_isdst);
+
+    memset(&tm, 0, sizeof(tm));
+    time = -1;
+    errno = EBADF;
+    err = p_localtime32_s(&tm, &time);
+    ok(err == EINVAL, "Expected _localtime32_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
+       tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
+       tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
+       "Expected tm structure members to be initialized to -1, got "
+       "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
+       tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
+       tm.tm_isdst);
+}
+
+static void test_localtime64_s(void)
+{
+    struct tm tm;
+    __time64_t time;
+    errno_t err;
+
+    if (!p_localtime64_s)
+    {
+        win_skip("Skipping _localtime64_s tests\n");
+        return;
+    }
+
+    errno = EBADF;
+    err = p_localtime64_s(NULL, NULL);
+    ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    errno = EBADF;
+    time = 0xdeadbeef;
+    err = p_localtime64_s(NULL, &time);
+    ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+
+    memset(&tm, 0, sizeof(tm));
+    errno = EBADF;
+    err = p_localtime64_s(&tm, NULL);
+    ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
+       tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
+       tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
+       "Expected tm structure members to be initialized to -1, got "
+       "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
+       tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
+       tm.tm_isdst);
+
+    memset(&tm, 0, sizeof(tm));
+    time = -1;
+    errno = EBADF;
+    err = p_localtime64_s(&tm, &time);
+    ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
+       tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
+       tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
+       "Expected tm structure members to be initialized to -1, got "
+       "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
+       tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
+       tm.tm_isdst);
+
+    memset(&tm, 0, sizeof(tm));
+    time = _MAX__TIME64_T + 1;
+    errno = EBADF;
+    err = p_localtime64_s(&tm, &time);
+    ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err);
+    ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno);
+    ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 &&
+       tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 &&
+       tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1,
+       "Expected tm structure members to be initialized to -1, got "
+       "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min,
+       tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday,
+       tm.tm_isdst);
+}
+
+static void test_daylight(void)
+{
+    int *ret1, *ret2;
+
+    if (!p__daylight)
+    {
+        win_skip("__daylight() not available\n");
+        return;
+    }
+
+    if (!p___p__daylight)
+    {
+        win_skip("__p__daylight not available\n");
+        return;
+    }
+
+    ret1 = p__daylight();
+    ret2 = p___p__daylight();
+    ok(ret1 && ret1 == ret2, "got %p\n", ret1);
+}
+
 START_TEST(time)
 {
+    init();
+
     test_ctime();
     test_gmtime();
     test_mktime();
@@ -347,4 +580,7 @@ START_TEST(time)
     test_strtime();
     test_wstrdate();
     test_wstrtime();
+    test_localtime32_s();
+    test_localtime64_s();
+    test_daylight();
 }