int *__p__fmode(void);
int *__p___mb_cur_max(void);
+extern int _commode;
+
+#ifndef _IOCOMMIT
+#define _IOCOMMIT 0x4000
+#endif
+
#ifdef feof
#undef feof
#endif
#define WX_NOSEEK 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_UNK_UNICODE 0x08
+
+static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
+static char utf16_bom[2] = { 0xff, 0xfe };
+
/* FIXME: this should be allocated dynamically */
#define MAX_FILES 2048
#define FD_BLOCK_SIZE 64
+#define MSVCRT_INTERNAL_BUFSIZ 4096
+
+/* ioinfo structure size is different in msvcrXX.dll's */
typedef struct {
HANDLE handle;
unsigned char wxflag;
- char unk1;
- BOOL crit_init;
+ char lookahead[3];
+ int exflag;
CRITICAL_SECTION crit;
} ioinfo;
* protection, rather than locking the whole table for every change.
*/
static CRITICAL_SECTION file_cs;
+static CRITICAL_SECTION_DEBUG file_cs_debug =
+{
+ 0, 0, &file_cs,
+ { &file_cs_debug.ProcessLocksList, &file_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": file_cs") }
+};
+static CRITICAL_SECTION file_cs = { &file_cs_debug, -1, 0, 0, 0, 0 };
#define LOCK_FILES() do { EnterCriticalSection(&file_cs); } while (0)
#define UNLOCK_FILES() do { LeaveCriticalSection(&file_cs); } while (0)
/* INTERNAL: Allocate an fd slot from a Win32 HANDLE, starting from fd */
/* caller must hold the files lock */
-static int alloc_fd_from(HANDLE hand, int flag, int fd)
+static int set_fd(HANDLE hand, int flag, int fd)
{
ioinfo *fdinfo;
}
fdinfo->handle = hand;
- fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT));
+ fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_NOSEEK));
+ fdinfo->lookahead[0] = '\n';
+ fdinfo->lookahead[1] = '\n';
+ fdinfo->lookahead[2] = '\n';
+ fdinfo->exflag = 0;
/* locate next free slot */
if (fd == fdstart && fd == fdend)
LOCK_FILES();
TRACE(":handle (%p) allocating fd (%d)\n",hand,fdstart);
- ret = alloc_fd_from(hand, flag, fdstart);
+ ret = set_fd(hand, flag, fdstart);
UNLOCK_FILES();
return ret;
}
*_errno() = EBADF;
return -1;
}
- memset(file, 0, sizeof(*file));
+ file->_ptr = file->_base = NULL;
+ file->_cnt = 0;
file->_file = fd;
file->_flag = stream_flags;
+ file->_tmpfname = NULL;
if(file<_iob || file>=_iob+_IOB_ENTRIES)
InitializeCriticalSection(&((file_crit*)file)->crit);
unsigned int i;
ioinfo *fdinfo;
- InitializeCriticalSection(&file_cs);
- file_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_cs");
GetStartupInfoA(&si);
if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
{
for (i = 0; i < count; i++)
{
if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
- alloc_fd_from(*handle_ptr, *wxflag_ptr, i);
+ set_fd(*handle_ptr, *wxflag_ptr, i);
wxflag_ptr++; handle_ptr++;
}
if (get_ioinfo(fdstart)->handle == INVALID_HANDLE_VALUE) break;
}
- if(!__pioinfo[0])
- alloc_fd_from(INVALID_HANDLE_VALUE, 0, 3);
+ fdinfo = get_ioinfo(STDIN_FILENO);
+ if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
+ HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD type = GetFileType(h);
- fdinfo = get_ioinfo(0);
- if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
- {
- HANDLE std = GetStdHandle(STD_INPUT_HANDLE);
-#ifndef __REACTOS__
- if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
- GetCurrentProcess(), &fdinfo->handle,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
-#else
- fdinfo->handle = std;
-#endif
- fdinfo->wxflag = WX_OPEN | WX_TEXT;
+ set_fd(h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_NOSEEK : 0)
+ |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0), STDIN_FILENO);
}
- fdinfo = get_ioinfo(1);
- if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
- {
- HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);
-#ifndef __REACTOS__
- if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
- GetCurrentProcess(), &fdinfo->handle,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
-#else
- fdinfo->handle = std;
-#endif
- fdinfo->wxflag = WX_OPEN | WX_TEXT;
+ fdinfo = get_ioinfo(STDOUT_FILENO);
+ if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD type = GetFileType(h);
+
+ set_fd(h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_NOSEEK : 0)
+ |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0), STDOUT_FILENO);
}
- fdinfo = get_ioinfo(2);
- if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
- {
- HANDLE std = GetStdHandle(STD_ERROR_HANDLE);
-#ifndef __REACTOS__
- if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
- GetCurrentProcess(), &fdinfo->handle,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
-#else
- fdinfo->handle = std;
-#endif
- fdinfo->wxflag = WX_OPEN | WX_TEXT;
+ fdinfo = get_ioinfo(STDERR_FILENO);
+ if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
+ HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
+ DWORD type = GetFileType(h);
+
+ set_fd(h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_NOSEEK : 0)
+ |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0), STDERR_FILENO);
}
- TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo(0)->handle,
- get_ioinfo(1)->handle, get_ioinfo(2)->handle);
+ TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo(STDIN_FILENO)->handle,
+ get_ioinfo(STDOUT_FILENO)->handle,
+ get_ioinfo(STDERR_FILENO)->handle);
memset(_iob,0,3*sizeof(FILE));
for (i = 0; i < 3; i++)
/* INTERNAL: Flush stdio file buffer */
static int flush_buffer(FILE* file)
{
- if(file->_bufsiz) {
+ if(file->_flag & (_IOMYBUF | _USERBUF)) {
int cnt=file->_ptr-file->_base;
if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
file->_flag |= _IOERR;
return EOF;
}
file->_ptr=file->_base;
- file->_cnt=file->_bufsiz;
+ file->_cnt=0;
}
return 0;
}
+/*********************************************************************
+ * _isatty (MSVCRT.@)
+ */
+int CDECL _isatty(int fd)
+{
+ HANDLE hand = fdtoh(fd);
+
+ TRACE(":fd (%d) handle (%p)\n",fd,hand);
+ if (hand == INVALID_HANDLE_VALUE)
+ return 0;
+
+ return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
+}
+
/* INTERNAL: Allocate stdio file buffer */
-/*static*/ void alloc_buffer(FILE* file)
+/*static*/ BOOL alloc_buffer(FILE* file)
{
- file->_base = calloc(BUFSIZ,1);
- if(file->_base) {
- file->_bufsiz = BUFSIZ;
- file->_flag |= _IOMYBUF;
- } else {
- file->_base = (char*)(&file->_charbuf);
- /* put here 2 ??? */
- file->_bufsiz = sizeof(file->_charbuf);
- }
- file->_ptr = file->_base;
- file->_cnt = 0;
+ if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
+ && _isatty(file->_file))
+ return FALSE;
+
+ file->_base = calloc(MSVCRT_INTERNAL_BUFSIZ,1);
+ if(file->_base) {
+ file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
+ file->_flag |= _IOMYBUF;
+ } else {
+ file->_base = (char*)(&file->_charbuf);
+ file->_bufsiz = 2;
+ file->_flag |= _IONBF;
+ }
+ file->_ptr = file->_base;
+ file->_cnt = 0;
+ return TRUE;
+}
+
+/* INTERNAL: Allocate temporary buffer for stdout and stderr */
+static BOOL add_std_buffer(FILE *file)
+{
+ static char buffers[2][BUFSIZ];
+
+ if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
+ || !_isatty(file->_file) || file->_bufsiz)
+ return FALSE;
+
+ file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
+ file->_bufsiz = file->_cnt = BUFSIZ;
+ return TRUE;
+}
+
+/* INTERNAL: Removes temporary buffer from stdout or stderr */
+/* Only call this function when add_std_buffer returned TRUE */
+static void remove_std_buffer(FILE *file)
+{
+ flush_buffer(file);
+ file->_ptr = file->_base = NULL;
+ file->_bufsiz = file->_cnt = 0;
}
/* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
FILE *file;
LOCK_FILES();
- for (i = 3; i < stream_idx; i++) {
+ for (i = 0; i < stream_idx; i++) {
file = get_file(i);
if (file->_flag)
{
if(file->_flag & mask) {
- fflush(file);
+ fflush(file);
num_flushed++;
}
}
if (is_valid_fd(nd))
_close(nd);
- ret = alloc_fd_from(handle, wxflag, nd);
+ ret = set_fd(handle, wxflag, nd);
if (ret == -1)
{
CloseHandle(handle);
/* free everything on process exit */
void msvcrt_free_io(void)
{
- int i;
+ unsigned int i;
+ int j;
+ _flushall();
_fcloseall();
- /* The Win32 _fcloseall() function explicitly doesn't close stdin,
- * stdout, and stderr (unlike GNU), so we need to fclose() them here
- * or they won't get flushed.
- */
- fclose(&_iob[0]);
- fclose(&_iob[1]);
- fclose(&_iob[2]);
for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
free(__pioinfo[i]);
+ for(j=0; j<stream_idx; j++)
+ {
+ FILE *file = get_file(j);
+ if(file<_iob || file>=_iob+_IOB_ENTRIES)
+ {
+ ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&((file_crit*)file)->crit);
+ }
+ }
+
for(i=0; i<sizeof(fstream)/sizeof(fstream[0]); i++)
free(fstream[i]);
- file_cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&file_cs);
}
flush_buffer(file);
if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
- offset -= file->_cnt;
- if (get_ioinfo(file->_file)->wxflag & WX_TEXT) {
- /* Black magic correction for CR removal */
- int i;
- for (i=0; i<file->_cnt; i++) {
- if (file->_ptr[i] == '\n')
- offset--;
- }
- /* Black magic when reading CR at buffer boundary*/
- if(get_ioinfo(file->_file)->wxflag & WX_READCR)
- offset--;
- }
+ whence = SEEK_SET;
+ offset += _ftelli64(file);
}
+
/* Discard buffered input */
file->_cnt = 0;
file->_ptr = file->_base;
}
/*********************************************************************
- * _chsize (MSVCRT.@)
+ * _chsize_s (MSVCRT.@)
*/
-int CDECL _chsize(int fd, long size)
+int CDECL _chsize_s(int fd, __int64 size)
{
- LONG cur, pos;
+ __int64 cur, pos;
HANDLE handle;
BOOL ret = FALSE;
- TRACE("(fd=%d, size=%d)\n", fd, size);
+ TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size));
+
+ if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
LOCK_FILES();
if (handle != INVALID_HANDLE_VALUE)
{
/* save the current file pointer */
- cur = _lseek(fd, 0, SEEK_CUR);
+ cur = _lseeki64(fd, 0, SEEK_CUR);
if (cur >= 0)
{
- pos = _lseek(fd, size, SEEK_SET);
+ pos = _lseeki64(fd, size, SEEK_SET);
if (pos >= 0)
{
ret = SetEndOfFile(handle);
}
/* restore the file pointer */
- _lseek(fd, cur, SEEK_SET);
+ _lseeki64(fd, cur, SEEK_SET);
}
}
UNLOCK_FILES();
- return ret ? 0 : -1;
+ return ret ? 0 : *_errno();
+}
+
+/*********************************************************************
+ * _chsize (MSVCRT.@)
+ */
+int CDECL _chsize(int fd, long size)
+{
+ /* _chsize_s returns errno on failure but _chsize should return -1 */
+ return _chsize_s( fd, size ) == 0 ? 0 : -1;
}
/*********************************************************************
{
int plus = strchrW(mode, '+') != NULL;
+ TRACE("%s\n", debugstr_w(mode));
+
+ while(*mode == ' ') mode++;
+
switch(*mode++)
{
case 'R': case 'r':
*stream_flags = plus ? _IORW : _IOWRT;
break;
default:
- _invalid_parameter(NULL, NULL, NULL, 0, 0);
- *_errno() = EINVAL;
+ MSVCRT_INVALID_PMT(0, EINVAL);
return -1;
}
- while (*mode)
+ *stream_flags |= _commode;
+
+ while (*mode && *mode!=',')
switch (*mode++)
{
case 'B': case 'b':
*open_flags |= _O_TEXT;
*open_flags &= ~_O_BINARY;
break;
+ case 'D':
+ *open_flags |= _O_TEMPORARY;
+ break;
+ case 'T':
+ *open_flags |= _O_SHORT_LIVED;
+ break;
+ case 'c':
+ *stream_flags |= _IOCOMMIT;
+ break;
+ case 'n':
+ *stream_flags &= ~_IOCOMMIT;
+ break;
+ case 'N':
+ *open_flags |= _O_NOINHERIT;
+ break;
case '+':
case ' ':
+ case 'a':
+ case 'w':
+ break;
+ case 'S':
+ case 'R':
+ FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
break;
default:
- FIXME(":unknown flag %c not supported\n",mode[-1]);
+ ERR("incorrect mode flag: %c\n", mode[-1]);
+ break;
+ }
+
+ if(*mode == ',')
+ {
+ static const WCHAR ccs[] = {'c','c','s'};
+ static const WCHAR utf8[] = {'u','t','f','-','8'};
+ static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
+ static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
+
+ mode++;
+ while(*mode == ' ') mode++;
+ if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
+ return -1;
+ mode += sizeof(ccs)/sizeof(ccs[0]);
+ while(*mode == ' ') mode++;
+ if(!MSVCRT_CHECK_PMT(*mode == '='))
+ return -1;
+ mode++;
+ while(*mode == ' ') mode++;
+
+ if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
+ {
+ *open_flags |= _O_U8TEXT;
+ mode += sizeof(utf8)/sizeof(utf8[0]);
+ }
+ else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
+ {
+ *open_flags |= _O_U16TEXT;
+ mode += sizeof(utf16le)/sizeof(utf16le[0]);
+ }
+ else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
+ {
+ *open_flags |= _O_WTEXT;
+ mode += sizeof(unicode)/sizeof(unicode[0]);
+ }
+ else
+ {
+ MSVCRT_INVALID_PMT(0, EINVAL);
+ return -1;
}
+
+ while(*mode == ' ') mode++;
+ }
+
+ if(!MSVCRT_CHECK_PMT(*mode == 0))
+ return -1;
return 0;
}
return (intptr_t)hand;
}
-/*********************************************************************
- * _isatty (MSVCRT.@)
- */
-int CDECL _isatty(int fd)
-{
- HANDLE hand = fdtoh(fd);
-
- TRACE(":fd (%d) handle (%p)\n",fd,hand);
- if (hand == INVALID_HANDLE_VALUE)
- return 0;
-
- return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
-}
-
/*********************************************************************
* _mktemp (MSVCRT.@)
*/
if (oflags & _O_APPEND) wxflags |= WX_APPEND;
if (oflags & _O_BINARY) {/* Nothing to do */}
else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
+ else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
+ else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
+ else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */}
else wxflags |= WX_TEXT; /* default to TEXT*/
if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
_O_TRUNC|_O_EXCL|_O_CREAT|
_O_RDWR|_O_WRONLY|_O_TEMPORARY|
_O_NOINHERIT|
- _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED
+ _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
+ _O_WTEXT|_O_U16TEXT|_O_U8TEXT
)))
ERR(":unsupported oflags 0x%04x\n",unsupp);
return ret;
}
+static int check_bom(HANDLE h, int oflags, BOOL seek)
+{
+ char bom[sizeof(utf8_bom)];
+ DWORD r;
+
+ oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
+
+ if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
+ return oflags;
+
+ if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
+ oflags |= _O_U8TEXT;
+ }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
+ if (seek && r>2)
+ SetFilePointer(h, 2, NULL, FILE_BEGIN);
+ oflags |= _O_U16TEXT;
+ }else if (seek) {
+ SetFilePointer(h, 0, NULL, FILE_BEGIN);
+ }
+
+ return oflags;
+}
+
/*********************************************************************
- * _sopen_s (MSVCRT.@)
+ * _wsopen_s (MSVCRT.@)
*/
-int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
+int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
{
DWORD access = 0, creation = 0, attrib;
+ SECURITY_ATTRIBUTES sa;
DWORD sharing;
int wxflag;
HANDLE hand;
- SECURITY_ATTRIBUTES sa;
- TRACE("fd*: %p file: (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
- fd, path, oflags, shflags, pmode);
+ TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
+ fd, debugstr_w(path), oflags, shflags, pmode);
- if (!fd)
- {
- MSVCRT_INVALID_PMT("null out fd pointer", EINVAL);
- return EINVAL;
- }
+ if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
*fd = -1;
wxflag = split_oflags(oflags);
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
+ sa.bInheritHandle = !(oflags & _O_NOINHERIT);
+
+ if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
+ && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
+ && !(access&GENERIC_READ))
+ {
+ hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hand != INVALID_HANDLE_VALUE)
+ {
+ oflags = check_bom(hand, oflags, FALSE);
+ CloseHandle(hand);
+ }
+ else
+ oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
+ }
- hand = CreateFileA(path, access, sharing, &sa, creation, attrib, 0);
+ hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
if (hand == INVALID_HANDLE_VALUE) {
- WARN(":failed-last error (%d)\n", GetLastError());
+ WARN(":failed-last error (%d)\n",GetLastError());
_dosmaperr(GetLastError());
return *_errno();
}
+ if (oflags & (_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
+ {
+ if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
+ || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
+ || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
+ {
+ if (oflags & _O_U8TEXT)
+ {
+ DWORD written = 0, tmp;
+
+ while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
+ sizeof(utf8_bom)-written, &tmp, NULL))
+ written += tmp;
+ if (written != sizeof(utf8_bom)) {
+ WARN("error writing BOM\n");
+ CloseHandle(hand);
+ _dosmaperr(GetLastError());
+ return *_errno();
+ }
+ }
+ else
+ {
+ DWORD written = 0, tmp;
+
+ while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
+ sizeof(utf16_bom)-written, &tmp, NULL))
+ written += tmp;
+ if (written != sizeof(utf16_bom))
+ {
+ WARN("error writing BOM\n");
+ CloseHandle(hand);
+ _dosmaperr(GetLastError());
+ return *_errno();
+ }
+ }
+ }
+ else if (access & GENERIC_READ)
+ oflags = check_bom(hand, oflags, TRUE);
+ }
+
*fd = alloc_fd(hand, wxflag);
+ if (*fd == -1)
+ return *_errno();
+
+ if (oflags & _O_WTEXT)
+ get_ioinfo(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
+ else if (oflags & _O_U16TEXT)
+ get_ioinfo(*fd)->exflag |= EF_UTF16;
+ else if (oflags & _O_U8TEXT)
+ get_ioinfo(*fd)->exflag |= EF_UTF8;
TRACE(":fd (%d) handle (%p)\n", *fd, hand);
return 0;
}
/*********************************************************************
- * _sopen (MSVCRT.@)
+ * _wsopen (MSVCRT.@)
*/
-int CDECL _sopen( const char *path, int oflags, int shflags, ... )
+int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
{
int pmode;
int fd;
if (oflags & _O_CREAT)
{
- va_list ap;
+ __ms_va_list ap;
- va_start(ap, shflags);
+ __ms_va_start(ap, shflags);
pmode = va_arg(ap, int);
- va_end(ap);
+ __ms_va_end(ap);
}
else
pmode = 0;
- _sopen_s(&fd, path, oflags, shflags, pmode);
+ _wsopen_s(&fd, path, oflags, shflags, pmode);
return fd;
}
/*********************************************************************
- * _wsopen_s (MSVCRT.@)
+ * _sopen_s (MSVCRT.@)
*/
-int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
+int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
{
- DWORD access = 0, creation = 0, attrib;
- SECURITY_ATTRIBUTES sa;
- DWORD sharing;
- int wxflag;
- HANDLE hand;
-
- TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
- fd, debugstr_w(path), oflags, shflags, pmode);
-
- if (!fd)
- {
- MSVCRT_INVALID_PMT("null out fd pointer", EINVAL);
- return EINVAL;
- }
-
- *fd = -1;
- wxflag = split_oflags(oflags);
- switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
- {
- case _O_RDONLY: access |= GENERIC_READ; break;
- case _O_WRONLY: access |= GENERIC_WRITE; break;
- case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
- }
-
- if (oflags & _O_CREAT)
- {
- if(pmode & ~(_S_IREAD | _S_IWRITE))
- FIXME(": pmode 0x%04x ignored\n", pmode);
- else
- WARN(": pmode 0x%04x ignored\n", pmode);
-
- if (oflags & _O_EXCL)
- creation = CREATE_NEW;
- else if (oflags & _O_TRUNC)
- creation = CREATE_ALWAYS;
- else
- creation = OPEN_ALWAYS;
- }
- else /* no _O_CREAT */
- {
- if (oflags & _O_TRUNC)
- creation = TRUNCATE_EXISTING;
- else
- creation = OPEN_EXISTING;
- }
-
- switch( shflags )
- {
- case _SH_DENYRW:
- sharing = 0L;
- break;
- case _SH_DENYWR:
- sharing = FILE_SHARE_READ;
- break;
- case _SH_DENYRD:
- sharing = FILE_SHARE_WRITE;
- break;
- case _SH_DENYNO:
- sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
- break;
- default:
- ERR( "Unhandled shflags 0x%x\n", shflags );
- return EINVAL;
- }
- attrib = FILE_ATTRIBUTE_NORMAL;
-
- if (oflags & _O_TEMPORARY)
- {
- attrib |= FILE_FLAG_DELETE_ON_CLOSE;
- access |= DELETE;
- sharing |= FILE_SHARE_DELETE;
- }
-
- sa.nLength = sizeof( SECURITY_ATTRIBUTES );
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
-
- hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
-
- if (hand == INVALID_HANDLE_VALUE) {
- WARN(":failed-last error (%d)\n",GetLastError());
- _dosmaperr(GetLastError());
- return *_errno();
- }
+ wchar_t *pathW;
+ int ret;
- *fd = alloc_fd(hand, wxflag);
+ if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
+ return EINVAL;
- TRACE(":fd (%d) handle (%p)\n", *fd, hand);
- return 0;
+ ret = _wsopen_s(fd, pathW, oflags, shflags, pmode);
+ free(pathW);
+ return ret;
}
/*********************************************************************
- * _wsopen (MSVCRT.@)
+ * _sopen (MSVCRT.@)
*/
-int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
+int CDECL _sopen( const char *path, int oflags, int shflags, ... )
{
int pmode;
int fd;
else
pmode = 0;
- _wsopen_s(&fd, path, oflags, shflags, pmode);
+ _sopen_s(&fd, path, oflags, shflags, pmode);
return fd;
}
return num_removed;
}
-/*********************************************************************
+static inline int get_utf8_char_len(char ch)
+{
+ if((ch&0xf8) == 0xf0)
+ return 4;
+ else if((ch&0xf0) == 0xe0)
+ return 3;
+ else if((ch&0xe0) == 0xc0)
+ return 2;
+ return 1;
+}
+
+/*********************************************************************
+ * (internal) read_utf8
+ */
+static int read_utf8(int fd, wchar_t *buf, unsigned int count)
+{
+ ioinfo *fdinfo = get_ioinfo(fd);
+ HANDLE hand = fdinfo->handle;
+ char min_buf[4], *readbuf, lookahead;
+ DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
+
+ /* make the buffer big enough to hold at least one character */
+ /* read bytes have to fit to output and lookahead buffers */
+ count /= 2;
+ readbuf_size = count < 4 ? 4 : count;
+ if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
+ readbuf_size = 4;
+ readbuf = min_buf;
+ }
+
+ if(fdinfo->lookahead[0] != '\n') {
+ readbuf[pos++] = fdinfo->lookahead[0];
+ fdinfo->lookahead[0] = '\n';
+
+ if(fdinfo->lookahead[1] != '\n') {
+ readbuf[pos++] = fdinfo->lookahead[1];
+ fdinfo->lookahead[1] = '\n';
+
+ if(fdinfo->lookahead[2] != '\n') {
+ readbuf[pos++] = fdinfo->lookahead[2];
+ fdinfo->lookahead[2] = '\n';
+ }
+ }
+ }
+
+ /* NOTE: this case is broken in native dll, reading
+ * sometimes fails when small buffer is passed
+ */
+ if(count < 4) {
+ if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
+ if (GetLastError() == ERROR_BROKEN_PIPE) {
+ fdinfo->wxflag |= WX_ATEOF;
+ return 0;
+ }else {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+ }else if(!num_read) {
+ fdinfo->wxflag |= WX_ATEOF;
+ return 0;
+ }else {
+ pos++;
+ }
+
+ char_len = get_utf8_char_len(readbuf[0]);
+ if(char_len>pos) {
+ if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
+ pos += num_read;
+ }
+
+ if(readbuf[0] == '\n')
+ fdinfo->wxflag |= WX_READNL;
+ else
+ fdinfo->wxflag &= ~WX_READNL;
+
+ if(readbuf[0] == 0x1a) {
+ fdinfo->wxflag |= WX_ATEOF;
+ return 0;
+ }
+
+ if(readbuf[0] == '\r') {
+ if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
+ buf[0] = '\r';
+ else if(lookahead == '\n')
+ buf[0] = '\n';
+ else {
+ buf[0] = '\r';
+ if(fdinfo->wxflag & (WX_PIPE | WX_NOSEEK))
+ fdinfo->lookahead[0] = lookahead;
+ else
+ SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
+ }
+ return 2;
+ }
+
+ if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
+ _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ return num_read*2;
+ }
+
+ if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
+ if(pos) {
+ num_read = 0;
+ }else if(GetLastError() == ERROR_BROKEN_PIPE) {
+ fdinfo->wxflag |= WX_ATEOF;
+ if (readbuf != min_buf) free(readbuf);
+ return 0;
+ }else {
+ _dosmaperr(GetLastError());
+ if (readbuf != min_buf) free(readbuf);
+ return -1;
+ }
+ }else if(!pos && !num_read) {
+ fdinfo->wxflag |= WX_ATEOF;
+ if (readbuf != min_buf) free(readbuf);
+ return 0;
+ }
+
+ pos += num_read;
+ if(readbuf[0] == '\n')
+ fdinfo->wxflag |= WX_READNL;
+ else
+ fdinfo->wxflag &= ~WX_READNL;
+
+ /* Find first byte of last character (may be incomplete) */
+ for(i=pos-1; i>0 && i>pos-4; i--)
+ if((readbuf[i]&0xc0) != 0x80)
+ break;
+ char_len = get_utf8_char_len(readbuf[i]);
+ if(char_len+i <= pos)
+ i += char_len;
+
+ if(fdinfo->wxflag & (WX_PIPE | WX_NOSEEK)) {
+ if(i < pos)
+ fdinfo->lookahead[0] = readbuf[i];
+ if(i+1 < pos)
+ fdinfo->lookahead[1] = readbuf[i+1];
+ if(i+2 < pos)
+ fdinfo->lookahead[2] = readbuf[i+2];
+ }else if(i < pos) {
+ SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
+ }
+ pos = i;
+
+ for(i=0, j=0; i<pos; i++) {
+ if(readbuf[i] == 0x1a) {
+ fdinfo->wxflag |= WX_ATEOF;
+ break;
+ }
+
+ /* strip '\r' if followed by '\n' */
+ if(readbuf[i] == '\r' && i+1==pos) {
+ if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
+ readbuf[j++] = '\r';
+ }else if(lookahead == '\n' && j==0) {
+ readbuf[j++] = '\n';
+ }else {
+ if(lookahead != '\n')
+ readbuf[j++] = '\r';
+
+ if(fdinfo->wxflag & (WX_PIPE | WX_NOSEEK))
+ fdinfo->lookahead[0] = lookahead;
+ else
+ SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
+ }
+ }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
+ readbuf[j++] = readbuf[i];
+ }
+ }
+ pos = j;
+
+ if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
+ _dosmaperr(GetLastError());
+ if (readbuf != min_buf) free(readbuf);
+ return -1;
+ }
+
+ if (readbuf != min_buf) free(readbuf);
+ return num_read*2;
+}
+
+/*********************************************************************
* (internal) read_i
*
* When reading \r as last character in text mode, read() positions
*/
static int read_i(int fd, void *buf, unsigned int count)
{
- DWORD num_read;
- char *bufstart = buf;
- HANDLE hand = fdtoh(fd);
- ioinfo *fdinfo = get_ioinfo(fd);
+ DWORD num_read, utf16;
+ char *bufstart = buf;
+ HANDLE hand = fdtoh(fd);
+ ioinfo *fdinfo = get_ioinfo(fd);
- if (count == 0)
- return 0;
+ if (count == 0)
+ return 0;
- if (fdinfo->wxflag & WX_READEOF) {
- fdinfo->wxflag |= WX_ATEOF;
- TRACE("already at EOF, returning 0\n");
- return 0;
- }
- /* Don't trace small reads, it gets *very* annoying */
- if (count > 4)
- TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
- if (hand == INVALID_HANDLE_VALUE)
- return -1;
+ if (fdinfo->wxflag & WX_ATEOF) {
+ TRACE("already at EOF, returning 0\n");
+ return 0;
+ }
+ /* Don't trace small reads, it gets *very* annoying */
+ if (count > 4)
+ TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
+ if (hand == INVALID_HANDLE_VALUE)
+ {
+ *_errno() = EBADF;
+ return -1;
+ }
- /* Reading single bytes in O_TEXT mode makes things slow
- * So read big chunks
- */
- if (ReadFile(hand, bufstart, count, &num_read, NULL))
+ utf16 = (fdinfo->exflag & EF_UTF16) != 0;
+ if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
{
+ *_errno() = EINVAL;
+ return -1;
+ }
+
+ if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
+ return read_utf8(fd, buf, count);
+
+ if (fdinfo->lookahead[0]!='\n' || ReadFile(hand, bufstart, count, &num_read, NULL))
+ {
+ if (fdinfo->lookahead[0] != '\n')
+ {
+ bufstart[0] = fdinfo->lookahead[0];
+ fdinfo->lookahead[0] = '\n';
+
+ if (utf16)
+ {
+ bufstart[1] = fdinfo->lookahead[1];
+ fdinfo->lookahead[1] = '\n';
+ }
+
+ if(count>1+utf16 && ReadFile(hand, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
+ num_read += 1+utf16;
+ else
+ num_read = 1+utf16;
+ }
+
+ if(utf16 && (num_read&1))
+ {
+ /* msvcr90 uses uninitialized value from the buffer in this case */
+ /* msvcrt ignores additional data */
+ ERR("got odd number of bytes in UTF16 mode\n");
+ num_read--;
+ }
+
if (count != 0 && num_read == 0)
{
- fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
+ fdinfo->wxflag |= WX_ATEOF;
TRACE(":EOF %s\n",debugstr_an(buf,num_read));
}
else if (fdinfo->wxflag & WX_TEXT)
{
DWORD i, j;
- if (bufstart[num_read-1] == '\r')
+
+ if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
+ fdinfo->wxflag |= WX_READNL;
+ else
+ fdinfo->wxflag &= ~WX_READNL;
+
+ for (i=0, j=0; i<num_read; i+=1+utf16)
{
- if(count == 1)
+ /* in text mode, a ctrl-z signals EOF */
+ if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
{
- fdinfo->wxflag &= ~WX_READCR;
- ReadFile(hand, bufstart, 1, &num_read, NULL);
+ fdinfo->wxflag |= WX_ATEOF;
+ TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
+ break;
}
- else
+
+ /* in text mode, strip \r if followed by \n */
+ if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
{
- fdinfo->wxflag |= WX_READCR;
- num_read--;
+ char lookahead[2];
+ DWORD len;
+
+ lookahead[1] = '\n';
+ if (ReadFile(hand, lookahead, 1+utf16, &len, NULL) && len)
+ {
+ if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
+ {
+ bufstart[j++] = '\n';
+ if(utf16) bufstart[j++] = 0;
+ }
+ else
+ {
+ if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
+ {
+ bufstart[j++] = '\r';
+ if(utf16) bufstart[j++] = 0;
+ }
+
+ if (fdinfo->wxflag & (WX_PIPE | WX_NOSEEK))
+ {
+ if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
+ {
+ bufstart[j++] = '\n';
+ if (utf16) bufstart[j++] = 0;
+ }
+ else
+ {
+ fdinfo->lookahead[0] = lookahead[0];
+ fdinfo->lookahead[1] = lookahead[1];
+ }
+ }
+ else
+ SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
+ }
+ }
+ else
+ {
+ bufstart[j++] = '\r';
+ if(utf16) bufstart[j++] = 0;
+ }
}
- }
- else
- fdinfo->wxflag &= ~WX_READCR;
- for (i=0, j=0; i<num_read; i++)
- {
- /* in text mode, a ctrl-z signals EOF */
- if (bufstart[i] == 0x1a)
+ else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
+ || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
{
- fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
- TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
- break;
+ bufstart[j++] = bufstart[i];
+ if(utf16) bufstart[j++] = bufstart[i+1];
}
- /* in text mode, strip \r if followed by \n.
- * BUG: should save state across calls somehow, so CR LF that
- * straddles buffer boundary gets recognized properly?
- */
- if ((bufstart[i] != '\r')
- || ((i+1) < num_read && bufstart[i+1] != '\n'))
- bufstart[j++] = bufstart[i];
}
num_read = j;
}
if (GetLastError() == ERROR_BROKEN_PIPE)
{
TRACE(":end-of-pipe\n");
- fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
+ fdinfo->wxflag |= WX_ATEOF;
return 0;
}
else
}
}
- if (count > 4)
- TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
- return num_read;
+ if (count > 4)
+ TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
+ return num_read;
}
/*********************************************************************
*/
int CDECL _setmode(int fd,int mode)
{
- int ret = get_ioinfo(fd)->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
- if (mode & (~(_O_TEXT|_O_BINARY)))
- FIXME("fd (%d) mode (0x%08x) unknown\n",fd,mode);
- if ((mode & _O_TEXT) == _O_TEXT)
+ int ret = get_ioinfo(fd)->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
+ if(ret==_O_TEXT && (get_ioinfo(fd)->exflag & (EF_UTF8|EF_UTF16)))
+ ret = _O_WTEXT;
+
+ if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
+ && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
+ *_errno() = EINVAL;
+ return -1;
+ }
+
+ if(mode == _O_BINARY) {
+ get_ioinfo(fd)->wxflag &= ~WX_TEXT;
+ get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
+ return ret;
+ }
+
get_ioinfo(fd)->wxflag |= WX_TEXT;
- else
- get_ioinfo(fd)->wxflag &= ~WX_TEXT;
- return ret;
+ if(mode == _O_TEXT)
+ get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
+ else if(mode == _O_U8TEXT)
+ get_ioinfo(fd)->exflag = (get_ioinfo(fd)->exflag & ~EF_UTF16) | EF_UTF8;
+ else
+ get_ioinfo(fd)->exflag = (get_ioinfo(fd)->exflag & ~EF_UTF8) | EF_UTF16;
+
+ return ret;
+
}
/*********************************************************************
*/
int CDECL _write(int fd, const void* buf, unsigned int count)
{
- DWORD num_written;
- HANDLE hand = fdtoh(fd);
+ DWORD num_written;
+ ioinfo *info = get_ioinfo(fd);
+ HANDLE hand = info->handle;
- /* Don't trace small writes, it gets *very* annoying */
+ /* Don't trace small writes, it gets *very* annoying */
#if 0
- if (count > 32)
- TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
+ if (count > 32)
+ TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
#endif
- if (hand == INVALID_HANDLE_VALUE)
+ if (hand == INVALID_HANDLE_VALUE)
{
- *_errno() = EBADF;
- return -1;
+ *_errno() = EBADF;
+ return -1;
}
- /* If appending, go to EOF */
- if (get_ioinfo(fd)->wxflag & WX_APPEND)
- _lseek(fd, 0, FILE_END);
+ if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
+ {
+ *_errno() = EINVAL;
+ return -1;
+ }
- if (!(get_ioinfo(fd)->wxflag & WX_TEXT))
+ /* If appending, go to EOF */
+ if (info->wxflag & WX_APPEND)
+ _lseek(fd, 0, FILE_END);
+
+ if (!(info->wxflag & WX_TEXT))
{
- if (WriteFile(hand, buf, count, &num_written, NULL)
- && (num_written == count))
- return num_written;
- TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
- hand, GetLastError());
- *_errno() = ENOSPC;
+ if (WriteFile(hand, buf, count, &num_written, NULL)
+ && (num_written == count))
+ return num_written;
+ TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
+ hand, GetLastError());
+ *_errno() = ENOSPC;
}
- else
- {
- unsigned int i, j, nr_lf;
- char *p = NULL;
- const char *q;
- const char *s = buf, *buf_start = buf;
- /* find number of \n ( without preceding \r ) */
- for ( nr_lf=0,i = 0; i <count; i++)
- {
- if (s[i]== '\n')
- {
- nr_lf++;
- /*if ((i >1) && (s[i-1] == '\r')) nr_lf--; */
- }
- }
- if (nr_lf)
- {
- if ((q = p = malloc(count + nr_lf)))
- {
- for (s = buf, i = 0, j = 0; i < count; i++)
- {
- if (s[i]== '\n')
- {
- p[j++] = '\r';
- /*if ((i >1) && (s[i-1] == '\r'))j--;*/
- }
- p[j++] = s[i];
- }
- }
- else
- {
- FIXME("Malloc failed\n");
- nr_lf =0;
- q = buf;
- }
- }
- else
- q = buf;
+ else
+ {
+ unsigned int i, j, nr_lf, size;
+ char *p = NULL;
+ const char *q;
+ const char *s = buf, *buf_start = buf;
- if ((WriteFile(hand, q, count+nr_lf, &num_written, NULL) == 0 ) || (num_written != count+nr_lf))
- {
- TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
- fd, hand, GetLastError(), num_written);
- *_errno() = ENOSPC;
- if(nr_lf)
- free(p);
- return s - buf_start;
- }
- else
- {
- if(nr_lf)
- free(p);
- return count;
- }
- }
- return -1;
+ if (!(info->exflag & (EF_UTF8|EF_UTF16)))
+ {
+ /* find number of \n */
+ for (nr_lf=0, i=0; i<count; i++)
+ if (s[i] == '\n')
+ nr_lf++;
+ if (nr_lf)
+ {
+ size = count+nr_lf;
+ if ((q = p = malloc(size)))
+ {
+ for (s = buf, i = 0, j = 0; i < count; i++)
+ {
+ if (s[i] == '\n')
+ p[j++] = '\r';
+ p[j++] = s[i];
+ }
+ }
+ else
+ {
+ FIXME("Malloc failed\n");
+ nr_lf = 0;
+ size = count;
+ q = buf;
+ }
+ }
+ else
+ {
+ size = count;
+ q = buf;
+ }
+ }
+ else if (info->exflag & EF_UTF16)
+ {
+ for (nr_lf=0, i=0; i<count; i+=2)
+ if (s[i]=='\n' && s[i+1]==0)
+ nr_lf += 2;
+ if (nr_lf)
+ {
+ size = count+nr_lf;
+ if ((q = p = malloc(size)))
+ {
+ for (s=buf, i=0, j=0; i<count; i++)
+ {
+ if (s[i]=='\n' && s[i+1]==0)
+ {
+ p[j++] = '\r';
+ p[j++] = 0;
+ }
+ p[j++] = s[i++];
+ p[j++] = s[i];
+ }
+ }
+ else
+ {
+ FIXME("Malloc failed\n");
+ nr_lf = 0;
+ size = count;
+ q = buf;
+ }
+ }
+ else
+ {
+ size = count;
+ q = buf;
+ }
+ }
+ else
+ {
+ DWORD conv_len;
+
+ for(nr_lf=0, i=0; i<count; i+=2)
+ if (s[i]=='\n' && s[i+1]==0)
+ nr_lf++;
+
+ conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
+ if(!conv_len) {
+ _dosmaperr(GetLastError());
+ free(p);
+ return -1;
+ }
+
+ size = conv_len+nr_lf;
+ if((p = malloc(count+nr_lf*2+size)))
+ {
+ for (s=buf, i=0, j=0; i<count; i++)
+ {
+ if (s[i]=='\n' && s[i+1]==0)
+ {
+ p[j++] = '\r';
+ p[j++] = 0;
+ }
+ p[j++] = s[i++];
+ p[j++] = s[i];
+ }
+ q = p+count+nr_lf*2;
+ WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
+ p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
+ }
+ else
+ {
+ FIXME("Malloc failed\n");
+ nr_lf = 0;
+ size = count;
+ q = buf;
+ }
+ }
+
+ if (!WriteFile(hand, q, size, &num_written, NULL))
+ num_written = -1;
+ if(p)
+ free(p);
+ if (num_written != size)
+ {
+ TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
+ fd, hand, GetLastError(), num_written);
+ *_errno() = ENOSPC;
+ return s - buf_start;
+ }
+ return count;
+ }
+
+ return -1;
}
/*********************************************************************
}
/* Allocate buffer if needed */
- if(file->_bufsiz == 0 && !(file->_flag & _IONBF))
+ if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
alloc_buffer(file);
if(!(file->_flag & _IOREAD)) {
}
}
- if(file->_flag & _IONBF) {
+ if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
int r;
if ((r = read_i(file->_file,&c,1)) != 1) {
file->_flag |= (r == 0) ? _IOEOF : _IOERR;
/*********************************************************************
* fgetwc (MSVCRT.@)
- *
- * In _O_TEXT mode, multibyte characters are read from the file, dropping
- * the CR from CR/LF combinations
*/
wint_t CDECL fgetwc(FILE* file)
{
- int c;
+ wint_t ret;
+ int ch;
- _lock_file(file);
- if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT))
- {
- wchar_t wc;
- unsigned int i;
- int j;
- char *chp, *wcp;
- wcp = (char *)&wc;
- for(i=0; i<sizeof(wc); i++)
- {
- if (file->_cnt>0)
- {
- file->_cnt--;
- chp = file->_ptr++;
- wcp[i] = *chp;
- }
- else
- {
- j = _filbuf(file);
- if(file->_cnt<=0)
- {
- file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
- file->_cnt = 0;
+ _lock_file(file);
- _unlock_file(file);
- return WEOF;
- }
- wcp[i] = j;
- }
- }
+ if((get_ioinfo(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
+ || !(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
+ char *p;
- _unlock_file(file);
- return wc;
- }
+ for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
+ ch = fgetc(file);
+ if(ch == EOF) {
+ ret = WEOF;
+ break;
+ }
+ *p = (char)ch;
+ }
+ }else {
+ char mbs[MB_LEN_MAX];
+ int len = 0;
+
+ ch = fgetc(file);
+ if(ch != EOF) {
+ mbs[0] = (char)ch;
+ if(isleadbyte((unsigned char)mbs[0])) {
+ ch = fgetc(file);
+ if(ch != EOF) {
+ mbs[1] = (char)ch;
+ len = 2;
+ }
+ }else {
+ len = 1;
+ }
+ }
- c = fgetc(file);
- if ((__mb_cur_max > 1) && isleadbyte(c))
- {
- FIXME("Treat Multibyte characters\n");
+ if(!len || mbtowc(&ret, mbs, len)==-1)
+ ret = WEOF;
}
- _unlock_file(file);
- if (c == EOF)
- return WEOF;
- else
- return (wint_t)c;
+ _unlock_file(file);
+ return ret;
}
/*********************************************************************
return 0;
_lock_file(file);
- if(file->_cnt) {
- int pcnt=((unsigned)file->_cnt>wrcnt)? wrcnt: file->_cnt;
- memcpy(file->_ptr, ptr, pcnt);
- file->_cnt -= pcnt;
- file->_ptr += pcnt;
- written = pcnt;
- wrcnt -= pcnt;
- ptr = (const char*)ptr + pcnt;
- } else if(!(file->_flag & _IOWRT)) {
- if(file->_flag & _IORW) {
- file->_flag |= _IOWRT;
- } else {
- _unlock_file(file);
- return 0;
- }
- }
- if(wrcnt) {
- /* Flush buffer */
- int res=flush_buffer(file);
- if(!res) {
- int pwritten = _write(file->_file, ptr, wrcnt);
- if (pwritten <= 0)
- {
+
+ while(wrcnt) {
+ if(file->_cnt) {
+ int pcnt=((unsigned)file->_cnt>wrcnt)? wrcnt: file->_cnt;
+ memcpy(file->_ptr, ptr, pcnt);
+ file->_cnt -= pcnt;
+ file->_ptr += pcnt;
+ written += pcnt;
+ wrcnt -= pcnt;
+ ptr = (const char*)ptr + pcnt;
+ } else if(!file->_bufsiz && (file->_flag & _IONBF)) {
+ if(!(file->_flag & _IOWRT)) {
+ if(file->_flag & _IORW)
+ file->_flag |= _IOWRT;
+ else
+ break;
+ }
+
+ if(_write(file->_file, ptr, wrcnt) <= 0) {
file->_flag |= _IOERR;
- pwritten=0;
+ break;
}
- written += pwritten;
+ written += wrcnt;
+ wrcnt = 0;
+ } else {
+ if(_flsbuf(*(const char*)ptr, file) == EOF)
+ break;
+ written++;
+ wrcnt--;
+ ptr = (const char*)ptr + 1;
}
}
int CDECL fopen_s(FILE** pFile,
const char *filename, const char *mode)
{
- if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
- !MSVCRT_CHECK_PMT(mode != NULL)) {
- *_errno() = EINVAL;
- return EINVAL;
- }
+ if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
+ if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
+ if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
*pFile = fopen(filename, mode);
{
size_t rcnt=size * nmemb;
size_t read=0;
- int pread=0;
+ size_t pread=0;
if(!rcnt)
return 0;
/* first buffered data */
if(file->_cnt>0) {
- int pcnt= (rcnt>(unsigned int)file->_cnt)? file->_cnt:rcnt;
+ int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
memcpy(ptr, file->_ptr, pcnt);
file->_cnt -= pcnt;
file->_ptr += pcnt;
return 0;
}
}
+
+ if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
+ alloc_buffer(file);
+
while(rcnt>0)
{
int i;
- /* Fill the buffer on small reads.
- * TODO: Use a better buffering strategy.
- */
- if (!file->_cnt && size*nmemb <= BUFSIZ/2 && !(file->_flag & _IONBF)) {
- if (file->_bufsiz == 0) {
- alloc_buffer(file);
- }
+ if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) {
file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
file->_ptr = file->_base;
- i = ((unsigned int)file->_cnt<rcnt) ? file->_cnt : rcnt;
+ i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
/* If the buffer fill reaches eof but fread wouldn't, clear eof. */
if (i > 0 && i < file->_cnt) {
get_ioinfo(file->_file)->wxflag &= ~WX_ATEOF;
file->_cnt -= i;
file->_ptr += i;
}
+ } else if (rcnt > INT_MAX) {
+ i = _read(file->_file, ptr, INT_MAX);
+ } else if (rcnt < BUFSIZ) {
+ i = _read(file->_file, ptr, rcnt);
} else {
- i = _read(file->_file,ptr, rcnt);
+ i = _read(file->_file, ptr, rcnt - BUFSIZ/2);
}
pread += i;
rcnt -= i;
_unlock_file(file);
return -1;
}
- if(file->_bufsiz) {
+ if(file->_flag & (_IOMYBUF | _USERBUF)) {
if(file->_flag & _IOWRT) {
pos += file->_ptr - file->_base;
*/
int CDECL fgetpos(FILE* file, fpos_t *pos)
{
- int off=0;
-
- _lock_file(file);
- *pos = _lseeki64(file->_file,0,SEEK_CUR);
- if(*pos == -1) {
- _unlock_file(file);
+ *pos = _ftelli64(file);
+ if(*pos == -1)
return -1;
- }
- if(file->_bufsiz) {
- if( file->_flag & _IOWRT ) {
- off = file->_ptr - file->_base;
- } else {
- off = -file->_cnt;
- if (get_ioinfo(file->_file)->wxflag & WX_TEXT) {
- /* Black magic correction for CR removal */
- int i;
- for (i=0; i<file->_cnt; i++) {
- if (file->_ptr[i] == '\n')
- off--;
- }
- /* Black magic when reading CR at buffer boundary*/
- if(get_ioinfo(file->_file)->wxflag & WX_READCR)
- off--;
- }
- }
- }
- *pos += off;
- _unlock_file(file);
return 0;
}
*/
int CDECL fputs(const char *s, FILE* file)
{
- size_t i, len = strlen(s);
+ size_t len = strlen(s);
int ret;
_lock_file(file);
- if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
- ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
- _unlock_file(file);
- return ret;
- }
- for (i=0; i<len; i++)
- if (fputc(s[i], file) == EOF) {
- _unlock_file(file);
- return EOF;
- }
-
+ ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF;
_unlock_file(file);
- return 0;
+ return ret;
}
/*********************************************************************
int CDECL fputws(const wchar_t *s, FILE* file)
{
size_t i, len = strlenW(s);
+ BOOL tmp_buf;
int ret;
_lock_file(file);
_unlock_file(file);
return ret;
}
+
+ tmp_buf = add_std_buffer(file);
for (i=0; i<len; i++) {
- if (((s[i] == '\n') && (fputc('\r', file) == EOF))
- || fputwc(s[i], file) == WEOF) {
+ if(fputwc(s[i], file) == WEOF) {
+ if(tmp_buf) remove_std_buffer(file);
_unlock_file(file);
return WEOF;
}
}
+ if(tmp_buf) remove_std_buffer(file);
_unlock_file(file);
return 0;
}
{
size = int_to_base32(tmpnam_unique++, tmpstr);
memcpy(p, tmpstr, size);
+ p[size] = '\0';
if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
GetLastError() == ERROR_FILE_NOT_FOUND)
break;
{
size = int_to_base32_w(tmpnam_unique++, tmpstr);
memcpy(p, tmpstr, size*sizeof(wchar_t));
+ p[size] = '\0';
if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
GetLastError() == ERROR_FILE_NOT_FOUND)
break;
return EOF;
_lock_file(file);
- if(file->_bufsiz == 0) {
- alloc_buffer(file);
+ if(file->_bufsiz == 0 && alloc_buffer(file))
file->_ptr++;
- }
if(file->_ptr>file->_base) {
file->_ptr--;
- *file->_ptr=c;
+ if(file->_flag & _IOSTRG) {
+ if(*file->_ptr != c) {
+ file->_ptr++;
+ _unlock_file(file);
+ return EOF;
+ }
+ }else {
+ *file->_ptr = c;
+ }
file->_cnt++;
clearerr(file);
_unlock_file(file);
wint_t CDECL ungetwc(wint_t wc, FILE * file)
{
wchar_t mwc = wc;
- char * pp = (char *)&mwc;
- int i;
+
+ if (wc == WEOF)
+ return WEOF;
_lock_file(file);
- for(i=sizeof(wchar_t)-1;i>=0;i--) {
- if(pp[i] != ungetc(pp[i],file)) {
+
+ if((get_ioinfo(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
+ || !(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
+ unsigned char * pp = (unsigned char *)&mwc;
+ int i;
+
+ for(i=sizeof(wchar_t)-1;i>=0;i--) {
+ if(pp[i] != ungetc(pp[i],file)) {
+ _unlock_file(file);
+ return WEOF;
+ }
+ }
+ }else {
+ char mbs[MB_LEN_MAX];
+ int len;
+
+ len = wctomb(mbs, mwc);
+ if(len == -1) {
_unlock_file(file);
return WEOF;
}
+
+ for(len--; len>=0; len--) {
+ if(mbs[len] != ungetc(mbs[len], file)) {
+ _unlock_file(file);
+ return WEOF;
+ }
+ }
}
_unlock_file(file);