Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/msvcrt/tests/file.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index bc26f90643e..78ed8931d7a 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -37,6 +37,20 @@ #include <locale.h> #include <winternl.h>
+#define WX_OPEN 0x01 +#define WX_ATEOF 0x02 +#define WX_READNL 0x04 +#define WX_PIPE 0x08 +#define WX_DONTINHERIT 0x10 +#define WX_APPEND 0x20 +#define WX_TTY 0x40 +#define WX_TEXT 0x80 + +#define EF_UTF8 0x01 +#define EF_UTF16 0x02 +#define EF_CRIT_INIT 0x04 +#define EF_UNK_UNICODE 0x08 + #define MSVCRT_FD_BLOCK_SIZE 32 typedef struct { HANDLE handle; @@ -2851,6 +2865,40 @@ static void test_open_hints(void) unlink(tempfile); }
+static void test_ioinfo_flags(void) +{ + HANDLE handle; + ioinfo *info; + char *tempf; + int tempfd; + + tempf = _tempnam(".","wne"); + + tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + + handle = (HANDLE)_get_osfhandle(tempfd); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == handle, "Unexpected handle %p, expected %p.\n", info->handle, handle); + ok(info->exflag == (EF_UTF16 | EF_CRIT_INIT | EF_UNK_UNICODE), "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + + close(tempfd); + + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(info->exflag == (EF_UTF16 | EF_CRIT_INIT | EF_UNK_UNICODE), "Unexpected exflag %#x.\n", info->exflag); + ok(!info->wxflag, "Unexpected wxflag %#x.\n", info->wxflag); + + info = &__pioinfo[(tempfd + 4) / MSVCRT_FD_BLOCK_SIZE][(tempfd + 4) % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(!info->exflag, "Unexpected exflag %#x.\n", info->exflag); + + unlink(tempf); + free(tempf); +} + START_TEST(file) { int arg_c; @@ -2925,6 +2973,7 @@ START_TEST(file) test_lseek(); test_fopen_hints(); test_open_hints(); + test_ioinfo_flags();
/* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- configure.ac | 1 + dlls/msvcr80/tests/Makefile.in | 7 ++ dlls/msvcr80/tests/msvcr80.c | 148 ++++++++++++++++++++++++++++ dlls/msvcr80/tests/msvcr80.manifest | 22 +++++ dlls/msvcr80/tests/msvcr80.rc | 22 +++++ dlls/msvcrt/file.c | 6 +- 6 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 dlls/msvcr80/tests/Makefile.in create mode 100644 dlls/msvcr80/tests/msvcr80.c create mode 100644 dlls/msvcr80/tests/msvcr80.manifest create mode 100644 dlls/msvcr80/tests/msvcr80.rc
diff --git a/configure.ac b/configure.ac index e509b232d11..6cbc0a61be1 100644 --- a/configure.ac +++ b/configure.ac @@ -2798,6 +2798,7 @@ WINE_CONFIG_MAKEFILE(dlls/msvcr120_app) WINE_CONFIG_MAKEFILE(dlls/msvcr70) WINE_CONFIG_MAKEFILE(dlls/msvcr71) WINE_CONFIG_MAKEFILE(dlls/msvcr80) +WINE_CONFIG_MAKEFILE(dlls/msvcr80/tests) WINE_CONFIG_MAKEFILE(dlls/msvcr90) WINE_CONFIG_MAKEFILE(dlls/msvcr90/tests) WINE_CONFIG_MAKEFILE(dlls/msvcrt) diff --git a/dlls/msvcr80/tests/Makefile.in b/dlls/msvcr80/tests/Makefile.in new file mode 100644 index 00000000000..1a17aea05ce --- /dev/null +++ b/dlls/msvcr80/tests/Makefile.in @@ -0,0 +1,7 @@ +TESTDLL = msvcr80.dll + +C_SRCS = \ + msvcr80.c + +RC_SRCS = \ + msvcr80.rc diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c new file mode 100644 index 00000000000..a9c51654e5e --- /dev/null +++ b/dlls/msvcr80/tests/msvcr80.c @@ -0,0 +1,148 @@ +/* + * Copyright 2022 Paul Gofman for CodeWeavers + * + * 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 + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <share.h> +#include <sys/stat.h> + +#include <windef.h> +#include <winbase.h> +#include <errno.h> +#include "wine/test.h" + +#define WX_OPEN 0x01 +#define WX_ATEOF 0x02 +#define WX_READNL 0x04 +#define WX_PIPE 0x08 +#define WX_DONTINHERIT 0x10 +#define WX_APPEND 0x20 +#define WX_TTY 0x40 +#define WX_TEXT 0x80 + +#define MSVCRT_FD_BLOCK_SIZE 32 + +typedef struct +{ + HANDLE handle; + unsigned char wxflag; + char lookahead[3]; + int exflag; + CRITICAL_SECTION crit; + char textmode : 7; + char unicode : 1; + char pipech2[2]; + __int64 startpos; + BOOL utf8translations; + char dbcsBuffer; + BOOL dbcsBufferUsed; +} ioinfo; + +static ioinfo **__pioinfo; + +static int (__cdecl *p__open)(const char *, int, ...); +static int (__cdecl *p__close)(int); +static intptr_t (__cdecl *p__get_osfhandle)(int); + +#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) +#define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) +static BOOL init(void) +{ + HMODULE hcrt; + + SetLastError(0xdeadbeef); + hcrt = LoadLibraryA("msvcr80.dll"); + if (!hcrt) { + win_skip("msvcr80.dll not installed (got %ld)\n", GetLastError()); + return FALSE; + } + + SET(__pioinfo, "__pioinfo"); + SET(p__open,"_open"); + SET(p__close,"_close"); + SET(p__get_osfhandle, "_get_osfhandle"); + + return TRUE; +} + +static void test_ioinfo_flags(void) +{ + HANDLE handle; + ioinfo *info; + char *tempf; + int tempfd; + + tempf = _tempnam(".","wne"); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + handle = (HANDLE)p__get_osfhandle(tempfd); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == handle, "Unexpected handle %p, expected %p.\n", info->handle, handle); + todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + todo_wine ok(info->unicode, "Unicode is not set.\n"); + todo_wine ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + todo_wine ok(info->unicode, "Unicode is not set.\n"); + ok(!info->wxflag, "Unexpected wxflag %#x.\n", info->wxflag); + todo_wine ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + + info = &__pioinfo[(tempfd + 4) / MSVCRT_FD_BLOCK_SIZE][(tempfd + 4) % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(!info->exflag, "Unexpected exflag %#x.\n", info->exflag); + ok(!info->textmode, "Unexpected textmode %d.\n", info->textmode); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_TEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + ok(!info->unicode, "Unicode is not set.\n"); + ok(!info->textmode, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_U8TEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + ok(!info->unicode, "Unicode is not set.\n"); + todo_wine ok(info->textmode == 1, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + unlink(tempf); + free(tempf); +} + +START_TEST(msvcr80) +{ + if(!init()) + return; + + test_ioinfo_flags(); +} diff --git a/dlls/msvcr80/tests/msvcr80.manifest b/dlls/msvcr80/tests/msvcr80.manifest new file mode 100644 index 00000000000..038788d4c4f --- /dev/null +++ b/dlls/msvcr80/tests/msvcr80.manifest @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity + type="win32" + name="Wine.msvcr80.Test" + version="1.0.0.0" + processorArchitecture="*" + /> +<description>Wine msvcr90 test suite</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="microsoft.vc80.crt" + version="8.0.50727.762" + processorArchitecture="*" + publicKeyToken="1fc8b3b9a1e18e3b" + language="*" + /> +</dependentAssembly> +</dependency> +</assembly> diff --git a/dlls/msvcr80/tests/msvcr80.rc b/dlls/msvcr80/tests/msvcr80.rc new file mode 100644 index 00000000000..69d3b1239b4 --- /dev/null +++ b/dlls/msvcr80/tests/msvcr80.rc @@ -0,0 +1,22 @@ +/* + * Copyright 2022 Paul Gofman for CodeWeavers + * + * 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 + */ + +#include "winuser.h" + +/* @makedep: msvcr80.manifest */ +1 RT_MANIFEST msvcr80.manifest diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index a84e61d8993..3497205e12c 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -114,8 +114,6 @@ typedef struct { char pipech2[2]; __int64 startpos; BOOL utf8translations; -#endif -#if _MSVCR_VER >= 90 char dbcsBuffer; BOOL dbcsBufferUsed; #endif @@ -3492,7 +3490,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) char conv[sizeof(lfbuf)]; size_t len = 0;
-#if _MSVCR_VER >= 90 +#if _MSVCR_VER >= 80 if (info->dbcsBufferUsed) { conv[j++] = info->dbcsBuffer; @@ -3511,7 +3509,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count)
if (i == count) { -#if _MSVCR_VER >= 90 +#if _MSVCR_VER >= 80 info->dbcsBuffer = conv[j-1]; info->dbcsBufferUsed = TRUE; break;
Signed-off-by: Piotr Caban piotr@codeweavers.com
There was a version of python that was depending on incorrect ioinfo layout. According to their commit messages it never worked on Windows (they were supporting msvcr80 builds but official builds were using msvcr90 at that point).
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/msvcr80/tests/msvcr80.c | 18 ++--- dlls/msvcrt/file.c | 140 +++++++++++++++++++++++++++-------- 2 files changed, 118 insertions(+), 40 deletions(-)
diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c index a9c51654e5e..c74cd8b93a2 100644 --- a/dlls/msvcr80/tests/msvcr80.c +++ b/dlls/msvcr80/tests/msvcr80.c @@ -97,17 +97,17 @@ static void test_ioinfo_flags(void) info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; ok(!!info, "NULL info.\n"); ok(info->handle == handle, "Unexpected handle %p, expected %p.\n", info->handle, handle); - todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); - todo_wine ok(info->unicode, "Unicode is not set.\n"); - todo_wine ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + ok(info->unicode, "Unicode is not set.\n"); + ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); p__close(tempfd);
ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); - todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); - todo_wine ok(info->unicode, "Unicode is not set.\n"); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->unicode, "Unicode is not set.\n"); ok(!info->wxflag, "Unexpected wxflag %#x.\n", info->wxflag); - todo_wine ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode);
info = &__pioinfo[(tempfd + 4) / MSVCRT_FD_BLOCK_SIZE][(tempfd + 4) % MSVCRT_FD_BLOCK_SIZE]; ok(!!info, "NULL info.\n"); @@ -119,7 +119,7 @@ static void test_ioinfo_flags(void) ok(tempfd != -1, "_open failed with error: %d\n", errno); info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; ok(!!info, "NULL info.\n"); - todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); ok(!info->unicode, "Unicode is not set.\n"); ok(!info->textmode, "Unexpected textmode %d.\n", info->textmode); @@ -129,10 +129,10 @@ static void test_ioinfo_flags(void) ok(tempfd != -1, "_open failed with error: %d\n", errno); info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; ok(!!info, "NULL info.\n"); - todo_wine ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); ok(!info->unicode, "Unicode is not set.\n"); - todo_wine ok(info->textmode == 1, "Unexpected textmode %d.\n", info->textmode); + ok(info->textmode == 1, "Unexpected textmode %d.\n", info->textmode); p__close(tempfd);
unlink(tempf); diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 3497205e12c..637cc614fad 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -86,22 +86,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); #define WX_TTY 0x40 #define WX_TEXT 0x80
-/* values for exflag - it's used differently in msvcr90.dll*/ -#define EF_UTF8 0x01 -#define EF_UTF16 0x02 -#define EF_CRIT_INIT 0x04 -#define EF_UNK_UNICODE 0x08 - static char utf8_bom[3] = { 0xef, 0xbb, 0xbf }; static char utf16_bom[2] = { 0xff, 0xfe };
+enum textmode +{ + TEXTMODE_ANSI, + TEXTMODE_UTF8, + TEXTMODE_UTF16LE, +}; + /* FIXME: this should be allocated dynamically */ #define MSVCRT_MAX_FILES 2048 #define MSVCRT_FD_BLOCK_SIZE 32
#define MSVCRT_INTERNAL_BUFSIZ 4096
-/* ioinfo structure size is different in msvcrXX.dll's */ typedef struct { HANDLE handle; unsigned char wxflag; @@ -130,6 +130,82 @@ ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 }; */ ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
+#if _MSVCR_VER >= 80 +static inline BOOL ioinfo_is_crit_init(ioinfo *info) +{ + return info->exflag & 1; +} + +static inline void ioinfo_set_crit_init(ioinfo *info) +{ + info->exflag |= 1; +} + +static inline enum textmode ioinfo_get_textmode(ioinfo *info) +{ + return info->textmode; +} + +static inline void ioinfo_set_textmode(ioinfo *info, enum textmode mode) +{ + info->textmode = mode; +} + +static inline void ioinfo_set_unicode(ioinfo *info, BOOL unicode) +{ + info->unicode = !!unicode; +} +#else + +#define EF_UTF8 0x01 +#define EF_UTF16 0x02 +#define EF_CRIT_INIT 0x04 +#define EF_UNK_UNICODE 0x08 + +static inline BOOL ioinfo_is_crit_init(ioinfo *info) +{ + return info->exflag & EF_CRIT_INIT; +} + +static inline void ioinfo_set_crit_init(ioinfo *info) +{ + info->exflag |= EF_CRIT_INIT; +} + +static inline enum textmode ioinfo_get_textmode(ioinfo *info) +{ + if (info->exflag & EF_UTF8) + return TEXTMODE_UTF8; + if (info->exflag & EF_UTF16) + return TEXTMODE_UTF16LE; + return TEXTMODE_ANSI; +} + +static inline void ioinfo_set_textmode(ioinfo *info, enum textmode mode) +{ + info->exflag &= EF_CRIT_INIT | EF_UNK_UNICODE; + switch (mode) + { + case TEXTMODE_ANSI: + break; + case TEXTMODE_UTF8: + info->exflag |= EF_UTF8; + break; + case TEXTMODE_UTF16LE: + info->exflag |= EF_UTF16; + break; + } +} + +static inline void ioinfo_set_unicode(ioinfo *info, BOOL unicode) +{ + if (unicode) + info->exflag |= EF_UNK_UNICODE; + else + info->exflag &= ~EF_UNK_UNICODE; +} +#endif + typedef struct { FILE file; CRITICAL_SECTION crit; @@ -270,11 +346,11 @@ static inline ioinfo* get_ioinfo_nolock(int fd)
static inline void init_ioinfo_cs(ioinfo *info) { - if(!(info->exflag & EF_CRIT_INIT)) { + if(!ioinfo_is_crit_init(info)) { LOCK_FILES(); - if(!(info->exflag & EF_CRIT_INIT)) { + if(!ioinfo_is_crit_init(info)) { InitializeCriticalSection(&info->crit); - info->exflag |= EF_CRIT_INIT; + ioinfo_set_crit_init(info); } UNLOCK_FILES(); } @@ -364,7 +440,7 @@ static inline ioinfo* get_ioinfo_alloc(int *fd)
static inline void release_ioinfo(ioinfo *info) { - if(info!=&MSVCRT___badioinfo && info->exflag & EF_CRIT_INIT) + if(info!=&MSVCRT___badioinfo && ioinfo_is_crit_init(info)) LeaveCriticalSection(&info->crit); }
@@ -431,7 +507,8 @@ static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag) fdinfo->lookahead[0] = '\n'; fdinfo->lookahead[1] = '\n'; fdinfo->lookahead[2] = '\n'; - fdinfo->exflag &= EF_CRIT_INIT; + ioinfo_set_unicode(fdinfo, FALSE); + ioinfo_set_textmode(fdinfo, TEXTMODE_ANSI);
if (hand == MSVCRT_NO_CONSOLE) hand = 0; switch (fdinfo-MSVCRT___pioinfo[0]) @@ -1260,7 +1337,7 @@ void msvcrt_free_io(void)
for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++) { - if(MSVCRT___pioinfo[i][j].exflag & EF_CRIT_INIT) + if(ioinfo_is_crit_init(&MSVCRT___pioinfo[i][j])) DeleteCriticalSection(&MSVCRT___pioinfo[i][j].crit); } free(MSVCRT___pioinfo[i]); @@ -2379,12 +2456,12 @@ int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pm return *_errno();
if (oflags & _O_WTEXT) - get_ioinfo_nolock(*fd)->exflag |= EF_UNK_UNICODE; + ioinfo_set_unicode(get_ioinfo_nolock(*fd), TRUE);
if (oflags & _O_U16TEXT) - get_ioinfo_nolock(*fd)->exflag |= EF_UTF16; + ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF16LE); else if (oflags & _O_U8TEXT) - get_ioinfo_nolock(*fd)->exflag |= EF_UTF8; + ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF8);
TRACE(":fd (%d) handle (%p)\n", *fd, hand); return 0; @@ -2801,14 +2878,14 @@ static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count) return -1; }
- utf16 = (fdinfo->exflag & EF_UTF16) != 0; - if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1) + utf16 = ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF16LE; + if (ioinfo_get_textmode(fdinfo) != TEXTMODE_ANSI && count&1) { *_errno() = EINVAL; return -1; }
- if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8)) + if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF8) return read_utf8(fdinfo, buf, count);
if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL)) @@ -2964,7 +3041,8 @@ int CDECL _setmode(int fd,int mode) { ioinfo *info = get_ioinfo(fd); int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY; - if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16))) + + if(ret==_O_TEXT && ioinfo_get_textmode(info) != TEXTMODE_ANSI) ret = _O_WTEXT;
if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT @@ -2981,18 +3059,18 @@ int CDECL _setmode(int fd,int mode)
if(mode == _O_BINARY) { info->wxflag &= ~WX_TEXT; - info->exflag &= ~(EF_UTF8|EF_UTF16); + ioinfo_set_textmode(info, TEXTMODE_ANSI); release_ioinfo(info); return ret; }
info->wxflag |= WX_TEXT; if(mode == _O_TEXT) - info->exflag &= ~(EF_UTF8|EF_UTF16); + ioinfo_set_textmode(info, TEXTMODE_ANSI); else if(mode == _O_U8TEXT) - info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8; + ioinfo_set_textmode(info, TEXTMODE_UTF8); else - info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16; + ioinfo_set_textmode(info, TEXTMODE_UTF16LE);
release_ioinfo(info); return ret; @@ -3452,7 +3530,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) return -1; }
- if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1) + if (ioinfo_get_textmode(info) != TEXTMODE_ANSI && count&1) { *_errno() = EINVAL; release_ioinfo(info); @@ -3485,7 +3563,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) char lfbuf[2048]; DWORD j = 0;
- if (!(info->exflag & (EF_UTF8|EF_UTF16)) && console) + if (ioinfo_get_textmode(info) == TEXTMODE_ANSI && console) { char conv[sizeof(lfbuf)]; size_t len = 0; @@ -3537,7 +3615,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) } j = len * 2; } - else if (!(info->exflag & (EF_UTF8|EF_UTF16))) + else if (ioinfo_get_textmode(info) == TEXTMODE_ANSI) { for (j = 0; i < count && j < sizeof(lfbuf)-1; i++, j++) { @@ -3546,7 +3624,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) lfbuf[j] = s[i]; } } - else if (info->exflag & EF_UTF16 || console) + else if (ioinfo_get_textmode(info) == TEXTMODE_UTF16LE || console) { for (j = 0; i < count && j < sizeof(lfbuf)-3; i++, j++) { @@ -3827,7 +3905,7 @@ wint_t CDECL _fgetwc_nolock(FILE* file) wint_t ret; int ch;
- if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16)) + if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) { char *p;
@@ -4098,7 +4176,7 @@ wint_t CDECL _fputwc_nolock(wint_t wc, FILE* file)
fdinfo = get_ioinfo_nolock(file->_file);
- if((fdinfo->wxflag&WX_TEXT) && !(fdinfo->exflag&(EF_UTF8|EF_UTF16))) { + if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_ANSI) { char buf[MB_LEN_MAX]; int char_len;
@@ -5611,7 +5689,7 @@ wint_t CDECL _ungetwc_nolock(wint_t wc, FILE * file) if (wc == WEOF) return WEOF;
- if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16)) + if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) { unsigned char * pp = (unsigned char *)&mwc; int i;
Signed-off-by: Piotr Caban piotr@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/msvcr90/tests/msvcr90.c | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+)
diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c index 63a2254d187..5b6a1d08399 100644 --- a/dlls/msvcr90/tests/msvcr90.c +++ b/dlls/msvcr90/tests/msvcr90.c @@ -33,6 +33,33 @@ #include <errno.h> #include "wine/test.h"
+#define WX_OPEN 0x01 +#define WX_ATEOF 0x02 +#define WX_READNL 0x04 +#define WX_PIPE 0x08 +#define WX_DONTINHERIT 0x10 +#define WX_APPEND 0x20 +#define WX_TTY 0x40 +#define WX_TEXT 0x80 + +#define MSVCRT_FD_BLOCK_SIZE 32 + +typedef struct { + HANDLE handle; + unsigned char wxflag; + char lookahead[3]; + int exflag; + CRITICAL_SECTION crit; + char textmode : 7; + char unicode : 1; + char pipech2[2]; + __int64 startpos; + BOOL utf8translations; + char dbcsBuffer; + BOOL dbcsBufferUsed; +} ioinfo; +static ioinfo **__pioinfo; + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
@@ -84,6 +111,9 @@ static int (__cdecl *p_controlfp_s)(unsigned int *, unsigned int, unsigned int); static int (__cdecl *p_tmpfile_s)(FILE**); static int (__cdecl *p_atoflt)(_CRT_FLOAT *, char *); static unsigned int (__cdecl *p_set_abort_behavior)(unsigned int, unsigned int); +static int (__cdecl *p__open)(const char *, int, ...); +static int (__cdecl *p__close)(int); +static intptr_t (__cdecl *p__get_osfhandle)(int); static int (__cdecl *p_sopen_s)(int*, const char*, int, int, int); static int (__cdecl *p_wsopen_s)(int*, const wchar_t*, int, int, int); static void* (__cdecl *p_realloc_crt)(void*, size_t); @@ -362,6 +392,7 @@ static BOOL init(void) ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, "Invalid parameter handler was already set\n");
+ SET(__pioinfo, "__pioinfo"); SET(p_initterm_e, "_initterm_e"); SET(p_encode_pointer, "_encode_pointer"); SET(p_decode_pointer, "_decode_pointer"); @@ -382,6 +413,9 @@ static BOOL init(void) SET(p_set_abort_behavior, "_set_abort_behavior"); SET(p_sopen_s, "_sopen_s"); SET(p_wsopen_s, "_wsopen_s"); + SET(p__open,"_open"); + SET(p__close,"_close"); + SET(p__get_osfhandle, "_get_osfhandle"); SET(p_realloc_crt, "_realloc_crt"); SET(p_malloc, "malloc"); SET(p_free, "free"); @@ -2350,6 +2384,63 @@ static void test__get_current_locale(void) p_setlocale(LC_ALL, "C"); }
+static void test_ioinfo_flags(void) +{ + HANDLE handle; + ioinfo *info; + char *tempf; + int tempfd; + + tempf = _tempnam(".","wne"); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + handle = (HANDLE)p__get_osfhandle(tempfd); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == handle, "Unexpected handle %p, expected %p.\n", info->handle, handle); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + ok(info->unicode, "Unicode is not set.\n"); + ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->unicode, "Unicode is not set.\n"); + ok(!info->wxflag, "Unexpected wxflag %#x.\n", info->wxflag); + ok(info->textmode == 2, "Unexpected textmode %d.\n", info->textmode); + + info = &__pioinfo[(tempfd + 4) / MSVCRT_FD_BLOCK_SIZE][(tempfd + 4) % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->handle == INVALID_HANDLE_VALUE, "Unexpected handle %p.\n", info->handle); + ok(!info->exflag, "Unexpected exflag %#x.\n", info->exflag); + ok(!info->textmode, "Unexpected textmode %d.\n", info->textmode); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_TEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + ok(!info->unicode, "Unicode is not set.\n"); + ok(!info->textmode, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + tempfd = p__open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_U8TEXT, _S_IWRITE); + ok(tempfd != -1, "_open failed with error: %d\n", errno); + info = &__pioinfo[tempfd / MSVCRT_FD_BLOCK_SIZE][tempfd % MSVCRT_FD_BLOCK_SIZE]; + ok(!!info, "NULL info.\n"); + ok(info->exflag == 1, "Unexpected exflag %#x.\n", info->exflag); + ok(info->wxflag == (WX_TEXT | WX_OPEN), "Unexpected wxflag %#x.\n", info->wxflag); + ok(!info->unicode, "Unicode is not set.\n"); + ok(info->textmode == 1, "Unexpected textmode %d.\n", info->textmode); + p__close(tempfd); + + unlink(tempf); + free(tempf); +} + START_TEST(msvcr90) { if(!init()) @@ -2391,4 +2482,5 @@ START_TEST(msvcr90) test_swscanf(); test____mb_cur_max_l_func(); test__get_current_locale(); + test_ioinfo_flags(); }
Signed-off-by: Piotr Caban piotr@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/msvcrt/file.c | 73 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 11 deletions(-)
diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 637cc614fad..13a4088e8b6 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -89,6 +89,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); static char utf8_bom[3] = { 0xef, 0xbb, 0xbf }; static char utf16_bom[2] = { 0xff, 0xfe };
+#define MSVCRT_INTERNAL_BUFSIZ 4096 + enum textmode { TEXTMODE_ANSI, @@ -96,12 +98,33 @@ enum textmode TEXTMODE_UTF16LE, };
-/* FIXME: this should be allocated dynamically */ +#if _MSVCR_VER >= 140 + +#define MSVCRT_MAX_FILES 8192 +#define MSVCRT_FD_BLOCK_SIZE 64 + +typedef struct { + CRITICAL_SECTION crit; + HANDLE handle; + __int64 startpos; + unsigned char wxflag; + char textmode; + char lookahead[3]; + char unicode : 1; + char utf8translations : 1; + char dbcsBufferUsed : 1; + char dbcsBuffer[MB_LEN_MAX]; +} ioinfo; + +/********************************************************************* + * __badioinfo (MSVCRT.@) + */ +ioinfo MSVCRT___badioinfo = { {0}, INVALID_HANDLE_VALUE, 0, WX_TEXT }; +#else + #define MSVCRT_MAX_FILES 2048 #define MSVCRT_FD_BLOCK_SIZE 32
-#define MSVCRT_INTERNAL_BUFSIZ 4096 - typedef struct { HANDLE handle; unsigned char wxflag; @@ -114,23 +137,35 @@ typedef struct { char pipech2[2]; __int64 startpos; BOOL utf8translations; - char dbcsBuffer; + char dbcsBuffer[1]; BOOL dbcsBufferUsed; #endif } ioinfo;
/********************************************************************* - * __pioinfo (MSVCRT.@) - * array of pointers to ioinfo arrays [32] + * __badioinfo (MSVCRT.@) */ -ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 }; +ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT }; +#endif
/********************************************************************* - * __badioinfo (MSVCRT.@) + * __pioinfo (MSVCRT.@) + * array of pointers to ioinfo arrays [32] */ -ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT }; +ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
#if _MSVCR_VER >= 80 + +#if _MSVCR_VER >= 140 +static inline BOOL ioinfo_is_crit_init(ioinfo *info) +{ + return TRUE; +} + +static inline void ioinfo_set_crit_init(ioinfo *info) +{ +} +#else static inline BOOL ioinfo_is_crit_init(ioinfo *info) { return info->exflag & 1; @@ -140,6 +175,7 @@ static inline void ioinfo_set_crit_init(ioinfo *info) { info->exflag |= 1; } +#endif
static inline enum textmode ioinfo_get_textmode(ioinfo *info) { @@ -385,9 +421,24 @@ static inline BOOL alloc_pioinfo_block(int fd) return FALSE; } for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++) + { block[i].handle = INVALID_HANDLE_VALUE; + if (ioinfo_is_crit_init(&block[i])) + { + /* Initialize crit section on block allocation for _MSVC_VER >= 140, + * ioinfo_is_crit_init() is always TRUE. */ + InitializeCriticalSection(&block[i].crit); + } + } if(InterlockedCompareExchangePointer((void**)&MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL)) + { + if (ioinfo_is_crit_init(&block[0])) + { + for(i = 0; i < MSVCRT_FD_BLOCK_SIZE; ++i) + DeleteCriticalSection(&block[i].crit); + } free(block); + } return TRUE; }
@@ -3571,7 +3622,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) #if _MSVCR_VER >= 80 if (info->dbcsBufferUsed) { - conv[j++] = info->dbcsBuffer; + conv[j++] = info->dbcsBuffer[0]; info->dbcsBufferUsed = FALSE; conv[j++] = s[i++]; len++; @@ -3588,7 +3639,7 @@ int CDECL _write(int fd, const void* buf, unsigned int count) if (i == count) { #if _MSVCR_VER >= 80 - info->dbcsBuffer = conv[j-1]; + info->dbcsBuffer[0] = conv[j-1]; info->dbcsBufferUsed = TRUE; break; #else
Signed-off-by: Piotr Caban piotr@codeweavers.com