* Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
*/
+/*********************************************
+ * This file contains ReactOS changes!!
+ * Don't blindly sync it with Wine code!
+ *
+ * If you break Unicode output on the console again, please update this counter:
+ * int hours_wasted_on_this = 42;
+ *********************************************/
+
/*
* msvcrt.dll file functions
*
#define WX_APPEND 0x20
#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 };
+
/* FIXME: this should be allocated dynamically */
#define MAX_FILES 2048
#define FD_BLOCK_SIZE 64
+/* ioinfo structure size is different in msvcrXX.dll's */
typedef struct {
HANDLE handle;
unsigned char wxflag;
char unk1;
- BOOL crit_init;
+ int exflag;
CRITICAL_SECTION crit;
} ioinfo;
CRITICAL_SECTION crit;
} file_crit;
-FILE _iob[3] = { { 0 } };
-static file_crit* fstream[MAX_FILES/FD_BLOCK_SIZE];
+FILE _iob[_IOB_ENTRIES] = { { 0 } };
+static file_crit* fstream[MAX_FILES/FD_BLOCK_SIZE] = { NULL };
static int max_streams = 512, stream_idx;
/* INTERNAL: process umask */
unsigned int i;
FILE *file;
- for (i = 3; i < max_streams; i++)
+ for (i = 3; i < (unsigned int)max_streams; i++)
{
file = get_file(i);
if (!file)
*handle_ptr = INVALID_HANDLE_VALUE;
}
wxflag_ptr++; handle_ptr++;
- }
+ }
return TRUE;
}
-/* INTERNAL: Set up all file descriptors,
- * as well as default streams (stdin, stderr and stdout)
+/* INTERNAL: Set up all file descriptors,
+ * as well as default streams (stdin, stderr and stdout)
*/
void msvcrt_init_io(void)
{
STARTUPINFOA si;
- int i;
+ unsigned int i;
ioinfo *fdinfo;
InitializeCriticalSection(&file_cs);
/* _flushall calls fflush which calls _flushall */
int CDECL fflush(FILE* file);
-/*********************************************************************
- * _flushall (MSVCRT.@)
- */
-int CDECL _flushall(void)
+/* INTERNAL: Flush all stream buffer */
+static int flush_all_buffers(int mask)
{
int i, num_flushed = 0;
FILE *file;
if (file->_flag)
{
- if(file->_flag & _IOWRT) {
- fflush(file);
+ if(file->_flag & mask) {
+ fflush(file);
num_flushed++;
}
}
return num_flushed;
}
+/*********************************************************************
+ * _flushall (MSVCRT.@)
+ */
+int CDECL _flushall(void)
+{
+ return flush_all_buffers(_IOWRT | _IOREAD);
+}
+
/*********************************************************************
* fflush (MSVCRT.@)
*/
int CDECL fflush(FILE* file)
{
if(!file) {
- _flushall();
+ flush_all_buffers(_IOWRT);
} else if(file->_flag & _IOWRT) {
int res;
_lock_file(file);
res = flush_buffer(file);
+ /* FIXME
+ if(!res && (file->_flag & _IOCOMMIT))
+ res = _commit(file->_file) ? EOF : 0;
+ */
_unlock_file(file);
return res;
- }
+ } else if(file->_flag & _IOREAD) {
+ _lock_file(file);
+ file->_cnt = 0;
+ file->_ptr = file->_base;
+ _unlock_file(file);
+
+ return 0;
+ }
return 0;
}
fclose(&_iob[2]);
for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
- free(__pioinfo[i]);
+ free(__pioinfo[i]);
for(i=0; i<sizeof(fstream)/sizeof(fstream[0]); i++)
- free(fstream[i]);
+ free(fstream[i]);
file_cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&file_cs);
*/
LONG CDECL _lseek(int fd, LONG offset, int whence)
{
- return _lseeki64(fd, offset, whence);
+ return (LONG)_lseeki64(fd, offset, whence);
}
/*********************************************************************
static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
{
int plus = strchrW(mode, '+') != NULL;
-
+
+ while(*mode == ' ') mode++;
+
switch(*mode++)
{
case 'R': case 'r':
return -1;
}
- while (*mode)
+ /* FIXME */
+ /* *stream_flags |= MSVCRT__commode; */
+
+ while (*mode && *mode!=',')
switch (*mode++)
{
case 'B': case 'b':
*open_flags |= _O_BINARY;
*open_flags &= ~_O_TEXT;
break;
- case 'T': case 't':
+ case 't':
*open_flags |= _O_TEXT;
*open_flags &= ~_O_BINARY;
break;
+ case 'D':
+ *open_flags |= _O_TEMPORARY;
+ break;
+ case 'T':
+ *open_flags |= _O_SHORT_LIVED;
+ break;
+ /* FIXME
+ 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
+ {
+ _invalid_parameter(NULL, NULL, NULL, 0, 0);
+ *_errno() = EINVAL;
+ return -1;
+ }
+
+ while(*mode == ' ') mode++;
+ }
+
+ if(!MSVCRT_CHECK_PMT(*mode == 0))
+ return -1;
+
return 0;
}
int wxflags = 0;
unsigned unsupp; /* until we support everything */
- if (oflags & _O_APPEND) wxflags |= WX_APPEND;
- if (oflags & _O_BINARY) {/* Nothing to do */}
- else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
- else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */}
+ 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;
+ if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
if ((unsupp = oflags & ~(
_O_BINARY|_O_TEXT|_O_APPEND|
_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);
else
creation = OPEN_EXISTING;
}
-
+
switch( shflags )
{
case _SH_DENYRW:
return fd;
}
+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;
+}
+
/*********************************************************************
* _wsopen_s (MSVCRT.@)
*/
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
+ 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 = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
if (hand == INVALID_HANDLE_VALUE) {
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);
+ *_errno() = 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);
+ *_errno() = 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;
wcp = (char *)&wc;
for(i=0; i<sizeof(wc); i++)
{
- if (file->_cnt>0)
+ if (file->_cnt>0)
{
file->_cnt--;
chp = file->_ptr++;
wcp[i] = *chp;
- }
+ }
else
{
j = _filbuf(file);
_unlock_file(file);
return wc;
}
-
+
c = fgetc(file);
if ((__mb_cur_max > 1) && isleadbyte(c))
{
_lock_file(file);
if(file->_cnt) {
- int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
+ int pcnt=((unsigned)file->_cnt>wrcnt)? wrcnt: file->_cnt;
memcpy(file->_ptr, ptr, pcnt);
file->_cnt -= pcnt;
file->_ptr += pcnt;
/*********************************************************************
* fputwc (MSVCRT.@)
+ * FORKED for ReactOS, don't sync with Wine!
+ * References:
+ * - http://jira.reactos.org/browse/CORE-6495
+ * - http://bugs.winehq.org/show_bug.cgi?id=8598
*/
-wint_t CDECL fputwc(wint_t wc, FILE* file)
+wint_t CDECL fputwc(wchar_t c, FILE* stream)
{
- wchar_t mwc=wc;
- if (fwrite( &mwc, sizeof(mwc), 1, file) != 1)
- return WEOF;
- return wc;
+ /* If this is a real file stream (and not some temporary one for
+ sprintf-like functions), check whether it is opened in text mode.
+ In this case, we have to perform an implicit conversion to ANSI. */
+ if (!(stream->_flag & _IOSTRG) && get_ioinfo(stream->_file)->wxflag & WX_TEXT)
+ {
+ /* Convert to multibyte in text mode */
+ char mbc[MB_LEN_MAX];
+ int mb_return;
+
+ mb_return = wctomb(mbc, c);
+
+ if(mb_return == -1)
+ return WEOF;
+
+ /* Output all characters */
+ if (fwrite(mbc, mb_return, 1, stream) != 1)
+ return WEOF;
+ }
+ else
+ {
+ if (fwrite(&c, sizeof(c), 1, stream) != 1)
+ return WEOF;
+ }
+
+ return c;
}
/*********************************************************************
/* first buffered data */
if(file->_cnt>0) {
- int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
+ int pcnt= (rcnt>(unsigned int)file->_cnt)? file->_cnt:rcnt;
memcpy(ptr, file->_ptr, pcnt);
file->_cnt -= pcnt;
file->_ptr += pcnt;
}
file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
file->_ptr = file->_base;
- i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
+ i = ((unsigned int)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;
/* Discard buffered input */
file->_cnt = 0;
file->_ptr = file->_base;
-
+
/* Reset direction of i/o */
if(file->_flag & _IORW) {
file->_flag &= ~(_IOREAD|_IOWRT);
*/
LONG CDECL ftell(FILE* file)
{
- return _ftelli64(file);
+ return (LONG)_ftelli64(file);
}
/*********************************************************************