[CRT]
[reactos.git] / reactos / lib / sdk / crt / stdio / file.c
index 6425575..b79b46a 100644 (file)
 int *__p__fmode(void);
 int *__p___mb_cur_max(void);
 
+extern int _commode;
+
+#ifndef _IOCOMMIT
+#define _IOCOMMIT 0x4000
+#endif
+
 #ifdef feof
 #undef feof
 #endif
@@ -83,16 +89,18 @@ int *__p___mb_cur_max(void);
 /* values for wxflag in file descriptor */
 #define WX_OPEN           0x01
 #define WX_ATEOF          0x02
+#define WX_READNL         0x04  /* read started with \n */
 #define WX_READEOF        0x04  /* like ATEOF, but for underlying file rather than buffer */
+#define WX_PIPE           0x08
 #define WX_READCR         0x08  /* underlying file is at \r */
 #define WX_DONTINHERIT    0x10
 #define WX_APPEND         0x20
+#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_CRIT_INIT      0x04
 #define EF_UNK_UNICODE    0x08
 
 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
@@ -106,7 +114,7 @@ static char utf16_bom[2] = { 0xff, 0xfe };
 typedef struct {
     HANDLE              handle;
     unsigned char       wxflag;
-    char                unk1;
+    char                lookahead[3];
     int                 exflag;
     CRITICAL_SECTION    crit;
 } ioinfo;
@@ -255,7 +263,7 @@ static void free_fd(int fd)
 
 /* 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;
 
@@ -284,7 +292,11 @@ static int alloc_fd_from(HANDLE hand, int flag, int fd)
   }
 
   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)
@@ -315,7 +327,7 @@ static int alloc_fd_from(HANDLE hand, int flag, int fd)
 
   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;
 }
@@ -435,7 +447,7 @@ void msvcrt_init_io(void)
     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++;
     }
@@ -445,7 +457,7 @@ void msvcrt_init_io(void)
   }
 
   if(!__pioinfo[0])
-      alloc_fd_from(INVALID_HANDLE_VALUE, 0, 3);
+      set_fd(INVALID_HANDLE_VALUE, 0, 3);
 
   fdinfo = get_ioinfo(0);
   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
@@ -887,7 +899,7 @@ int CDECL _dup2(int od, int nd)
 
       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);
@@ -1247,9 +1259,11 @@ void CDECL rewind(FILE* file)
 static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
 {
   int plus = strchrW(mode, '+') != NULL;
-  
+
+  TRACE("%s\n", debugstr_w(mode));
+
   while(*mode == ' ') mode++;
-  
+
   switch(*mode++)
   {
   case 'R': case 'r':
@@ -1265,14 +1279,12 @@ static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
     *stream_flags = plus ? _IORW : _IOWRT;
     break;
   default:
-    _invalid_parameter(NULL, NULL, NULL, 0, 0);
-    *_errno() = EINVAL;
+    MSVCRT_INVALID_PMT(0, EINVAL);
     return -1;
   }
 
-  /* FIXME */
-  /* *stream_flags |= MSVCRT__commode; */
-  
+  *stream_flags |= _commode;
+
   while (*mode && *mode!=',')
     switch (*mode++)
     {
@@ -1290,14 +1302,12 @@ static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
     case 'T':
       *open_flags |= _O_SHORT_LIVED;
       break;
-      /* FIXME 
-   case 'c':
+    case 'c':
       *stream_flags |= _IOCOMMIT;
       break;
     case 'n':
       *stream_flags &= ~_IOCOMMIT;
-      break;      
-      */
+      break;
     case 'N':
       *open_flags |= _O_NOINHERIT;
       break;
@@ -1350,17 +1360,15 @@ static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
     }
     else
     {
-      _invalid_parameter(NULL, NULL, NULL, 0, 0);
-      *_errno() = EINVAL;
+      MSVCRT_INVALID_PMT(0, EINVAL);
       return -1;
     }
 
     while(*mode == ' ') mode++;
   }
 
- if(!MSVCRT_CHECK_PMT(*mode == 0))
 if(!MSVCRT_CHECK_PMT(*mode == 0))
     return -1;
-  
   return 0;
 }
 
@@ -1486,9 +1494,12 @@ char * CDECL _mktemp(char *pattern)
   int id;
   char letter = 'a';
 
+  if(!pattern)
+      return NULL;
+
   while(*pattern)
     numX = (*pattern++ == 'X')? numX + 1 : 0;
-  if (numX < 5)
+  if (numX < 6)
     return NULL;
   pattern--;
   id = GetCurrentProcessId();
@@ -1503,8 +1514,7 @@ char * CDECL _mktemp(char *pattern)
   do
   {
     *pattern = letter++;
-    if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
-        GetLastError() == ERROR_FILE_NOT_FOUND)
+    if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
       return retVal;
   } while(letter <= 'z');
   return NULL;
@@ -1549,15 +1559,15 @@ wchar_t * CDECL _wmktemp(wchar_t *pattern)
     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 (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 */}
+    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|
@@ -1627,26 +1637,44 @@ int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
   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");
-    *_errno() = EINVAL;
-    return EINVAL;
-  }
+  if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
 
   *fd = -1;
   wxflag = split_oflags(oflags);
@@ -1708,25 +1736,89 @@ int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmod
 
   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
   sa.lpSecurityDescriptor = NULL;
-  sa.bInheritHandle       = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
+  sa.bInheritHandle       = !(oflags & _O_NOINHERIT);
 
-  hand = CreateFileA(path, access, sharing, &sa, creation, attrib, 0);
+  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)  {
-    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;
@@ -1742,51 +1834,27 @@ int CDECL _sopen( const char *path, int oflags, int shflags, ... )
   else
     pmode = 0;
 
-  _sopen_s(&fd, path, oflags, shflags, pmode);
+  _wsopen_s(&fd, path, oflags, shflags, pmode);
   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.@)
+ *              _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;
+  SECURITY_ATTRIBUTES sa;
 
-  TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
-        fd, debugstr_w(path), oflags, shflags, pmode);
+  TRACE("fd*: %p file: (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
+        fd, path, oflags, shflags, pmode);
 
   if (!fd)
   {
-    MSVCRT_INVALID_PMT("null out fd pointer");
-    *_errno() = EINVAL;
+    MSVCRT_INVALID_PMT("null out fd pointer", EINVAL);
     return EINVAL;
   }
 
@@ -1852,88 +1920,23 @@ int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int
   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);
-
+  hand = CreateFileA(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);
-                  *_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;
 }
 
 /*********************************************************************
- *              _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;
@@ -1949,7 +1952,7 @@ int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
   else
     pmode = 0;
 
-  _wsopen_s(&fd, path, oflags, shflags, pmode);
+  _sopen_s(&fd, path, oflags, shflags, pmode);
   return fd;
 }
 
@@ -2014,6 +2017,7 @@ int CDECL _wcreat(const wchar_t *path, int flags)
  */
 int CDECL _open_osfhandle(intptr_t handle, int oflags)
 {
+  DWORD flags;
   int fd;
 
   /* _O_RDONLY (0) always matches, so set the read flag
@@ -2025,8 +2029,23 @@ int CDECL _open_osfhandle(intptr_t handle, int oflags)
   if (!(oflags & (_O_BINARY | _O_TEXT)))
       oflags |= _O_BINARY;
 
-  fd = alloc_fd((HANDLE)handle, split_oflags(oflags));
-  TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, oflags);
+  flags = GetFileType((HANDLE)handle);
+  if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
+  {
+    _dosmaperr(GetLastError());
+    return -1;
+  }
+
+  if (flags == FILE_TYPE_CHAR)
+    flags = WX_NOSEEK;
+  else if (flags == FILE_TYPE_PIPE)
+    flags = WX_PIPE;
+  else
+    flags = 0;
+  flags |= split_oflags(oflags);
+
+  fd = alloc_fd((HANDLE)handle, flags);
+  TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags);
   return fd;
 }
 
@@ -2166,14 +2185,32 @@ int CDECL _read(int fd, void *buf, unsigned int count)
  */
 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;
+
 }
 
 /*********************************************************************
@@ -2247,89 +2284,170 @@ int CDECL _umask(int umask)
  */
 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;
 }
 
 /*********************************************************************
@@ -2390,13 +2508,7 @@ int CDECL fclose(FILE* file)
  */
 int CDECL feof(FILE* file)
 {
-    int ret;
-
-    _lock_file(file);
-    ret = file->_flag & _IOEOF;
-    _unlock_file(file);
-
-    return ret;
+    return file->_flag & _IOEOF;
 }
 
 /*********************************************************************
@@ -2404,13 +2516,7 @@ int CDECL feof(FILE* file)
  */
 int CDECL ferror(FILE* file)
 {
-    int ret;
-
-    _lock_file(file);
-    ret = file->_flag & _IOERR;
-    _unlock_file(file);
-
-    return ret;
+    return file->_flag & _IOERR;
 }
 
 /*********************************************************************
@@ -2421,6 +2527,11 @@ int CDECL _filbuf(FILE* file)
     unsigned char c;
     _lock_file(file);
 
+    if(file->_flag & _IOSTRG) {
+        _unlock_file(file);
+        return EOF;
+    }
+
     /* Allocate buffer if needed */
     if(file->_bufsiz == 0 && !(file->_flag & _IONBF))
         alloc_buffer(file);
@@ -2523,60 +2634,50 @@ char * CDECL fgets(char *s, int size, FILE* file)
 
 /*********************************************************************
  *             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;
 
-            _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;
 }
 
 /*********************************************************************
@@ -2671,33 +2772,36 @@ size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
         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;
         }
     }
 
@@ -2990,7 +3094,7 @@ FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
 {
   int open_flags, stream_flags, fd;
 
-  TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file->_file);
+  TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
 
   LOCK_FILES();
   if (!file || ((fd = file->_file) < 0) || fd > fdend)
@@ -3073,8 +3177,6 @@ int CDECL fsetpos(FILE* file, const fpos_t *pos)
  */
 __int64 CDECL _ftelli64(FILE* file)
 {
-    /* TODO: just call fgetpos and return lower half of result */
-    int off=0;
     __int64 pos;
 
     _lock_file(file);
@@ -3084,26 +3186,50 @@ __int64 CDECL _ftelli64(FILE* file)
         return -1;
     }
     if(file->_bufsiz)  {
-        if( file->_flag & _IOWRT ) {
-            off = file->_ptr - file->_base;
+        if(file->_flag & _IOWRT) {
+            pos += file->_ptr - file->_base;
+
+            if(get_ioinfo(file->_file)->wxflag & WX_TEXT) {
+                char *p;
+
+                for(p=file->_base; p<file->_ptr; p++)
+                    if(*p == '\n')
+                        pos++;
+            }
+        } else if(!file->_cnt) { /* nothing to do */
+        } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
+            int i;
+
+            pos -= file->_cnt;
+            if(get_ioinfo(file->_file)->wxflag & WX_TEXT) {
+                for(i=0; i<file->_cnt; i++)
+                    if(file->_ptr[i] == '\n')
+                        pos--;
+            }
         } 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--;
+            char *p;
+
+            if(_lseeki64(file->_file, pos, SEEK_SET) != pos) {
+                _unlock_file(file);
+                return -1;
+            }
+
+            pos -= file->_bufsiz;
+            pos += file->_ptr - file->_base;
+
+            if(get_ioinfo(file->_file)->wxflag & WX_TEXT) {
+                if(get_ioinfo(file->_file)->wxflag & WX_READNL)
+                    pos--;
+
+                for(p=file->_base; p<file->_ptr; p++)
+                    if(*p == '\n')
+                        pos++;
             }
         }
     }
 
     _unlock_file(file);
-    return off + pos;
+    return pos;
 }
 
 /*********************************************************************
@@ -3477,16 +3603,20 @@ FILE* CDECL tmpfile(void)
   FILE* file = NULL;
 
   LOCK_FILES();
-  fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY);
+  fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
+          _S_IREAD | _S_IWRITE);
   if (fd != -1 && (file = alloc_fp()))
   {
-    if (init_fp(file, fd, _O_RDWR) == -1)
+    if (init_fp(file, fd, _IORW) == -1)
     {
         file->_flag = 0;
         file = NULL;
     }
     else file->_tmpfname = _strdup(filename);
   }
+
+  if(fd != -1 && !file)
+      _close(fd);
   UNLOCK_FILES();
   return file;
 }