xref: /reactos/sdk/lib/crt/stdio/file.c (revision 3f976713)
1 /*
2  * PROJECT:         ReactOS CRT library
3  * LICENSE:         LGPL - See COPYING in the top level directory
4  * FILE:            lib/sdk/crt/stdio/file.c
5  * PURPOSE:         File CRT functions
6  * PROGRAMMERS:     Wine team
7  *                  Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8  */
9 
10 /*********************************************
11  * This file contains ReactOS changes!!
12  * Don't blindly sync it with Wine code!
13  *
14  * If you break Unicode output on the console again, please update this counter:
15  *   int hours_wasted_on_this = 42;
16  *********************************************/
17 
18 /*
19  * msvcrt.dll file functions
20  *
21  * Copyright 1996,1998 Marcus Meissner
22  * Copyright 1996 Jukka Iivonen
23  * Copyright 1997,2000 Uwe Bonnes
24  * Copyright 2000 Jon Griffiths
25  * Copyright 2004 Eric Pouech
26  * Copyright 2004 Juan Lang
27  *
28  * This library is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU Lesser General Public
30  * License as published by the Free Software Foundation; either
31  * version 2.1 of the License, or (at your option) any later version.
32  *
33  * This library is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * Lesser General Public License for more details.
37  *
38  * You should have received a copy of the GNU Lesser General Public
39  * License along with this library; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41  *
42  * TODO
43  * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
44  */
45 
46 #include <precomp.h>
47 #include "wine/unicode.h"
48 #include "internal/wine/msvcrt.h"
49 
50 #include <sys/utime.h>
51 #include <direct.h>
52 
53 int *__p__fmode(void);
54 int *__p___mb_cur_max(void);
55 
56 extern int _commode;
57 
58 #ifndef _IOCOMMIT
59 #define _IOCOMMIT 0x4000
60 #endif
61 
62 #ifdef feof
63 #undef feof
64 #endif
65 #ifdef _fileno
66 #undef _fileno
67 #endif
68 #ifdef ferror
69 #undef ferror
70 #endif
71 #ifdef clearerr
72 #undef clearerr
73 #endif
74 
75 #undef getc
76 #undef getwc
77 #undef getchar
78 #undef getwchar
79 #undef putc
80 #undef putwc
81 #undef putchar
82 #undef putwchar
83 
84 #undef vprintf
85 #undef vwprintf
86 
87 /* _access() bit flags FIXME: incomplete */
88 /* defined in crt/io.h */
89 
90 /* values for wxflag in file descriptor */
91 #define WX_OPEN           0x01
92 #define WX_ATEOF          0x02
93 #define WX_READNL         0x04  /* read started with \n */
94 #define WX_READEOF        0x04  /* like ATEOF, but for underlying file rather than buffer */
95 #define WX_PIPE           0x08
96 #define WX_READCR         0x08  /* underlying file is at \r */
97 #define WX_DONTINHERIT    0x10
98 #define WX_APPEND         0x20
99 #define WX_TTY            0x40
100 #define WX_TEXT           0x80
101 
102 /* values for exflag - it's used differently in msvcr90.dll*/
103 #define EF_UTF8           0x01
104 #define EF_UTF16          0x02
105 #define EF_CRIT_INIT      0x04
106 #define EF_UNK_UNICODE    0x08
107 
108 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
109 static char utf16_bom[2] = { 0xff, 0xfe };
110 
111 /* FIXME: this should be allocated dynamically */
112 #define MSVCRT_MAX_FILES 2048
113 #define MSVCRT_FD_BLOCK_SIZE 32
114 
115 #define MSVCRT_INTERNAL_BUFSIZ 4096
116 
117 /*********************************************************************
118  *		__pioinfo (MSVCRT.@)
119  * array of pointers to ioinfo arrays [32]
120  */
121 ioinfo * __pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
122 
123 /*********************************************************************
124  *		__badioinfo (MSVCRT.@)
125  */
126 ioinfo __badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
127 
128 typedef struct {
129     FILE file;
130     CRITICAL_SECTION crit;
131 } file_crit;
132 
133 FILE _iob[_IOB_ENTRIES] = { { 0 } };
134 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { NULL };
135 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
136 
137 /* INTERNAL: process umask */
138 static int MSVCRT_umask = 0;
139 
140 /* INTERNAL: static data for tmpnam and _wtmpname functions */
141 static int tmpnam_unique;
142 
143 /* This critical section protects the MSVCRT_fstreams table
144  * and MSVCRT_stream_idx from race conditions. It also
145  * protects fd critical sections creation code.
146  */
147 static CRITICAL_SECTION MSVCRT_file_cs;
148 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
149 {
150     0, 0, &MSVCRT_file_cs,
151     { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
152       0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
153 };
154 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
155 #define LOCK_FILES()    do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
156 #define UNLOCK_FILES()  do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
157 
158 static inline ioinfo* get_ioinfo_nolock(int fd)
159 {
160     ioinfo *ret = NULL;
161     if(fd>=0 && fd<MSVCRT_MAX_FILES)
162         ret = __pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
163     if(!ret)
164         return &__badioinfo;
165 
166     return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
167 }
168 
169 static inline void init_ioinfo_cs(ioinfo *info)
170 {
171     if(!(info->exflag & EF_CRIT_INIT)) {
172         LOCK_FILES();
173         if(!(info->exflag & EF_CRIT_INIT)) {
174             InitializeCriticalSection(&info->crit);
175             info->exflag |= EF_CRIT_INIT;
176         }
177         UNLOCK_FILES();
178     }
179 }
180 
181 ioinfo* get_ioinfo(int fd)
182 {
183     ioinfo *ret = get_ioinfo_nolock(fd);
184     if(ret == &__badioinfo)
185         return ret;
186     init_ioinfo_cs(ret);
187     EnterCriticalSection(&ret->crit);
188     return ret;
189 }
190 
191 static inline BOOL alloc_pioinfo_block(int fd)
192 {
193     ioinfo *block;
194     int i;
195 
196     if(fd<0 || fd>=MSVCRT_MAX_FILES)
197     {
198         *_errno() = ENFILE;
199         return FALSE;
200     }
201 
202     block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
203     if(!block)
204     {
205         WARN(":out of memory!\n");
206         *_errno() = ENOMEM;
207         return FALSE;
208     }
209     for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
210         block[i].handle = INVALID_HANDLE_VALUE;
211     if(InterlockedCompareExchangePointer((void**)&__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL))
212         free(block);
213     return TRUE;
214 }
215 
216 static inline ioinfo* get_ioinfo_alloc_fd(int fd)
217 {
218     ioinfo *ret;
219 
220     ret = get_ioinfo(fd);
221     if(ret != &__badioinfo)
222         return ret;
223 
224     if(!alloc_pioinfo_block(fd))
225         return &__badioinfo;
226 
227     return get_ioinfo(fd);
228 }
229 
230 static inline ioinfo* get_ioinfo_alloc(int *fd)
231 {
232     int i;
233 
234     *fd = -1;
235     for(i=0; i<MSVCRT_MAX_FILES; i++)
236     {
237         ioinfo *info = get_ioinfo_nolock(i);
238 
239         if(info == &__badioinfo)
240         {
241             if(!alloc_pioinfo_block(i))
242                 return &__badioinfo;
243             info = get_ioinfo_nolock(i);
244         }
245 
246         init_ioinfo_cs(info);
247         if(TryEnterCriticalSection(&info->crit))
248         {
249             if(info->handle == INVALID_HANDLE_VALUE)
250             {
251                 *fd = i;
252                 return info;
253             }
254             LeaveCriticalSection(&info->crit);
255         }
256     }
257 
258     WARN(":files exhausted!\n");
259     *_errno() = ENFILE;
260     return &__badioinfo;
261 }
262 
263 void release_ioinfo(ioinfo *info)
264 {
265     if(info!=&__badioinfo && info->exflag & EF_CRIT_INIT)
266         LeaveCriticalSection(&info->crit);
267 }
268 
269 static inline FILE* msvcrt_get_file(int i)
270 {
271     file_crit *ret;
272 
273     if(i >= MSVCRT_max_streams)
274         return NULL;
275 
276     if(i < _IOB_ENTRIES)
277         return &_iob[i];
278 
279     ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
280     if(!ret) {
281         MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
282         if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
283             ERR("out of memory\n");
284             *_errno() = ENOMEM;
285             return NULL;
286         }
287 
288         ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
289     } else
290         ret += i%MSVCRT_FD_BLOCK_SIZE;
291 
292     return &ret->file;
293 }
294 
295 /* INTERNAL: free a file entry fd */
296 static void msvcrt_free_fd(int fd)
297 {
298   ioinfo *fdinfo = get_ioinfo(fd);
299 
300   if(fdinfo != &__badioinfo)
301   {
302     fdinfo->handle = INVALID_HANDLE_VALUE;
303     fdinfo->wxflag = 0;
304   }
305   TRACE(":fd (%d) freed\n",fd);
306 
307   if (fd < 3)
308   {
309     switch (fd)
310     {
311     case 0:
312         SetStdHandle(STD_INPUT_HANDLE, 0);
313         break;
314     case 1:
315         SetStdHandle(STD_OUTPUT_HANDLE, 0);
316         break;
317     case 2:
318         SetStdHandle(STD_ERROR_HANDLE, 0);
319         break;
320     }
321   }
322   release_ioinfo(fdinfo);
323 }
324 
325 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag)
326 {
327   fdinfo->handle = hand;
328   fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY));
329   fdinfo->lookahead[0] = '\n';
330   fdinfo->lookahead[1] = '\n';
331   fdinfo->lookahead[2] = '\n';
332   fdinfo->exflag &= EF_CRIT_INIT;
333 
334   switch (fdinfo-__pioinfo[0])
335   {
336   case 0: SetStdHandle(STD_INPUT_HANDLE,  hand); break;
337   case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
338   case 2: SetStdHandle(STD_ERROR_HANDLE,  hand); break;
339   }
340 }
341 
342 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
343 /*static*/ int msvcrt_alloc_fd(HANDLE hand, int flag)
344 {
345     int fd;
346     ioinfo *info = get_ioinfo_alloc(&fd);
347 
348     TRACE(":handle (%p) allocating fd (%d)\n", hand, fd);
349 
350     if(info == &__badioinfo)
351         return -1;
352 
353     msvcrt_set_fd(info, hand, flag);
354     release_ioinfo(info);
355     return fd;
356 }
357 
358 /* INTERNAL: Allocate a FILE* for an fd slot */
359 /* caller must hold the files lock */
360 static FILE* msvcrt_alloc_fp(void)
361 {
362   int i;
363   FILE *file;
364 
365   for (i = 3; i < MSVCRT_max_streams; i++)
366   {
367     file = msvcrt_get_file(i);
368     if (!file)
369       return NULL;
370 
371     if (file->_flag == 0)
372     {
373       if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++;
374       return file;
375     }
376   }
377 
378   return NULL;
379 }
380 
381 /* INTERNAL: initialize a FILE* from an open fd */
382 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags)
383 {
384   TRACE(":fd (%d) allocating FILE*\n",fd);
385   if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN))
386   {
387     WARN(":invalid fd %d\n",fd);
388     *__doserrno() = 0;
389     *_errno() = EBADF;
390     return -1;
391   }
392   file->_ptr = file->_base = NULL;
393   file->_cnt = 0;
394   file->_file = fd;
395   file->_flag = stream_flags;
396   file->_tmpfname = NULL;
397 
398   if(file<_iob || file>=_iob+_IOB_ENTRIES)
399       InitializeCriticalSection(&((file_crit*)file)->crit);
400 
401   TRACE(":got FILE* (%p)\n",file);
402   return 0;
403 }
404 
405 /* INTERNAL: Create an inheritance data block (for spawned process)
406  * The inheritance block is made of:
407  *      00      int     nb of file descriptor (NBFD)
408  *      04      char    file flags (wxflag): repeated for each fd
409  *      4+NBFD  HANDLE  file handle: repeated for each fd
410  */
411 unsigned create_io_inherit_block(WORD *size, BYTE **block)
412 {
413   int         fd, last_fd;
414   char*       wxflag_ptr;
415   HANDLE*     handle_ptr;
416   ioinfo*     fdinfo;
417 
418   for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--)
419     if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE)
420       break;
421   last_fd++;
422 
423   *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd;
424   *block = calloc(1, *size);
425   if (!*block)
426   {
427     *size = 0;
428     return FALSE;
429   }
430   wxflag_ptr = (char*)*block + sizeof(unsigned);
431   handle_ptr = (HANDLE*)(wxflag_ptr + last_fd);
432 
433   *(unsigned*)*block = last_fd;
434   for (fd = 0; fd < last_fd; fd++)
435   {
436     /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
437     fdinfo = get_ioinfo_nolock(fd);
438     if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
439     {
440       *wxflag_ptr = fdinfo->wxflag;
441       *handle_ptr = fdinfo->handle;
442     }
443     else
444     {
445       *wxflag_ptr = 0;
446       *handle_ptr = INVALID_HANDLE_VALUE;
447     }
448     wxflag_ptr++; handle_ptr++;
449   }
450   return TRUE;
451 }
452 
453 /* INTERNAL: Set up all file descriptors,
454  * as well as default streams (stdin, stderr and stdout)
455  */
456 void msvcrt_init_io(void)
457 {
458   STARTUPINFOA  si;
459   unsigned int  i;
460   ioinfo        *fdinfo;
461 
462   GetStartupInfoA(&si);
463   if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
464   {
465     BYTE*       wxflag_ptr;
466     HANDLE*     handle_ptr;
467     unsigned int count;
468 
469     count = *(unsigned*)si.lpReserved2;
470     wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
471     handle_ptr = (HANDLE*)(wxflag_ptr + count);
472 
473     count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
474     count = min(count, MSVCRT_MAX_FILES);
475     for (i = 0; i < count; i++)
476     {
477       if ((*wxflag_ptr & WX_OPEN) && GetFileType(*handle_ptr) != FILE_TYPE_UNKNOWN)
478       {
479         fdinfo = get_ioinfo_alloc_fd(i);
480         if(fdinfo != &__badioinfo)
481             msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr);
482         release_ioinfo(fdinfo);
483       }
484 
485       wxflag_ptr++; handle_ptr++;
486     }
487   }
488 
489   fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO);
490   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
491     HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
492     DWORD type = GetFileType(h);
493 
494     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
495             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
496   }
497   release_ioinfo(fdinfo);
498 
499   fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO);
500   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
501     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
502     DWORD type = GetFileType(h);
503 
504     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
505             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
506   }
507   release_ioinfo(fdinfo);
508 
509   fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO);
510   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
511     HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
512     DWORD type = GetFileType(h);
513 
514     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
515             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
516   }
517   release_ioinfo(fdinfo);
518 
519   TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle,
520         get_ioinfo_nolock(STDOUT_FILENO)->handle,
521         get_ioinfo_nolock(STDERR_FILENO)->handle);
522 
523   memset(_iob,0,3*sizeof(FILE));
524   for (i = 0; i < 3; i++)
525   {
526     /* FILE structs for stdin/out/err are static and never deleted */
527     _iob[i]._file = i;
528     _iob[i]._tmpfname = NULL;
529     _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
530   }
531   MSVCRT_stream_idx = 3;
532 }
533 
534 /* INTERNAL: Flush stdio file buffer */
535 static int msvcrt_flush_buffer(FILE* file)
536 {
537     if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT &&
538             file->_flag & (_IOMYBUF|_USERBUF)) {
539         int cnt=file->_ptr-file->_base;
540         if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
541             file->_flag |= _IOERR;
542             return EOF;
543         }
544 
545         if(file->_flag & _IORW)
546             file->_flag &= ~_IOWRT;
547 
548 #ifdef __REACTOS__ /* CORE-11949 */
549     file->_ptr=file->_base;
550     file->_cnt=0;
551 #endif
552     }
553 
554 #ifndef __REACTOS__ /* CORE-11949 */
555     file->_ptr=file->_base;
556     file->_cnt=0;
557 #endif
558     return 0;
559 }
560 
561 /*********************************************************************
562  *		_isatty (MSVCRT.@)
563  */
564 int CDECL _isatty(int fd)
565 {
566     TRACE(":fd (%d)\n",fd);
567 
568     return get_ioinfo_nolock(fd)->wxflag & WX_TTY;
569 }
570 
571 /* INTERNAL: Allocate stdio file buffer */
572 /*static*/ BOOL msvcrt_alloc_buffer(FILE* file)
573 {
574     if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
575             && _isatty(file->_file))
576         return FALSE;
577 
578     file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ);
579     if(file->_base) {
580         file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
581         file->_flag |= _IOMYBUF;
582     } else {
583         file->_base = (char*)(&file->_charbuf);
584         file->_bufsiz = 2;
585         file->_flag |= _IONBF;
586     }
587     file->_ptr = file->_base;
588     file->_cnt = 0;
589     return TRUE;
590 }
591 
592 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
593 static BOOL add_std_buffer(FILE *file)
594 {
595     static char buffers[2][BUFSIZ];
596 
597     if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
598             || (file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
599             || !_isatty(file->_file))
600         return FALSE;
601 
602     file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
603     file->_bufsiz = file->_cnt = BUFSIZ;
604     file->_flag |= _USERBUF;
605     return TRUE;
606 }
607 
608 /* INTERNAL: Removes temporary buffer from stdout or stderr */
609 /* Only call this function when add_std_buffer returned TRUE */
610 static void remove_std_buffer(FILE *file)
611 {
612     msvcrt_flush_buffer(file);
613     file->_ptr = file->_base = NULL;
614     file->_bufsiz = file->_cnt = 0;
615     file->_flag &= ~_USERBUF;
616 }
617 
618 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
619 static int msvcrt_int_to_base32(int num, char *str)
620 {
621   char *p;
622   int n = num;
623   int digits = 0;
624 
625   while (n != 0)
626   {
627     n >>= 5;
628     digits++;
629   }
630   p = str + digits;
631   *p = 0;
632   while (--p >= str)
633   {
634     *p = (num & 31) + '0';
635     if (*p > '9')
636       *p += ('a' - '0' - 10);
637     num >>= 5;
638   }
639 
640   return digits;
641 }
642 
643 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
644 static int msvcrt_int_to_base32_w(int num, wchar_t *str)
645 {
646     wchar_t *p;
647     int n = num;
648     int digits = 0;
649 
650     while (n != 0)
651     {
652         n >>= 5;
653         digits++;
654     }
655     p = str + digits;
656     *p = 0;
657     while (--p >= str)
658     {
659         *p = (num & 31) + '0';
660         if (*p > '9')
661             *p += ('a' - '0' - 10);
662         num >>= 5;
663     }
664 
665     return digits;
666 }
667 
668 /* INTERNAL: Create a wide string from an ascii string */
669 wchar_t *msvcrt_wstrdupa(const char *str)
670 {
671   const unsigned int len = strlen(str) + 1 ;
672   wchar_t *wstr = malloc(len* sizeof (wchar_t));
673   if (!wstr)
674     return NULL;
675    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
676   return wstr;
677 }
678 
679 /*********************************************************************
680  *		__iob_func(MSVCRT.@)
681  */
682 FILE * CDECL __iob_func(void)
683 {
684  return &_iob[0];
685 }
686 
687 /*********************************************************************
688  *		_access (MSVCRT.@)
689  */
690 int CDECL _access(const char *filename, int mode)
691 {
692   DWORD attr = GetFileAttributesA(filename);
693 
694   TRACE("(%s,%d) %d\n",filename,mode,attr);
695 
696   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
697   {
698     _dosmaperr(GetLastError());
699     return -1;
700   }
701   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
702   {
703     _set_errno(ERROR_ACCESS_DENIED);
704     return -1;
705   }
706   return 0;
707 }
708 
709 /*********************************************************************
710  *		_access_s (MSVCRT.@)
711  */
712 int CDECL _access_s(const char *filename, int mode)
713 {
714   if (!MSVCRT_CHECK_PMT(filename != NULL) ||
715       !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
716   {
717      _set_errno(EINVAL);
718      return -1;
719   }
720 
721   return _access(filename, mode);
722 }
723 
724 /*********************************************************************
725  *		_waccess (MSVCRT.@)
726  */
727 int CDECL _waccess(const wchar_t *filename, int mode)
728 {
729   DWORD attr = GetFileAttributesW(filename);
730 
731   TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
732 
733   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
734   {
735     _dosmaperr(GetLastError());
736     return -1;
737   }
738   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
739   {
740     _set_errno(ERROR_ACCESS_DENIED);
741     return -1;
742   }
743   return 0;
744 }
745 
746 /*********************************************************************
747  *		_waccess_s (MSVCRT.@)
748  */
749 int CDECL _waccess_s(const wchar_t *filename, int mode)
750 {
751   if (!MSVCRT_CHECK_PMT(filename != NULL) ||
752       !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
753   {
754      *_errno() = EINVAL;
755      return -1;
756   }
757 
758   return _waccess(filename, mode);
759 }
760 
761 /*********************************************************************
762  *		_chmod (MSVCRT.@)
763  */
764 int CDECL _chmod(const char *path, int flags)
765 {
766   DWORD oldFlags = GetFileAttributesA(path);
767 
768   if (oldFlags != INVALID_FILE_ATTRIBUTES)
769   {
770     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
771       oldFlags | FILE_ATTRIBUTE_READONLY;
772 
773     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
774       return 0;
775   }
776   _dosmaperr(GetLastError());
777   return -1;
778 }
779 
780 /*********************************************************************
781  *		_wchmod (MSVCRT.@)
782  */
783 int CDECL _wchmod(const wchar_t *path, int flags)
784 {
785   DWORD oldFlags = GetFileAttributesW(path);
786 
787   if (oldFlags != INVALID_FILE_ATTRIBUTES)
788   {
789     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
790       oldFlags | FILE_ATTRIBUTE_READONLY;
791 
792     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
793       return 0;
794   }
795   _dosmaperr(GetLastError());
796   return -1;
797 }
798 
799 /*********************************************************************
800  *		_unlink (MSVCRT.@)
801  */
802 int CDECL _unlink(const char *path)
803 {
804   TRACE("%s\n",debugstr_a(path));
805   if(DeleteFileA(path))
806     return 0;
807   TRACE("failed (%d)\n",GetLastError());
808   _dosmaperr(GetLastError());
809   return -1;
810 }
811 
812 /*********************************************************************
813  *		_wunlink (MSVCRT.@)
814  */
815 int CDECL _wunlink(const wchar_t *path)
816 {
817   TRACE("(%s)\n",debugstr_w(path));
818   if(DeleteFileW(path))
819     return 0;
820   TRACE("failed (%d)\n",GetLastError());
821   _dosmaperr(GetLastError());
822   return -1;
823 }
824 
825 /*********************************************************************
826  *		_commit (MSVCRT.@)
827  */
828 int CDECL _commit(int fd)
829 {
830     ioinfo *info = get_ioinfo(fd);
831     int ret;
832 
833     TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
834 
835     if (info->handle == INVALID_HANDLE_VALUE)
836         ret = -1;
837     else if (!FlushFileBuffers(info->handle))
838     {
839         if (GetLastError() == ERROR_INVALID_HANDLE)
840         {
841             /* FlushFileBuffers fails for console handles
842              * so we ignore this error.
843              */
844             ret = 0;
845         }
846         else
847         {
848             TRACE(":failed-last error (%d)\n",GetLastError());
849             _dosmaperr(GetLastError());
850             ret = -1;
851         }
852     }
853     else
854     {
855         TRACE(":ok\n");
856         ret = 0;
857     }
858 
859     release_ioinfo(info);
860     return ret;
861 }
862 
863 /* _flushall calls fflush which calls _flushall */
864 int CDECL fflush(FILE* file);
865 
866 /* INTERNAL: Flush all stream buffer */
867 static int msvcrt_flush_all_buffers(int mask)
868 {
869   int i, num_flushed = 0;
870   FILE *file;
871 
872   LOCK_FILES();
873   for (i = 0; i < MSVCRT_stream_idx; i++) {
874     file = msvcrt_get_file(i);
875 
876     if (file->_flag)
877     {
878       if(file->_flag & mask) {
879 	fflush(file);
880         num_flushed++;
881       }
882     }
883   }
884   UNLOCK_FILES();
885 
886   TRACE(":flushed (%d) handles\n",num_flushed);
887   return num_flushed;
888 }
889 
890 /*********************************************************************
891  *		_flushall (MSVCRT.@)
892  */
893 int CDECL _flushall(void)
894 {
895     return msvcrt_flush_all_buffers(_IOWRT | _IOREAD);
896 }
897 
898 /*********************************************************************
899  *		fflush (MSVCRT.@)
900  */
901 int CDECL fflush(FILE* file)
902 {
903     if(!file) {
904         msvcrt_flush_all_buffers(_IOWRT);
905     } else if(file->_flag & _IOWRT) {
906         int res;
907 
908         _lock_file(file);
909         res = msvcrt_flush_buffer(file);
910         /* FIXME
911         if(!res && (file->_flag & _IOCOMMIT))
912             res = _commit(file->_file) ? EOF : 0;
913         */
914         _unlock_file(file);
915 
916         return res;
917     } else if(file->_flag & _IOREAD) {
918         _lock_file(file);
919         file->_cnt = 0;
920         file->_ptr = file->_base;
921         _unlock_file(file);
922 
923         return 0;
924     }
925     return 0;
926 }
927 
928 /*********************************************************************
929  *		_close (MSVCRT.@)
930  */
931 int CDECL _close(int fd)
932 {
933   ioinfo *info = get_ioinfo(fd);
934   int ret;
935 
936   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
937   if (!(info->wxflag & WX_OPEN)) {
938     ret = -1;
939   } else if (fd == STDOUT_FILENO &&
940           info->handle == get_ioinfo_nolock(STDERR_FILENO)->handle) {
941     msvcrt_free_fd(fd);
942     ret = 0;
943   } else if (fd == STDERR_FILENO &&
944           info->handle == get_ioinfo_nolock(STDOUT_FILENO)->handle) {
945     msvcrt_free_fd(fd);
946     ret = 0;
947   } else {
948     ret = CloseHandle(info->handle) ? 0 : -1;
949     msvcrt_free_fd(fd);
950     if (ret) {
951       WARN(":failed-last error (%d)\n",GetLastError());
952       _dosmaperr(GetLastError());
953       ret = -1;
954     }
955   }
956   release_ioinfo(info);
957   return ret;
958 }
959 
960 /*********************************************************************
961  *		_dup2 (MSVCRT.@)
962  * NOTES
963  * MSDN isn't clear on this point, but the remarks for _pipe
964  * indicate file descriptors duplicated with _dup and _dup2 are always
965  * inheritable.
966  */
967 int CDECL _dup2(int od, int nd)
968 {
969   ioinfo *info_od, *info_nd;
970   int ret;
971 
972   TRACE("(od=%d, nd=%d)\n", od, nd);
973 
974   if (od < nd)
975   {
976     info_od = get_ioinfo(od);
977     info_nd = get_ioinfo_alloc_fd(nd);
978   }
979   else
980   {
981     info_nd = get_ioinfo_alloc_fd(nd);
982     info_od = get_ioinfo(od);
983   }
984 
985   if (info_nd == &__badioinfo)
986   {
987       ret = -1;
988   }
989   else if (info_od->wxflag & WX_OPEN)
990   {
991     HANDLE handle;
992 
993     if (DuplicateHandle(GetCurrentProcess(), info_od->handle,
994      GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
995     {
996       int wxflag = info_od->wxflag & ~WX_DONTINHERIT;
997 
998       if (info_nd->wxflag & WX_OPEN)
999         _close(nd);
1000 
1001       msvcrt_set_fd(info_nd, handle, wxflag);
1002       /* _dup2 returns 0, not nd, on success */
1003       ret = 0;
1004     }
1005     else
1006     {
1007       ret = -1;
1008       _dosmaperr(GetLastError());
1009     }
1010   }
1011   else
1012   {
1013     *_errno() = EBADF;
1014     ret = -1;
1015   }
1016 
1017   release_ioinfo(info_od);
1018   release_ioinfo(info_nd);
1019   return ret;
1020 }
1021 
1022 /*********************************************************************
1023  *		_dup (MSVCRT.@)
1024  */
1025 int CDECL _dup(int od)
1026 {
1027   int fd, ret;
1028   ioinfo *info = get_ioinfo_alloc(&fd);
1029 
1030   if (_dup2(od, fd) == 0)
1031     ret = fd;
1032   else
1033     ret = -1;
1034   release_ioinfo(info);
1035   return ret;
1036 }
1037 
1038 /*********************************************************************
1039  *		_eof (MSVCRT.@)
1040  */
1041 int CDECL _eof(int fd)
1042 {
1043   ioinfo *info = get_ioinfo(fd);
1044   DWORD curpos,endpos;
1045   LONG hcurpos,hendpos;
1046 
1047   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1048 
1049   if (info->handle == INVALID_HANDLE_VALUE)
1050   {
1051     release_ioinfo(info);
1052     return -1;
1053   }
1054 
1055   if (info->wxflag & WX_ATEOF)
1056   {
1057       release_ioinfo(info);
1058       return TRUE;
1059   }
1060 
1061   /* Otherwise we do it the hard way */
1062   hcurpos = hendpos = 0;
1063   curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT);
1064   endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END);
1065 
1066   if (curpos == endpos && hcurpos == hendpos)
1067   {
1068     /* FIXME: shouldn't WX_ATEOF be set here? */
1069     release_ioinfo(info);
1070     return TRUE;
1071   }
1072 
1073   SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN);
1074   release_ioinfo(info);
1075   return FALSE;
1076 }
1077 
1078 /*********************************************************************
1079  *		_fcloseall (MSVCRT.@)
1080  */
1081 int CDECL _fcloseall(void)
1082 {
1083   int num_closed = 0, i;
1084   FILE *file;
1085 
1086   LOCK_FILES();
1087   for (i = 3; i < MSVCRT_stream_idx; i++) {
1088     file = msvcrt_get_file(i);
1089 
1090     if (file->_flag && !fclose(file))
1091       num_closed++;
1092   }
1093   UNLOCK_FILES();
1094 
1095   TRACE(":closed (%d) handles\n",num_closed);
1096   return num_closed;
1097 }
1098 
1099 /* free everything on process exit */
1100 void msvcrt_free_io(void)
1101 {
1102     unsigned int i;
1103     int j;
1104 
1105     _flushall();
1106     _fcloseall();
1107 
1108     for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
1109     {
1110         if(!__pioinfo[i])
1111             continue;
1112 
1113         for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++)
1114         {
1115             if(__pioinfo[i][j].exflag & EF_CRIT_INIT)
1116                 DeleteCriticalSection(&__pioinfo[i][j].crit);
1117         }
1118         free(__pioinfo[i]);
1119     }
1120 
1121     for(j=0; j<MSVCRT_stream_idx; j++)
1122     {
1123         FILE *file = msvcrt_get_file(j);
1124         if(file<_iob || file>=_iob+_IOB_ENTRIES)
1125         {
1126             ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1127             DeleteCriticalSection(&((file_crit*)file)->crit);
1128         }
1129     }
1130 
1131     for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1132         free(MSVCRT_fstream[i]);
1133 }
1134 
1135 /*********************************************************************
1136  *		_lseeki64 (MSVCRT.@)
1137  */
1138 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1139 {
1140   ioinfo *info = get_ioinfo(fd);
1141   LARGE_INTEGER ofs;
1142 
1143   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1144 
1145   if (info->handle == INVALID_HANDLE_VALUE)
1146   {
1147     release_ioinfo(info);
1148     return -1;
1149   }
1150 
1151   if (whence < 0 || whence > 2)
1152   {
1153     release_ioinfo(info);
1154     *_errno() = EINVAL;
1155     return -1;
1156   }
1157 
1158   TRACE(":fd (%d) to %s pos %s\n",
1159         fd,wine_dbgstr_longlong(offset),
1160         (whence==SEEK_SET)?"SEEK_SET":
1161         (whence==SEEK_CUR)?"SEEK_CUR":
1162         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1163 
1164   /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1165    * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1166   ofs.QuadPart = offset;
1167   if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1168       GetLastError() == ERROR_SUCCESS)
1169   {
1170     info->wxflag &= ~(WX_ATEOF|WX_READEOF);
1171     /* FIXME: What if we seek _to_ EOF - is EOF set? */
1172 
1173     release_ioinfo(info);
1174     return ofs.QuadPart;
1175   }
1176   release_ioinfo(info);
1177   TRACE(":error-last error (%d)\n",GetLastError());
1178   _dosmaperr(GetLastError());
1179   return -1;
1180 }
1181 
1182 /*********************************************************************
1183  *		_lseek (MSVCRT.@)
1184  */
1185 LONG CDECL _lseek(int fd, LONG offset, int whence)
1186 {
1187     return (LONG)_lseeki64(fd, offset, whence);
1188 }
1189 
1190 /*********************************************************************
1191  *              _lock_file (MSVCRT.@)
1192  */
1193 void CDECL _lock_file(FILE *file)
1194 {
1195     if(file>=_iob && file<_iob+_IOB_ENTRIES)
1196         _lock(_STREAM_LOCKS+(file-_iob));
1197     /* ReactOS: string streams dont need to be locked */
1198     else if(!(file->_flag & _IOSTRG))
1199         EnterCriticalSection(&((file_crit*)file)->crit);
1200 }
1201 
1202 /*********************************************************************
1203  *              _unlock_file (MSVCRT.@)
1204  */
1205 void CDECL _unlock_file(FILE *file)
1206 {
1207     if(file>=_iob && file<_iob+_IOB_ENTRIES)
1208         _unlock(_STREAM_LOCKS+(file-_iob));
1209     /* ReactOS: string streams dont need to be locked */
1210     else if(!(file->_flag & _IOSTRG))
1211         LeaveCriticalSection(&((file_crit*)file)->crit);
1212 
1213 }
1214 
1215 /*********************************************************************
1216  *		_locking (MSVCRT.@)
1217  *
1218  * This is untested; the underlying LockFile doesn't work yet.
1219  */
1220 int CDECL _locking(int fd, int mode, LONG nbytes)
1221 {
1222   ioinfo *info = get_ioinfo(fd);
1223   BOOL ret;
1224   DWORD cur_locn;
1225 
1226   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1227   if (info->handle == INVALID_HANDLE_VALUE)
1228   {
1229     release_ioinfo(info);
1230     return -1;
1231   }
1232 
1233   if (mode < 0 || mode > 4)
1234   {
1235     release_ioinfo(info);
1236     *_errno() = EINVAL;
1237     return -1;
1238   }
1239 
1240   TRACE(":fd (%d) by 0x%08x mode %s\n",
1241         fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
1242         (mode==_LK_LOCK)?"_LK_LOCK":
1243         (mode==_LK_NBLCK)?"_LK_NBLCK":
1244         (mode==_LK_RLCK)?"_LK_RLCK":
1245         (mode==_LK_NBRLCK)?"_LK_NBRLCK":
1246                           "UNKNOWN");
1247 
1248   if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, FILE_CURRENT)) == INVALID_SET_FILE_POINTER)
1249   {
1250     release_ioinfo(info);
1251     FIXME ("Seek failed\n");
1252     *_errno() = EINVAL; /* FIXME */
1253     return -1;
1254   }
1255   if (mode == _LK_LOCK || mode == _LK_RLCK)
1256   {
1257     int nretry = 10;
1258     ret = 1; /* just to satisfy gcc */
1259     while (nretry--)
1260     {
1261       ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1262       if (ret) break;
1263       Sleep(1);
1264     }
1265   }
1266   else if (mode == _LK_UNLCK)
1267     ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1268   else
1269     ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1270   /* FIXME - what about error settings? */
1271   release_ioinfo(info);
1272   return ret ? 0 : -1;
1273 }
1274 
1275 /*********************************************************************
1276  *		_fseeki64 (MSVCRT.@)
1277  */
1278 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1279 {
1280   int ret;
1281 
1282   _lock_file(file);
1283   /* Flush output if needed */
1284   if(file->_flag & _IOWRT)
1285 	msvcrt_flush_buffer(file);
1286 
1287   if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1288       whence = SEEK_SET;
1289       offset += _ftelli64(file);
1290   }
1291 
1292   /* Discard buffered input */
1293   file->_cnt = 0;
1294   file->_ptr = file->_base;
1295   /* Reset direction of i/o */
1296   if(file->_flag & _IORW) {
1297         file->_flag &= ~(_IOREAD|_IOWRT);
1298   }
1299   /* Clear end of file flag */
1300   file->_flag &= ~_IOEOF;
1301   ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1302 
1303   _unlock_file(file);
1304   return ret;
1305 }
1306 
1307 /*********************************************************************
1308  *		fseek (MSVCRT.@)
1309  */
1310 int CDECL fseek(FILE* file, long offset, int whence)
1311 {
1312     return _fseeki64( file, offset, whence );
1313 }
1314 
1315 /*********************************************************************
1316  *		_chsize_s (MSVCRT.@)
1317  */
1318 int CDECL _chsize_s(int fd, __int64 size)
1319 {
1320     ioinfo *info;
1321     __int64 cur, pos;
1322     BOOL ret = FALSE;
1323 
1324     TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size));
1325 
1326     if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
1327 
1328     info = get_ioinfo(fd);
1329     if (info->handle != INVALID_HANDLE_VALUE)
1330     {
1331         /* save the current file pointer */
1332         cur = _lseeki64(fd, 0, SEEK_CUR);
1333         if (cur >= 0)
1334         {
1335             pos = _lseeki64(fd, size, SEEK_SET);
1336             if (pos >= 0)
1337             {
1338                 ret = SetEndOfFile(info->handle);
1339                 if (!ret) _dosmaperr(GetLastError());
1340             }
1341 
1342             /* restore the file pointer */
1343             _lseeki64(fd, cur, SEEK_SET);
1344         }
1345     }
1346 
1347     release_ioinfo(info);
1348     return ret ? 0 : *_errno();
1349 }
1350 
1351 /*********************************************************************
1352  *		_chsize (MSVCRT.@)
1353  */
1354 int CDECL _chsize(int fd, long size)
1355 {
1356     /* _chsize_s returns errno on failure but _chsize should return -1 */
1357     return _chsize_s( fd, size ) == 0 ? 0 : -1;
1358 }
1359 
1360 /*********************************************************************
1361  *		clearerr (MSVCRT.@)
1362  */
1363 void CDECL clearerr(FILE* file)
1364 {
1365   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1366 
1367   _lock_file(file);
1368   file->_flag &= ~(_IOERR | _IOEOF);
1369   _unlock_file(file);
1370 }
1371 
1372 /*********************************************************************
1373  *		rewind (MSVCRT.@)
1374  */
1375 void CDECL rewind(FILE* file)
1376 {
1377   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1378 
1379   _lock_file(file);
1380   fseek(file, 0L, SEEK_SET);
1381   clearerr(file);
1382   _unlock_file(file);
1383 }
1384 
1385 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1386 {
1387   int plus = strchrW(mode, '+') != NULL;
1388 
1389   TRACE("%s\n", debugstr_w(mode));
1390 
1391   while(*mode == ' ') mode++;
1392 
1393   switch(*mode++)
1394   {
1395   case 'R': case 'r':
1396     *open_flags = plus ? _O_RDWR : _O_RDONLY;
1397     *stream_flags = plus ? _IORW : _IOREAD;
1398     break;
1399   case 'W': case 'w':
1400     *open_flags = _O_CREAT | _O_TRUNC | (plus  ? _O_RDWR : _O_WRONLY);
1401     *stream_flags = plus ? _IORW : _IOWRT;
1402     break;
1403   case 'A': case 'a':
1404     *open_flags = _O_CREAT | _O_APPEND | (plus  ? _O_RDWR : _O_WRONLY);
1405     *stream_flags = plus ? _IORW : _IOWRT;
1406     break;
1407   default:
1408     MSVCRT_INVALID_PMT(0, EINVAL);
1409     return -1;
1410   }
1411 
1412   *stream_flags |= _commode;
1413 
1414   while (*mode && *mode!=',')
1415     switch (*mode++)
1416     {
1417     case 'B': case 'b':
1418       *open_flags |=  _O_BINARY;
1419       *open_flags &= ~_O_TEXT;
1420       break;
1421     case 't':
1422       *open_flags |=  _O_TEXT;
1423       *open_flags &= ~_O_BINARY;
1424       break;
1425     case 'D':
1426       *open_flags |= _O_TEMPORARY;
1427       break;
1428     case 'T':
1429       *open_flags |= _O_SHORT_LIVED;
1430       break;
1431     case 'c':
1432       *stream_flags |= _IOCOMMIT;
1433       break;
1434     case 'n':
1435       *stream_flags &= ~_IOCOMMIT;
1436       break;
1437     case 'N':
1438       *open_flags |= _O_NOINHERIT;
1439       break;
1440     case '+':
1441     case ' ':
1442     case 'a':
1443     case 'w':
1444       break;
1445     case 'S':
1446     case 'R':
1447       FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1448       break;
1449     default:
1450       ERR("incorrect mode flag: %c\n", mode[-1]);
1451       break;
1452     }
1453 
1454   if(*mode == ',')
1455   {
1456     static const WCHAR ccs[] = {'c','c','s'};
1457     static const WCHAR utf8[] = {'u','t','f','-','8'};
1458     static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1459     static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1460 
1461     mode++;
1462     while(*mode == ' ') mode++;
1463     if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1464       return -1;
1465     mode += sizeof(ccs)/sizeof(ccs[0]);
1466     while(*mode == ' ') mode++;
1467     if(!MSVCRT_CHECK_PMT(*mode == '='))
1468         return -1;
1469     mode++;
1470     while(*mode == ' ') mode++;
1471 
1472     if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1473     {
1474       *open_flags |= _O_U8TEXT;
1475       mode += sizeof(utf8)/sizeof(utf8[0]);
1476     }
1477     else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1478     {
1479       *open_flags |= _O_U16TEXT;
1480       mode += sizeof(utf16le)/sizeof(utf16le[0]);
1481     }
1482     else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1483     {
1484       *open_flags |= _O_WTEXT;
1485       mode += sizeof(unicode)/sizeof(unicode[0]);
1486     }
1487     else
1488     {
1489       MSVCRT_INVALID_PMT(0, EINVAL);
1490       return -1;
1491     }
1492 
1493     while(*mode == ' ') mode++;
1494   }
1495 
1496   if(!MSVCRT_CHECK_PMT(*mode == 0))
1497     return -1;
1498   return 0;
1499 }
1500 
1501 /*********************************************************************
1502  *		_fdopen (MSVCRT.@)
1503  */
1504 FILE* CDECL _fdopen(int fd, const char *mode)
1505 {
1506     FILE *ret;
1507     wchar_t *modeW = NULL;
1508 
1509     if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1510 
1511     ret = _wfdopen(fd, modeW);
1512 
1513     free(modeW);
1514     return ret;
1515 }
1516 
1517 /*********************************************************************
1518  *		_wfdopen (MSVCRT.@)
1519  */
1520 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1521 {
1522   int open_flags, stream_flags;
1523   FILE* file;
1524 
1525   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1526 
1527   LOCK_FILES();
1528   if (!(file = msvcrt_alloc_fp()))
1529     file = NULL;
1530   else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1531   {
1532     file->_flag = 0;
1533     file = NULL;
1534   }
1535   else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1536   UNLOCK_FILES();
1537 
1538   return file;
1539 }
1540 
1541 /*********************************************************************
1542  *		_filelength (MSVCRT.@)
1543  */
1544 LONG CDECL _filelength(int fd)
1545 {
1546   LONG curPos = _lseek(fd, 0, SEEK_CUR);
1547   if (curPos != -1)
1548   {
1549     LONG endPos = _lseek(fd, 0, SEEK_END);
1550     if (endPos != -1)
1551     {
1552       if (endPos != curPos)
1553         _lseek(fd, curPos, SEEK_SET);
1554       return endPos;
1555     }
1556   }
1557   return -1;
1558 }
1559 
1560 /*********************************************************************
1561  *		_filelengthi64 (MSVCRT.@)
1562  */
1563 __int64 CDECL _filelengthi64(int fd)
1564 {
1565   __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1566   if (curPos != -1)
1567   {
1568     __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1569     if (endPos != -1)
1570     {
1571       if (endPos != curPos)
1572         _lseeki64(fd, curPos, SEEK_SET);
1573       return endPos;
1574     }
1575   }
1576   return -1;
1577 }
1578 
1579 /*********************************************************************
1580  *		_fileno (MSVCRT.@)
1581  */
1582 int CDECL _fileno(FILE* file)
1583 {
1584   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1585   return file->_file;
1586 }
1587 
1588 /*********************************************************************
1589  *		_get_osfhandle (MSVCRT.@)
1590  */
1591 intptr_t CDECL _get_osfhandle(int fd)
1592 {
1593   HANDLE hand = get_ioinfo_nolock(fd)->handle;
1594   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1595 
1596   if(hand == INVALID_HANDLE_VALUE)
1597       *_errno() = EBADF;
1598   return (intptr_t)hand;
1599 }
1600 
1601 /*********************************************************************
1602  *		_mktemp (MSVCRT.@)
1603  */
1604 char * CDECL _mktemp(char *pattern)
1605 {
1606   int numX = 0;
1607   char *retVal = pattern;
1608   int id;
1609   char letter = 'a';
1610 
1611   if(!pattern)
1612       return NULL;
1613 
1614   while(*pattern)
1615     numX = (*pattern++ == 'X')? numX + 1 : 0;
1616   if (numX < 6)
1617     return NULL;
1618   pattern--;
1619   id = GetCurrentProcessId();
1620   numX = 6;
1621   while(numX--)
1622   {
1623     int tempNum = id / 10;
1624     *pattern-- = id - (tempNum * 10) + '0';
1625     id = tempNum;
1626   }
1627   pattern++;
1628   do
1629   {
1630     *pattern = letter++;
1631     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
1632       return retVal;
1633   } while(letter <= 'z');
1634   return NULL;
1635 }
1636 
1637 /*********************************************************************
1638  *		_wmktemp (MSVCRT.@)
1639  */
1640 wchar_t * CDECL _wmktemp(wchar_t *pattern)
1641 {
1642   int numX = 0;
1643   wchar_t *retVal = pattern;
1644   int id;
1645   wchar_t letter = 'a';
1646 
1647   while(*pattern)
1648     numX = (*pattern++ == 'X')? numX + 1 : 0;
1649   if (numX < 5)
1650     return NULL;
1651   pattern--;
1652   id = GetCurrentProcessId();
1653   numX = 6;
1654   while(numX--)
1655   {
1656     int tempNum = id / 10;
1657     *pattern-- = id - (tempNum * 10) + '0';
1658     id = tempNum;
1659   }
1660   pattern++;
1661   do
1662   {
1663     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1664         GetLastError() == ERROR_FILE_NOT_FOUND)
1665       return retVal;
1666     *pattern = letter++;
1667   } while(letter != '|');
1668   return NULL;
1669 }
1670 
1671 /*static*/ unsigned split_oflags(unsigned oflags)
1672 {
1673     int wxflags = 0;
1674     unsigned unsupp; /* until we support everything */
1675 
1676     if (oflags & _O_APPEND)              wxflags |= WX_APPEND;
1677     if (oflags & _O_BINARY)              {/* Nothing to do */}
1678     else if (oflags & _O_TEXT)           wxflags |= WX_TEXT;
1679     else if (oflags & _O_WTEXT)          wxflags |= WX_TEXT;
1680     else if (oflags & _O_U16TEXT)        wxflags |= WX_TEXT;
1681     else if (oflags & _O_U8TEXT)         wxflags |= WX_TEXT;
1682     else if (*__p__fmode() & _O_BINARY)  {/* Nothing to do */}
1683     else                                        wxflags |= WX_TEXT; /* default to TEXT*/
1684     if (oflags & _O_NOINHERIT)           wxflags |= WX_DONTINHERIT;
1685 
1686     if ((unsupp = oflags & ~(
1687                     _O_BINARY|_O_TEXT|_O_APPEND|
1688                     _O_TRUNC|_O_EXCL|_O_CREAT|
1689                     _O_RDWR|_O_WRONLY|_O_TEMPORARY|
1690                     _O_NOINHERIT|
1691                     _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
1692                     _O_WTEXT|_O_U16TEXT|_O_U8TEXT
1693                     )))
1694         ERR(":unsupported oflags 0x%04x\n",unsupp);
1695 
1696     return wxflags;
1697 }
1698 
1699 /*********************************************************************
1700  *              _pipe (MSVCRT.@)
1701  */
1702 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
1703 {
1704   int ret = -1;
1705   SECURITY_ATTRIBUTES sa;
1706   HANDLE readHandle, writeHandle;
1707 
1708   if (!pfds)
1709   {
1710     *_errno() = EINVAL;
1711     return -1;
1712   }
1713 
1714   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1715   sa.bInheritHandle = !(textmode & _O_NOINHERIT);
1716   sa.lpSecurityDescriptor = NULL;
1717   if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1718   {
1719     unsigned int wxflags = split_oflags(textmode);
1720     int fd;
1721 
1722     fd = msvcrt_alloc_fd(readHandle, wxflags);
1723     if (fd != -1)
1724     {
1725       pfds[0] = fd;
1726       fd = msvcrt_alloc_fd(writeHandle, wxflags);
1727       if (fd != -1)
1728       {
1729         pfds[1] = fd;
1730         ret = 0;
1731       }
1732       else
1733       {
1734         _close(pfds[0]);
1735         CloseHandle(writeHandle);
1736         *_errno() = EMFILE;
1737       }
1738     }
1739     else
1740     {
1741       CloseHandle(readHandle);
1742       CloseHandle(writeHandle);
1743       *_errno() = EMFILE;
1744     }
1745   }
1746   else
1747     _dosmaperr(GetLastError());
1748 
1749   return ret;
1750 }
1751 
1752 static int check_bom(HANDLE h, int oflags, BOOL seek)
1753 {
1754     char bom[sizeof(utf8_bom)];
1755     DWORD r;
1756 
1757     oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1758 
1759     if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1760         return oflags;
1761 
1762     if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1763         oflags |= _O_U8TEXT;
1764     }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1765         if (seek && r>2)
1766             SetFilePointer(h, 2, NULL, FILE_BEGIN);
1767         oflags |= _O_U16TEXT;
1768     }else if (seek) {
1769         SetFilePointer(h, 0, NULL, FILE_BEGIN);
1770     }
1771 
1772     return oflags;
1773 }
1774 
1775 /*********************************************************************
1776  *              _wsopen_s (MSVCRT.@)
1777  */
1778 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
1779 {
1780   DWORD access = 0, creation = 0, attrib;
1781   SECURITY_ATTRIBUTES sa;
1782   DWORD sharing, type;
1783   int wxflag;
1784   HANDLE hand;
1785 
1786   TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1787         fd, debugstr_w(path), oflags, shflags, pmode);
1788 
1789   if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
1790 
1791   *fd = -1;
1792   wxflag = split_oflags(oflags);
1793   switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1794   {
1795   case _O_RDONLY: access |= GENERIC_READ; break;
1796   case _O_WRONLY: access |= GENERIC_WRITE; break;
1797   case _O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1798   }
1799 
1800   if (oflags & _O_CREAT)
1801   {
1802     if(pmode & ~(_S_IREAD | _S_IWRITE))
1803       FIXME(": pmode 0x%04x ignored\n", pmode);
1804     else
1805       WARN(": pmode 0x%04x ignored\n", pmode);
1806 
1807     if (oflags & _O_EXCL)
1808       creation = CREATE_NEW;
1809     else if (oflags & _O_TRUNC)
1810       creation = CREATE_ALWAYS;
1811     else
1812       creation = OPEN_ALWAYS;
1813   }
1814   else  /* no _O_CREAT */
1815   {
1816     if (oflags & _O_TRUNC)
1817       creation = TRUNCATE_EXISTING;
1818     else
1819       creation = OPEN_EXISTING;
1820   }
1821 
1822   switch( shflags )
1823   {
1824     case _SH_DENYRW:
1825       sharing = 0L;
1826       break;
1827     case _SH_DENYWR:
1828       sharing = FILE_SHARE_READ;
1829       break;
1830     case _SH_DENYRD:
1831       sharing = FILE_SHARE_WRITE;
1832       break;
1833     case _SH_DENYNO:
1834       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1835       break;
1836     default:
1837       ERR( "Unhandled shflags 0x%x\n", shflags );
1838       return EINVAL;
1839   }
1840   attrib = FILE_ATTRIBUTE_NORMAL;
1841 
1842   if (oflags & _O_TEMPORARY)
1843   {
1844       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1845       access |= DELETE;
1846       sharing |= FILE_SHARE_DELETE;
1847   }
1848 
1849   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1850   sa.lpSecurityDescriptor = NULL;
1851   sa.bInheritHandle       = !(oflags & _O_NOINHERIT);
1852 
1853   if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1854           && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1855           && !(access&GENERIC_READ))
1856   {
1857       hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1858               &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1859       if (hand != INVALID_HANDLE_VALUE)
1860       {
1861           oflags = check_bom(hand, oflags, FALSE);
1862           CloseHandle(hand);
1863       }
1864       else
1865           oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1866   }
1867 
1868   hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1869   if (hand == INVALID_HANDLE_VALUE)  {
1870     WARN(":failed-last error (%d)\n",GetLastError());
1871     _dosmaperr(GetLastError());
1872     return *_errno();
1873   }
1874 
1875   if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
1876   {
1877       if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1878                   || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1879                   || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1880       {
1881           if (oflags & _O_U8TEXT)
1882           {
1883               DWORD written = 0, tmp;
1884 
1885               while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1886                           sizeof(utf8_bom)-written, &tmp, NULL))
1887                   written += tmp;
1888               if (written != sizeof(utf8_bom)) {
1889                   WARN("error writing BOM\n");
1890                   CloseHandle(hand);
1891                   _dosmaperr(GetLastError());
1892                   return *_errno();
1893               }
1894           }
1895           else
1896           {
1897               DWORD written = 0, tmp;
1898 
1899               while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1900                           sizeof(utf16_bom)-written, &tmp, NULL))
1901                   written += tmp;
1902               if (written != sizeof(utf16_bom))
1903               {
1904                   WARN("error writing BOM\n");
1905                   CloseHandle(hand);
1906                   _dosmaperr(GetLastError());
1907                   return *_errno();
1908               }
1909           }
1910       }
1911       else if (access & GENERIC_READ)
1912           oflags = check_bom(hand, oflags, TRUE);
1913   }
1914 
1915   type = GetFileType(hand);
1916   if (type == FILE_TYPE_CHAR)
1917       wxflag |= WX_TTY;
1918   else if (type == FILE_TYPE_PIPE)
1919       wxflag |= WX_PIPE;
1920 
1921   *fd = msvcrt_alloc_fd(hand, wxflag);
1922   if (*fd == -1)
1923       return *_errno();
1924 
1925   if (oflags & _O_WTEXT)
1926       get_ioinfo_nolock(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1927   else if (oflags & _O_U16TEXT)
1928       get_ioinfo_nolock(*fd)->exflag |= EF_UTF16;
1929   else if (oflags & _O_U8TEXT)
1930       get_ioinfo_nolock(*fd)->exflag |= EF_UTF8;
1931 
1932   TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1933   return 0;
1934 }
1935 
1936 /*********************************************************************
1937  *              _wsopen (MSVCRT.@)
1938  */
1939 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
1940 {
1941   int pmode;
1942   int fd;
1943 
1944   if (oflags & _O_CREAT)
1945   {
1946     __ms_va_list ap;
1947 
1948     __ms_va_start(ap, shflags);
1949     pmode = va_arg(ap, int);
1950     __ms_va_end(ap);
1951   }
1952   else
1953     pmode = 0;
1954 
1955   _wsopen_s(&fd, path, oflags, shflags, pmode);
1956   return fd;
1957 }
1958 
1959 /*********************************************************************
1960  *              _sopen_s (MSVCRT.@)
1961  */
1962 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1963 {
1964     wchar_t *pathW;
1965     int ret;
1966 
1967     if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
1968         return EINVAL;
1969 
1970     ret = _wsopen_s(fd, pathW, oflags, shflags, pmode);
1971     free(pathW);
1972     return ret;
1973 }
1974 
1975 /*********************************************************************
1976  *              _sopen (MSVCRT.@)
1977  */
1978 int CDECL _sopen( const char *path, int oflags, int shflags, ... )
1979 {
1980   int pmode;
1981   int fd;
1982 
1983   if (oflags & _O_CREAT)
1984   {
1985     va_list ap;
1986 
1987     va_start(ap, shflags);
1988     pmode = va_arg(ap, int);
1989     va_end(ap);
1990   }
1991   else
1992     pmode = 0;
1993 
1994   _sopen_s(&fd, path, oflags, shflags, pmode);
1995   return fd;
1996 }
1997 
1998 /*********************************************************************
1999  *              _open (MSVCRT.@)
2000  */
2001 int CDECL _open( const char *path, int flags, ... )
2002 {
2003   va_list ap;
2004 
2005   if (flags & _O_CREAT)
2006   {
2007     int pmode;
2008     va_start(ap, flags);
2009     pmode = va_arg(ap, int);
2010     va_end(ap);
2011     return _sopen( path, flags, _SH_DENYNO, pmode );
2012   }
2013   else
2014     return _sopen( path, flags, _SH_DENYNO);
2015 }
2016 
2017 /*********************************************************************
2018  *              _wopen (MSVCRT.@)
2019  */
2020 int CDECL _wopen(const wchar_t *path,int flags,...)
2021 {
2022   va_list ap;
2023 
2024   if (flags & _O_CREAT)
2025   {
2026     int pmode;
2027     va_start(ap, flags);
2028     pmode = va_arg(ap, int);
2029     va_end(ap);
2030     return _wsopen( path, flags, _SH_DENYNO, pmode );
2031   }
2032   else
2033     return _wsopen( path, flags, _SH_DENYNO);
2034 }
2035 
2036 /*********************************************************************
2037  *		_creat (MSVCRT.@)
2038  */
2039 int CDECL _creat(const char *path, int flags)
2040 {
2041   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2042   return _open(path, usedFlags);
2043 }
2044 
2045 /*********************************************************************
2046  *		_wcreat (MSVCRT.@)
2047  */
2048 int CDECL _wcreat(const wchar_t *path, int flags)
2049 {
2050   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2051   return _wopen(path, usedFlags);
2052 }
2053 
2054 /*********************************************************************
2055  *		_open_osfhandle (MSVCRT.@)
2056  */
2057 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2058 {
2059   DWORD flags;
2060   int fd;
2061 
2062   /* _O_RDONLY (0) always matches, so set the read flag
2063    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2064    * file, so set the write flag. It also only sets _O_TEXT if it wants
2065    * text - it never sets _O_BINARY.
2066    */
2067   /* don't let split_oflags() decide the mode if no mode is passed */
2068   if (!(oflags & (_O_BINARY | _O_TEXT)))
2069       oflags |= _O_BINARY;
2070 
2071   flags = GetFileType((HANDLE)handle);
2072   if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2073   {
2074     _dosmaperr(GetLastError());
2075     return -1;
2076   }
2077 
2078   if (flags == FILE_TYPE_CHAR)
2079     flags = WX_TTY;
2080   else if (flags == FILE_TYPE_PIPE)
2081     flags = WX_PIPE;
2082   else
2083     flags = 0;
2084   flags |= split_oflags(oflags);
2085 
2086   fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2087   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags);
2088   return fd;
2089 }
2090 
2091 /*********************************************************************
2092  *		_rmtmp (MSVCRT.@)
2093  */
2094 int CDECL _rmtmp(void)
2095 {
2096   int num_removed = 0, i;
2097   FILE *file;
2098 
2099   LOCK_FILES();
2100   for (i = 3; i < MSVCRT_stream_idx; i++) {
2101     file = msvcrt_get_file(i);
2102 
2103     if (file->_tmpfname)
2104     {
2105       fclose(file);
2106       num_removed++;
2107     }
2108   }
2109   UNLOCK_FILES();
2110 
2111   if (num_removed)
2112     TRACE(":removed (%d) temp files\n",num_removed);
2113   return num_removed;
2114 }
2115 
2116 static inline int get_utf8_char_len(char ch)
2117 {
2118     if((ch&0xf8) == 0xf0)
2119         return 4;
2120     else if((ch&0xf0) == 0xe0)
2121         return 3;
2122     else if((ch&0xe0) == 0xc0)
2123         return 2;
2124     return 1;
2125 }
2126 
2127 /*********************************************************************
2128  * (internal) read_utf8
2129  */
2130 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2131 {
2132     HANDLE hand = fdinfo->handle;
2133     char min_buf[4], *readbuf, lookahead;
2134     DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2135 
2136     /* make the buffer big enough to hold at least one character */
2137     /* read bytes have to fit to output and lookahead buffers */
2138     count /= 2;
2139     readbuf_size = count < 4 ? 4 : count;
2140     if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2141         readbuf_size = 4;
2142         readbuf = min_buf;
2143     }
2144 
2145     if(fdinfo->lookahead[0] != '\n') {
2146         readbuf[pos++] = fdinfo->lookahead[0];
2147         fdinfo->lookahead[0] = '\n';
2148 
2149         if(fdinfo->lookahead[1] != '\n') {
2150             readbuf[pos++] = fdinfo->lookahead[1];
2151             fdinfo->lookahead[1] = '\n';
2152 
2153             if(fdinfo->lookahead[2] != '\n') {
2154                 readbuf[pos++] = fdinfo->lookahead[2];
2155                 fdinfo->lookahead[2] = '\n';
2156             }
2157         }
2158     }
2159 
2160     /* NOTE: this case is broken in native dll, reading
2161      *        sometimes fails when small buffer is passed
2162      */
2163     if(count < 4) {
2164         if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2165             if (GetLastError() == ERROR_BROKEN_PIPE) {
2166                 fdinfo->wxflag |= WX_ATEOF;
2167                 return 0;
2168             }else {
2169                 _dosmaperr(GetLastError());
2170                 return -1;
2171             }
2172         }else if(!num_read) {
2173             fdinfo->wxflag |= WX_ATEOF;
2174             return 0;
2175         }else {
2176             pos++;
2177         }
2178 
2179         char_len = get_utf8_char_len(readbuf[0]);
2180         if(char_len>pos) {
2181             if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2182                 pos += num_read;
2183         }
2184 
2185         if(readbuf[0] == '\n')
2186             fdinfo->wxflag |= WX_READNL;
2187         else
2188             fdinfo->wxflag &= ~WX_READNL;
2189 
2190         if(readbuf[0] == 0x1a) {
2191             fdinfo->wxflag |= WX_ATEOF;
2192             return 0;
2193         }
2194 
2195         if(readbuf[0] == '\r') {
2196             if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2197                 buf[0] = '\r';
2198             else if(lookahead == '\n')
2199                 buf[0] = '\n';
2200             else {
2201                 buf[0] = '\r';
2202                 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2203                     fdinfo->lookahead[0] = lookahead;
2204                 else
2205                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2206             }
2207             return 2;
2208         }
2209 
2210         if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2211             _dosmaperr(GetLastError());
2212             return -1;
2213         }
2214 
2215         return num_read*2;
2216     }
2217 
2218     if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2219         if(pos) {
2220             num_read = 0;
2221         }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2222             fdinfo->wxflag |= WX_ATEOF;
2223             if (readbuf != min_buf) free(readbuf);
2224             return 0;
2225         }else {
2226             _dosmaperr(GetLastError());
2227             if (readbuf != min_buf) free(readbuf);
2228             return -1;
2229         }
2230     }else if(!pos && !num_read) {
2231         fdinfo->wxflag |= WX_ATEOF;
2232         if (readbuf != min_buf) free(readbuf);
2233         return 0;
2234     }
2235 
2236     pos += num_read;
2237     if(readbuf[0] == '\n')
2238         fdinfo->wxflag |= WX_READNL;
2239     else
2240         fdinfo->wxflag &= ~WX_READNL;
2241 
2242     /* Find first byte of last character (may be incomplete) */
2243     for(i=pos-1; i>0 && i>pos-4; i--)
2244         if((readbuf[i]&0xc0) != 0x80)
2245             break;
2246     char_len = get_utf8_char_len(readbuf[i]);
2247     if(char_len+i <= pos)
2248         i += char_len;
2249 
2250     if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2251         if(i < pos)
2252             fdinfo->lookahead[0] = readbuf[i];
2253         if(i+1 < pos)
2254             fdinfo->lookahead[1] = readbuf[i+1];
2255         if(i+2 < pos)
2256             fdinfo->lookahead[2] = readbuf[i+2];
2257     }else if(i < pos) {
2258         SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2259     }
2260     pos = i;
2261 
2262     for(i=0, j=0; i<pos; i++) {
2263         if(readbuf[i] == 0x1a) {
2264             fdinfo->wxflag |= WX_ATEOF;
2265             break;
2266         }
2267 
2268         /* strip '\r' if followed by '\n' */
2269         if(readbuf[i] == '\r' && i+1==pos) {
2270             if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2271                 readbuf[j++] = '\r';
2272             }else if(lookahead == '\n' && j==0) {
2273                 readbuf[j++] = '\n';
2274             }else {
2275                 if(lookahead != '\n')
2276                     readbuf[j++] = '\r';
2277 
2278                 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2279                     fdinfo->lookahead[0] = lookahead;
2280                 else
2281                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2282             }
2283         }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2284             readbuf[j++] = readbuf[i];
2285         }
2286     }
2287     pos = j;
2288 
2289     if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2290         _dosmaperr(GetLastError());
2291         if (readbuf != min_buf) free(readbuf);
2292         return -1;
2293     }
2294 
2295     if (readbuf != min_buf) free(readbuf);
2296     return num_read*2;
2297 }
2298 
2299 /*********************************************************************
2300  * (internal) read_i
2301  *
2302  * When reading \r as last character in text mode, read() positions
2303  * the file pointer on the \r character while getc() goes on to
2304  * the following \n
2305  */
2306 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2307 {
2308     DWORD num_read, utf16;
2309     char *bufstart = buf;
2310 
2311     if (count == 0)
2312         return 0;
2313 
2314     if (fdinfo->wxflag & WX_ATEOF) {
2315         TRACE("already at EOF, returning 0\n");
2316         return 0;
2317     }
2318     /* Don't trace small reads, it gets *very* annoying */
2319     if (count > 4)
2320         TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2321     if (fdinfo->handle == INVALID_HANDLE_VALUE)
2322     {
2323         *_errno() = EBADF;
2324         return -1;
2325     }
2326 
2327     utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2328     if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2329     {
2330         *_errno() = EINVAL;
2331         return -1;
2332     }
2333 
2334     if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2335         return read_utf8(fdinfo, buf, count);
2336 
2337     if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2338     {
2339         if (fdinfo->lookahead[0] != '\n')
2340         {
2341             bufstart[0] = fdinfo->lookahead[0];
2342             fdinfo->lookahead[0] = '\n';
2343 
2344             if (utf16)
2345             {
2346                 bufstart[1] =  fdinfo->lookahead[1];
2347                 fdinfo->lookahead[1] = '\n';
2348             }
2349 
2350             if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2351                 num_read += 1+utf16;
2352             else
2353                 num_read = 1+utf16;
2354         }
2355 
2356         if(utf16 && (num_read&1))
2357         {
2358             /* msvcr90 uses uninitialized value from the buffer in this case */
2359             /* msvcrt ignores additional data */
2360             ERR("got odd number of bytes in UTF16 mode\n");
2361             num_read--;
2362         }
2363 
2364         if (count != 0 && num_read == 0)
2365         {
2366             fdinfo->wxflag |= WX_ATEOF;
2367             TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2368         }
2369         else if (fdinfo->wxflag & WX_TEXT)
2370         {
2371             DWORD i, j;
2372 
2373             if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2374                 fdinfo->wxflag |= WX_READNL;
2375             else
2376                 fdinfo->wxflag &= ~WX_READNL;
2377 
2378             for (i=0, j=0; i<num_read; i+=1+utf16)
2379             {
2380                 /* in text mode, a ctrl-z signals EOF */
2381                 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2382                 {
2383                     fdinfo->wxflag |= WX_ATEOF;
2384                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2385                     break;
2386                 }
2387 
2388                 /* in text mode, strip \r if followed by \n */
2389                 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2390                 {
2391                     char lookahead[2];
2392                     DWORD len;
2393 
2394                     lookahead[1] = '\n';
2395                     if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
2396                     {
2397                         if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2398                         {
2399                             bufstart[j++] = '\n';
2400                             if(utf16) bufstart[j++] = 0;
2401                         }
2402                         else
2403                         {
2404                             if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2405                             {
2406                                 bufstart[j++] = '\r';
2407                                 if(utf16) bufstart[j++] = 0;
2408                             }
2409 
2410                             if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
2411                             {
2412                                 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
2413                                 {
2414                                     bufstart[j++] = '\n';
2415                                     if (utf16) bufstart[j++] = 0;
2416                                 }
2417                                 else
2418                                 {
2419                                     fdinfo->lookahead[0] = lookahead[0];
2420                                     fdinfo->lookahead[1] = lookahead[1];
2421                                 }
2422                             }
2423                             else
2424                                 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2425                         }
2426                     }
2427                     else
2428                     {
2429                         bufstart[j++] = '\r';
2430                         if(utf16) bufstart[j++] = 0;
2431                     }
2432                 }
2433                 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2434                         || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2435                 {
2436                     bufstart[j++] = bufstart[i];
2437                     if(utf16) bufstart[j++] = bufstart[i+1];
2438                 }
2439             }
2440             num_read = j;
2441         }
2442     }
2443     else
2444     {
2445         if (GetLastError() == ERROR_BROKEN_PIPE)
2446         {
2447             TRACE(":end-of-pipe\n");
2448             fdinfo->wxflag |= WX_ATEOF;
2449             return 0;
2450         }
2451         else
2452         {
2453             TRACE(":failed-last error (%d)\n",GetLastError());
2454             return -1;
2455         }
2456     }
2457 
2458     if (count > 4)
2459         TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2460     return num_read;
2461 }
2462 
2463 /*********************************************************************
2464  *		_read (MSVCRT.@)
2465  */
2466 int CDECL _read(int fd, void *buf, unsigned int count)
2467 {
2468     ioinfo *info = get_ioinfo(fd);
2469     int num_read = read_i(fd, info, buf, count);
2470     release_ioinfo(info);
2471     return num_read;
2472 }
2473 
2474 /*********************************************************************
2475  *		_setmode (MSVCRT.@)
2476  */
2477 int CDECL _setmode(int fd,int mode)
2478 {
2479     ioinfo *info = get_ioinfo(fd);
2480     int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
2481     if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16)))
2482         ret = _O_WTEXT;
2483 
2484     if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
2485                 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
2486         *_errno() = EINVAL;
2487         release_ioinfo(info);
2488         return -1;
2489     }
2490 
2491     if(info == &__badioinfo) {
2492         *_errno() = EBADF;
2493         return EOF;
2494     }
2495 
2496     if(mode == _O_BINARY) {
2497         info->wxflag &= ~WX_TEXT;
2498         info->exflag &= ~(EF_UTF8|EF_UTF16);
2499         release_ioinfo(info);
2500         return ret;
2501     }
2502 
2503     info->wxflag |= WX_TEXT;
2504     if(mode == _O_TEXT)
2505         info->exflag &= ~(EF_UTF8|EF_UTF16);
2506     else if(mode == _O_U8TEXT)
2507         info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8;
2508     else
2509         info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16;
2510 
2511     release_ioinfo(info);
2512     return ret;
2513 
2514 }
2515 
2516 /*********************************************************************
2517  *		_tell (MSVCRT.@)
2518  */
2519 long CDECL _tell(int fd)
2520 {
2521   return _lseek(fd, 0, SEEK_CUR);
2522 }
2523 
2524 /*********************************************************************
2525  *		_telli64 (MSVCRT.@)
2526  */
2527 __int64 CDECL _telli64(int fd)
2528 {
2529   return _lseeki64(fd, 0, SEEK_CUR);
2530 }
2531 
2532 /*********************************************************************
2533  *		_tempnam (MSVCRT.@)
2534  */
2535 char * CDECL _tempnam(const char *dir, const char *prefix)
2536 {
2537   char tmpbuf[MAX_PATH];
2538   const char *tmp_dir = getenv("TMP");
2539 
2540   if (tmp_dir) dir = tmp_dir;
2541 
2542   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2543   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2544   {
2545     TRACE("got name (%s)\n",tmpbuf);
2546     DeleteFileA(tmpbuf);
2547     return _strdup(tmpbuf);
2548   }
2549   TRACE("failed (%d)\n",GetLastError());
2550   return NULL;
2551 }
2552 
2553 /*********************************************************************
2554  *		_wtempnam (MSVCRT.@)
2555  */
2556 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
2557 {
2558   wchar_t tmpbuf[MAX_PATH];
2559 
2560   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2561   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2562   {
2563     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2564     DeleteFileW(tmpbuf);
2565     return _wcsdup(tmpbuf);
2566   }
2567   TRACE("failed (%d)\n",GetLastError());
2568   return NULL;
2569 }
2570 
2571 /*********************************************************************
2572  *		_umask (MSVCRT.@)
2573  */
2574 int CDECL _umask(int umask)
2575 {
2576   int old_umask = MSVCRT_umask;
2577   TRACE("(%d)\n",umask);
2578   MSVCRT_umask = umask;
2579   return old_umask;
2580 }
2581 
2582 /*********************************************************************
2583  *		_write (MSVCRT.@)
2584  */
2585 int CDECL _write(int fd, const void* buf, unsigned int count)
2586 {
2587     DWORD num_written;
2588     ioinfo *info = get_ioinfo(fd);
2589     HANDLE hand = info->handle;
2590 
2591     /* Don't trace small writes, it gets *very* annoying */
2592 #if 0
2593     if (count > 32)
2594         TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2595 #endif
2596     if (hand == INVALID_HANDLE_VALUE)
2597     {
2598         *_errno() = EBADF;
2599         release_ioinfo(info);
2600         return -1;
2601     }
2602 
2603     if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2604     {
2605         *_errno() = EINVAL;
2606         release_ioinfo(info);
2607         return -1;
2608     }
2609 
2610     /* If appending, go to EOF */
2611     if (info->wxflag & WX_APPEND)
2612         _lseek(fd, 0, FILE_END);
2613 
2614     if (!(info->wxflag & WX_TEXT))
2615     {
2616         if (WriteFile(hand, buf, count, &num_written, NULL)
2617                 &&  (num_written == count))
2618         {
2619             release_ioinfo(info);
2620             return num_written;
2621         }
2622         TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2623                 hand, GetLastError());
2624         *_errno() = ENOSPC;
2625     }
2626     else
2627     {
2628         unsigned int i, j, nr_lf, size;
2629         char *p = NULL;
2630         const char *q;
2631         const char *s = buf, *buf_start = buf;
2632 
2633         if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2634         {
2635             /* find number of \n */
2636             for (nr_lf=0, i=0; i<count; i++)
2637                 if (s[i] == '\n')
2638                     nr_lf++;
2639             if (nr_lf)
2640             {
2641                 size = count+nr_lf;
2642                 if ((q = p = malloc(size)))
2643                 {
2644                     for (s = buf, i = 0, j = 0; i < count; i++)
2645                     {
2646                         if (s[i] == '\n')
2647                             p[j++] = '\r';
2648                         p[j++] = s[i];
2649                     }
2650                 }
2651                 else
2652                 {
2653                     FIXME("Malloc failed\n");
2654                     nr_lf = 0;
2655                     size = count;
2656                     q = buf;
2657                 }
2658             }
2659             else
2660             {
2661                 size = count;
2662                 q = buf;
2663             }
2664         }
2665         else if (info->exflag & EF_UTF16)
2666         {
2667             for (nr_lf=0, i=0; i<count; i+=2)
2668                 if (s[i]=='\n' && s[i+1]==0)
2669                     nr_lf += 2;
2670             if (nr_lf)
2671             {
2672                 size = count+nr_lf;
2673                 if ((q = p = malloc(size)))
2674                 {
2675                     for (s=buf, i=0, j=0; i<count; i++)
2676                     {
2677                         if (s[i]=='\n' && s[i+1]==0)
2678                         {
2679                             p[j++] = '\r';
2680                             p[j++] = 0;
2681                         }
2682                         p[j++] = s[i++];
2683                         p[j++] = s[i];
2684                     }
2685                 }
2686                 else
2687                 {
2688                     FIXME("Malloc failed\n");
2689                     nr_lf = 0;
2690                     size = count;
2691                     q = buf;
2692                 }
2693             }
2694             else
2695             {
2696                 size = count;
2697                 q = buf;
2698             }
2699         }
2700         else
2701         {
2702             DWORD conv_len;
2703 
2704             for(nr_lf=0, i=0; i<count; i+=2)
2705                 if (s[i]=='\n' && s[i+1]==0)
2706                     nr_lf++;
2707 
2708             conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2709             if(!conv_len) {
2710                 _dosmaperr(GetLastError());
2711                 free(p);
2712                 release_ioinfo(info);
2713                 return -1;
2714             }
2715 
2716             size = conv_len+nr_lf;
2717             if((p = malloc(count+nr_lf*2+size)))
2718             {
2719                 for (s=buf, i=0, j=0; i<count; i++)
2720                 {
2721                     if (s[i]=='\n' && s[i+1]==0)
2722                     {
2723                         p[j++] = '\r';
2724                         p[j++] = 0;
2725                     }
2726                     p[j++] = s[i++];
2727                     p[j++] = s[i];
2728                 }
2729                 q = p+count+nr_lf*2;
2730                 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
2731                         p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
2732             }
2733             else
2734             {
2735                 FIXME("Malloc failed\n");
2736                 nr_lf = 0;
2737                 size = count;
2738                 q = buf;
2739             }
2740         }
2741 
2742         if (!WriteFile(hand, q, size, &num_written, NULL))
2743             num_written = -1;
2744         release_ioinfo(info);
2745         if(p)
2746             free(p);
2747         if (num_written != size)
2748         {
2749             TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2750                     fd, hand, GetLastError(), num_written);
2751             *_errno() = ENOSPC;
2752             return s - buf_start;
2753         }
2754         return count;
2755     }
2756 
2757     release_ioinfo(info);
2758     return -1;
2759 }
2760 
2761 /*********************************************************************
2762  *		_putw (MSVCRT.@)
2763  */
2764 int CDECL _putw(int val, FILE* file)
2765 {
2766   int len;
2767 
2768   _lock_file(file);
2769   len = _write(file->_file, &val, sizeof(val));
2770   if (len == sizeof(val)) {
2771     _unlock_file(file);
2772     return val;
2773   }
2774 
2775   file->_flag |= _IOERR;
2776   _unlock_file(file);
2777   return EOF;
2778 }
2779 
2780 /*********************************************************************
2781  *		fclose (MSVCRT.@)
2782  */
2783 int CDECL fclose(FILE* file)
2784 {
2785   int r, flag;
2786 
2787   _lock_file(file);
2788   flag = file->_flag;
2789   free(file->_tmpfname);
2790   file->_tmpfname = NULL;
2791   /* flush stdio buffers */
2792   if(file->_flag & _IOWRT)
2793       fflush(file);
2794   if(file->_flag & _IOMYBUF)
2795       free(file->_base);
2796 
2797   r=_close(file->_file);
2798 
2799   file->_flag = 0;
2800   _unlock_file(file);
2801   if(file<_iob || file>=_iob+_IOB_ENTRIES)
2802       DeleteCriticalSection(&((file_crit*)file)->crit);
2803 
2804   if(file == msvcrt_get_file(MSVCRT_stream_idx-1)) {
2805     while(MSVCRT_stream_idx>3 && !file->_flag) {
2806       MSVCRT_stream_idx--;
2807       file = msvcrt_get_file(MSVCRT_stream_idx-1);
2808     }
2809   }
2810 
2811   return ((r == -1) || (flag & _IOERR) ? EOF : 0);
2812 }
2813 
2814 /*********************************************************************
2815  *		feof (MSVCRT.@)
2816  */
2817 int CDECL feof(FILE* file)
2818 {
2819     return file->_flag & _IOEOF;
2820 }
2821 
2822 /*********************************************************************
2823  *		ferror (MSVCRT.@)
2824  */
2825 int CDECL ferror(FILE* file)
2826 {
2827     return file->_flag & _IOERR;
2828 }
2829 
2830 /*********************************************************************
2831  *		_filbuf (MSVCRT.@)
2832  */
2833 int CDECL _filbuf(FILE* file)
2834 {
2835     unsigned char c;
2836     _lock_file(file);
2837 
2838     if(file->_flag & _IOSTRG) {
2839         _unlock_file(file);
2840         return EOF;
2841     }
2842 
2843     /* Allocate buffer if needed */
2844     if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
2845         msvcrt_alloc_buffer(file);
2846 
2847     if(!(file->_flag & _IOREAD)) {
2848         if(file->_flag & _IORW)
2849             file->_flag |= _IOREAD;
2850         else {
2851             _unlock_file(file);
2852             return EOF;
2853         }
2854     }
2855 
2856     if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
2857         int r;
2858         if ((r = _read(file->_file,&c,1)) != 1) {
2859             file->_flag |= (r == 0) ? _IOEOF : _IOERR;
2860             _unlock_file(file);
2861             return EOF;
2862         }
2863 
2864         _unlock_file(file);
2865         return c;
2866     } else {
2867         file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
2868         if(file->_cnt<=0) {
2869             file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2870             file->_cnt = 0;
2871             _unlock_file(file);
2872             return EOF;
2873         }
2874 
2875         file->_cnt--;
2876         file->_ptr = file->_base+1;
2877         c = *(unsigned char *)file->_base;
2878         _unlock_file(file);
2879         return c;
2880     }
2881 }
2882 
2883 /*********************************************************************
2884  *		fgetc (MSVCRT.@)
2885  */
2886 int CDECL fgetc(FILE* file)
2887 {
2888   unsigned char *i;
2889   unsigned int j;
2890 
2891   _lock_file(file);
2892   if (file->_cnt>0) {
2893     file->_cnt--;
2894     i = (unsigned char *)file->_ptr++;
2895     j = *i;
2896   } else
2897     j = _filbuf(file);
2898 
2899   _unlock_file(file);
2900   return j;
2901 }
2902 
2903 /*********************************************************************
2904  *		_fgetchar (MSVCRT.@)
2905  */
2906 int CDECL _fgetchar(void)
2907 {
2908   return fgetc(stdin);
2909 }
2910 
2911 /*********************************************************************
2912  *		fgets (MSVCRT.@)
2913  */
2914 char * CDECL fgets(char *s, int size, FILE* file)
2915 {
2916   int    cc = EOF;
2917   char * buf_start = s;
2918 
2919   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2920 	file,file->_file,s,size);
2921 
2922   _lock_file(file);
2923 
2924   while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n')
2925     {
2926       *s++ = (char)cc;
2927       size --;
2928     }
2929   if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
2930   {
2931     TRACE(":nothing read\n");
2932     _unlock_file(file);
2933     return NULL;
2934   }
2935   if ((cc != EOF) && (size > 1))
2936     *s++ = cc;
2937   *s = '\0';
2938   TRACE(":got %s\n", debugstr_a(buf_start));
2939   _unlock_file(file);
2940   return buf_start;
2941 }
2942 
2943 /*********************************************************************
2944  *		fgetwc (MSVCRT.@)
2945  */
2946 wint_t CDECL fgetwc(FILE* file)
2947 {
2948     wint_t ret;
2949     int ch;
2950 
2951     _lock_file(file);
2952 
2953     if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
2954             || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
2955         char *p;
2956 
2957         for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
2958             ch = fgetc(file);
2959             if(ch == EOF) {
2960                 ret = WEOF;
2961                 break;
2962             }
2963             *p = (char)ch;
2964         }
2965     }else {
2966         char mbs[MB_LEN_MAX];
2967         int len = 0;
2968 
2969         ch = fgetc(file);
2970         if(ch != EOF) {
2971             mbs[0] = (char)ch;
2972             if(isleadbyte((unsigned char)mbs[0])) {
2973                 ch = fgetc(file);
2974                 if(ch != EOF) {
2975                     mbs[1] = (char)ch;
2976                     len = 2;
2977                 }
2978             }else {
2979                 len = 1;
2980             }
2981         }
2982 
2983         if(!len || mbtowc(&ret, mbs, len)==-1)
2984             ret = WEOF;
2985     }
2986 
2987     _unlock_file(file);
2988     return ret;
2989 }
2990 
2991 /*********************************************************************
2992  *		_getw (MSVCRT.@)
2993  */
2994 int CDECL _getw(FILE* file)
2995 {
2996   char *ch;
2997   int i, k;
2998   unsigned int j;
2999   ch = (char *)&i;
3000 
3001   _lock_file(file);
3002   for (j=0; j<sizeof(int); j++) {
3003     k = fgetc(file);
3004     if (k == EOF) {
3005       file->_flag |= _IOEOF;
3006       _unlock_file(file);
3007       return EOF;
3008     }
3009     ch[j] = k;
3010   }
3011 
3012   _unlock_file(file);
3013   return i;
3014 }
3015 
3016 /*********************************************************************
3017  *		getwc (MSVCRT.@)
3018  */
3019 wint_t CDECL getwc(FILE* file)
3020 {
3021   return fgetwc(file);
3022 }
3023 
3024 /*********************************************************************
3025  *		_fgetwchar (MSVCRT.@)
3026  */
3027 wint_t CDECL _fgetwchar(void)
3028 {
3029   return fgetwc(stdin);
3030 }
3031 
3032 /*********************************************************************
3033  *		getwchar (MSVCRT.@)
3034  */
3035 wint_t CDECL getwchar(void)
3036 {
3037   return _fgetwchar();
3038 }
3039 
3040 /*********************************************************************
3041  *              fgetws (MSVCRT.@)
3042  */
3043 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
3044 {
3045   int    cc = WEOF;
3046   wchar_t * buf_start = s;
3047 
3048   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3049         file,file->_file,s,size);
3050 
3051   _lock_file(file);
3052 
3053   while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n')
3054     {
3055       *s++ = (char)cc;
3056       size --;
3057     }
3058   if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3059   {
3060     TRACE(":nothing read\n");
3061     _unlock_file(file);
3062     return NULL;
3063   }
3064   if ((cc != WEOF) && (size > 1))
3065     *s++ = cc;
3066   *s = 0;
3067   TRACE(":got %s\n", debugstr_w(buf_start));
3068   _unlock_file(file);
3069   return buf_start;
3070 }
3071 
3072 /*********************************************************************
3073  *		fwrite (MSVCRT.@)
3074  */
3075 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
3076 {
3077     size_t wrcnt=size * nmemb;
3078     int written = 0;
3079     if (size == 0)
3080         return 0;
3081 
3082     _lock_file(file);
3083 
3084     while(wrcnt) {
3085 #ifndef __REACTOS__
3086         if(file->_cnt < 0) {
3087             WARN("negative file->_cnt value in %p\n", file);
3088             file->_flag |= MSVCRT__IOERR;
3089             break;
3090         } else
3091 #endif
3092         if(file->_cnt) {
3093             int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3094             memcpy(file->_ptr, ptr, pcnt);
3095             file->_cnt -= pcnt;
3096             file->_ptr += pcnt;
3097             written += pcnt;
3098             wrcnt -= pcnt;
3099             ptr = (const char*)ptr + pcnt;
3100         } else if((file->_flag & _IONBF)
3101                 || ((file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= file->_bufsiz)
3102                 || (!(file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
3103             size_t pcnt;
3104             int bufsiz;
3105 
3106             if(file->_flag & _IONBF)
3107                 bufsiz = 1;
3108             else if(!(file->_flag & (_IOMYBUF | _USERBUF)))
3109                 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
3110             else
3111                 bufsiz = file->_bufsiz;
3112 
3113             pcnt = (wrcnt / bufsiz) * bufsiz;
3114 
3115             if(msvcrt_flush_buffer(file) == EOF)
3116                 break;
3117 
3118             if(_write(file->_file, ptr, pcnt) <= 0) {
3119                 file->_flag |= _IOERR;
3120                 break;
3121             }
3122             written += pcnt;
3123             wrcnt -= pcnt;
3124             ptr = (const char*)ptr + pcnt;
3125         } else {
3126             if(_flsbuf(*(const char*)ptr, file) == EOF)
3127                 break;
3128             written++;
3129             wrcnt--;
3130             ptr = (const char*)ptr + 1;
3131         }
3132     }
3133 
3134     _unlock_file(file);
3135     return written / size;
3136 }
3137 
3138 /*********************************************************************
3139  *		fputwc (MSVCRT.@)
3140  * FORKED for ReactOS, don't sync with Wine!
3141  * References:
3142  *   - http://jira.reactos.org/browse/CORE-6495
3143  *   - http://bugs.winehq.org/show_bug.cgi?id=8598
3144  */
3145 wint_t CDECL fputwc(wchar_t c, FILE* stream)
3146 {
3147     /* If this is a real file stream (and not some temporary one for
3148        sprintf-like functions), check whether it is opened in text mode.
3149        In this case, we have to perform an implicit conversion to ANSI. */
3150     if (!(stream->_flag & _IOSTRG) && get_ioinfo_nolock(stream->_file)->wxflag & WX_TEXT)
3151     {
3152         /* Convert to multibyte in text mode */
3153         char mbc[MB_LEN_MAX];
3154         int mb_return;
3155 
3156         mb_return = wctomb(mbc, c);
3157 
3158         if(mb_return == -1)
3159             return WEOF;
3160 
3161         /* Output all characters */
3162         if (fwrite(mbc, mb_return, 1, stream) != 1)
3163             return WEOF;
3164     }
3165     else
3166     {
3167         if (fwrite(&c, sizeof(c), 1, stream) != 1)
3168             return WEOF;
3169     }
3170 
3171     return c;
3172 }
3173 
3174 /*********************************************************************
3175  *		_fputwchar (MSVCRT.@)
3176  */
3177 wint_t CDECL _fputwchar(wint_t wc)
3178 {
3179   return fputwc(wc, stdout);
3180 }
3181 
3182 /*********************************************************************
3183  *		_wfsopen (MSVCRT.@)
3184  */
3185 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
3186 {
3187   FILE* file;
3188   int open_flags, stream_flags, fd;
3189 
3190   TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3191 
3192   /* map mode string to open() flags. "man fopen" for possibilities. */
3193   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3194       return NULL;
3195 
3196   LOCK_FILES();
3197   fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
3198   if (fd < 0)
3199     file = NULL;
3200   else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3201    != -1)
3202     TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3203   else if (file)
3204   {
3205     file->_flag = 0;
3206     file = NULL;
3207   }
3208 
3209   TRACE(":got (%p)\n",file);
3210   if (fd >= 0 && !file)
3211     _close(fd);
3212   UNLOCK_FILES();
3213   return file;
3214 }
3215 
3216 /*********************************************************************
3217  *		_fsopen (MSVCRT.@)
3218  */
3219 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
3220 {
3221     FILE *ret;
3222     wchar_t *pathW = NULL, *modeW = NULL;
3223 
3224     if (path && !(pathW = msvcrt_wstrdupa(path))) {
3225         _invalid_parameter(NULL, NULL, NULL, 0, 0);
3226         *_errno() = EINVAL;
3227         return NULL;
3228     }
3229     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3230     {
3231         free(pathW);
3232         _invalid_parameter(NULL, NULL, NULL, 0, 0);
3233         *_errno() = EINVAL;
3234         return NULL;
3235     }
3236 
3237     ret = _wfsopen(pathW, modeW, share);
3238 
3239     free(pathW);
3240     free(modeW);
3241     return ret;
3242 }
3243 
3244 /*********************************************************************
3245  *		fopen (MSVCRT.@)
3246  */
3247 FILE * CDECL fopen(const char *path, const char *mode)
3248 {
3249     return _fsopen( path, mode, _SH_DENYNO );
3250 }
3251 
3252 /*********************************************************************
3253  *              fopen_s (MSVCRT.@)
3254  */
3255 int CDECL fopen_s(FILE** pFile,
3256         const char *filename, const char *mode)
3257 {
3258     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
3259     if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
3260     if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
3261 
3262     *pFile = fopen(filename, mode);
3263 
3264     if(!*pFile)
3265         return *_errno();
3266     return 0;
3267 }
3268 
3269 /*********************************************************************
3270  *		_wfopen (MSVCRT.@)
3271  */
3272 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
3273 {
3274     return _wfsopen( path, mode, _SH_DENYNO );
3275 }
3276 
3277 /*********************************************************************
3278  *		_wfopen_s (MSVCRT.@)
3279  */
3280 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
3281         const wchar_t *mode)
3282 {
3283     if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
3284         !MSVCRT_CHECK_PMT(mode != NULL)) {
3285         *_errno() = EINVAL;
3286         return EINVAL;
3287     }
3288 
3289     *pFile = _wfopen(filename, mode);
3290 
3291     if(!*pFile)
3292         return *_errno();
3293     return 0;
3294 }
3295 
3296 /* fputc calls _flsbuf which calls fputc */
3297 int CDECL _flsbuf(int c, FILE* file);
3298 
3299 /*********************************************************************
3300  *		fputc (MSVCRT.@)
3301  */
3302 int CDECL fputc(int c, FILE* file)
3303 {
3304   int res;
3305 
3306   _lock_file(file);
3307   if(file->_cnt>0) {
3308     *file->_ptr++=c;
3309     file->_cnt--;
3310     if (c == '\n')
3311     {
3312       res = msvcrt_flush_buffer(file);
3313       _unlock_file(file);
3314       return res ? res : c;
3315     }
3316     else {
3317       _unlock_file(file);
3318       return c & 0xff;
3319     }
3320   } else {
3321     res = _flsbuf(c, file);
3322     _unlock_file(file);
3323     return res;
3324   }
3325 }
3326 
3327 /*********************************************************************
3328  *		_fputchar (MSVCRT.@)
3329  */
3330 int CDECL _fputchar(int c)
3331 {
3332   return fputc(c, stdout);
3333 }
3334 
3335 /*********************************************************************
3336  *		fread (MSVCRT.@)
3337  */
3338 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
3339 {
3340   size_t rcnt=size * nmemb;
3341   size_t read=0;
3342   size_t pread=0;
3343 
3344   if(!rcnt)
3345 	return 0;
3346 
3347   _lock_file(file);
3348 
3349   /* first buffered data */
3350   if(file->_cnt>0) {
3351 	int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
3352 	memcpy(ptr, file->_ptr, pcnt);
3353 	file->_cnt -= pcnt;
3354 	file->_ptr += pcnt;
3355 	read += pcnt ;
3356 	rcnt -= pcnt ;
3357         ptr = (char*)ptr + pcnt;
3358   } else if(!(file->_flag & _IOREAD )) {
3359 	if(file->_flag & _IORW) {
3360 		file->_flag |= _IOREAD;
3361 	} else {
3362         _unlock_file(file);
3363         return 0;
3364     }
3365   }
3366 
3367   if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
3368       msvcrt_alloc_buffer(file);
3369 
3370   while(rcnt>0)
3371   {
3372     int i;
3373     if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) {
3374       file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
3375       file->_ptr = file->_base;
3376       i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
3377       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
3378       if (i > 0 && i < file->_cnt) {
3379         get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF;
3380         file->_flag &= ~_IOEOF;
3381       }
3382       if (i > 0) {
3383         memcpy(ptr, file->_ptr, i);
3384         file->_cnt -= i;
3385         file->_ptr += i;
3386       }
3387     } else if (rcnt > INT_MAX) {
3388       i = _read(file->_file, ptr, INT_MAX);
3389     } else if (rcnt < BUFSIZ) {
3390       i = _read(file->_file, ptr, rcnt);
3391     } else {
3392       i = _read(file->_file, ptr, rcnt - BUFSIZ/2);
3393     }
3394     pread += i;
3395     rcnt -= i;
3396     ptr = (char *)ptr+i;
3397     /* expose feof condition in the flags
3398      * MFC tests file->_flag for feof, and doesn't call feof())
3399      */
3400     if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF)
3401         file->_flag |= _IOEOF;
3402     else if (i == -1)
3403     {
3404         file->_flag |= _IOERR;
3405         pread = 0;
3406         rcnt = 0;
3407     }
3408     if (i < 1) break;
3409   }
3410   read+=pread;
3411   _unlock_file(file);
3412   return read / size;
3413 }
3414 
3415 /*********************************************************************
3416  *		_wfreopen (MSVCRT.@)
3417  *
3418  */
3419 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
3420 {
3421   int open_flags, stream_flags, fd;
3422 
3423   TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
3424 
3425   LOCK_FILES();
3426   if (!file || ((fd = file->_file) < 0))
3427     file = NULL;
3428   else
3429   {
3430     fclose(file);
3431     /* map mode string to open() flags. "man fopen" for possibilities. */
3432     if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3433       file = NULL;
3434     else
3435     {
3436       fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE);
3437       if (fd < 0)
3438         file = NULL;
3439       else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
3440       {
3441           file->_flag = 0;
3442           WARN(":failed-last error (%d)\n",GetLastError());
3443           _dosmaperr(GetLastError());
3444           file = NULL;
3445       }
3446     }
3447   }
3448   UNLOCK_FILES();
3449   return file;
3450 }
3451 
3452 /*********************************************************************
3453  *      freopen (MSVCRT.@)
3454  *
3455  */
3456 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
3457 {
3458     FILE *ret;
3459     wchar_t *pathW = NULL, *modeW = NULL;
3460 
3461     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3462     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3463     {
3464         free(pathW);
3465         return NULL;
3466     }
3467 
3468     ret = _wfreopen(pathW, modeW, file);
3469 
3470     free(pathW);
3471     free(modeW);
3472     return ret;
3473 }
3474 
3475 /*********************************************************************
3476  *		fsetpos (MSVCRT.@)
3477  */
3478 int CDECL fsetpos(FILE* file, const fpos_t *pos)
3479 {
3480   int ret;
3481 
3482   _lock_file(file);
3483   /* Note that all this has been lifted 'as is' from fseek */
3484   if(file->_flag & _IOWRT)
3485 	msvcrt_flush_buffer(file);
3486 
3487   /* Discard buffered input */
3488   file->_cnt = 0;
3489   file->_ptr = file->_base;
3490 
3491   /* Reset direction of i/o */
3492   if(file->_flag & _IORW) {
3493         file->_flag &= ~(_IOREAD|_IOWRT);
3494   }
3495 
3496   ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3497   _unlock_file(file);
3498   return ret;
3499 }
3500 
3501 /*********************************************************************
3502  *		_ftelli64 (MSVCRT.@)
3503  */
3504 __int64 CDECL _ftelli64(FILE* file)
3505 {
3506     __int64 pos;
3507 
3508     _lock_file(file);
3509     pos = _telli64(file->_file);
3510     if(pos == -1) {
3511         _unlock_file(file);
3512         return -1;
3513     }
3514     if(file->_flag & (_IOMYBUF | _USERBUF))  {
3515         if(file->_flag & _IOWRT) {
3516             pos += file->_ptr - file->_base;
3517 
3518             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3519                 char *p;
3520 
3521                 for(p=file->_base; p<file->_ptr; p++)
3522                     if(*p == '\n')
3523                         pos++;
3524             }
3525         } else if(!file->_cnt) { /* nothing to do */
3526         } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
3527             int i;
3528 
3529             pos -= file->_cnt;
3530             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3531                 for(i=0; i<file->_cnt; i++)
3532                     if(file->_ptr[i] == '\n')
3533                         pos--;
3534             }
3535         } else {
3536             char *p;
3537 
3538             if(_lseeki64(file->_file, pos, SEEK_SET) != pos) {
3539                 _unlock_file(file);
3540                 return -1;
3541             }
3542 
3543             pos -= file->_bufsiz;
3544             pos += file->_ptr - file->_base;
3545 
3546             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3547                 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL)
3548                     pos--;
3549 
3550                 for(p=file->_base; p<file->_ptr; p++)
3551                     if(*p == '\n')
3552                         pos++;
3553             }
3554         }
3555     }
3556 
3557     _unlock_file(file);
3558     return pos;
3559 }
3560 
3561 /*********************************************************************
3562  *		ftell (MSVCRT.@)
3563  */
3564 LONG CDECL ftell(FILE* file)
3565 {
3566   return (LONG)_ftelli64(file);
3567 }
3568 
3569 /*********************************************************************
3570  *		fgetpos (MSVCRT.@)
3571  */
3572 int CDECL fgetpos(FILE* file, fpos_t *pos)
3573 {
3574     *pos = _ftelli64(file);
3575     if(*pos == -1)
3576         return -1;
3577     return 0;
3578 }
3579 
3580 /*********************************************************************
3581  *		fputs (MSVCRT.@)
3582  */
3583 int CDECL fputs(const char *s, FILE* file)
3584 {
3585     size_t len = strlen(s);
3586     int ret;
3587 
3588     _lock_file(file);
3589     ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF;
3590     _unlock_file(file);
3591     return ret;
3592 }
3593 
3594 /*********************************************************************
3595  *		fputws (MSVCRT.@)
3596  */
3597 int CDECL fputws(const wchar_t *s, FILE* file)
3598 {
3599     size_t i, len = strlenW(s);
3600     BOOL tmp_buf;
3601     int ret;
3602 
3603     _lock_file(file);
3604     if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3605         ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
3606         _unlock_file(file);
3607         return ret;
3608     }
3609 
3610     tmp_buf = add_std_buffer(file);
3611     for (i=0; i<len; i++) {
3612         if(fputwc(s[i], file) == WEOF) {
3613             if(tmp_buf) remove_std_buffer(file);
3614             _unlock_file(file);
3615             return WEOF;
3616         }
3617     }
3618 
3619     if(tmp_buf) remove_std_buffer(file);
3620     _unlock_file(file);
3621     return 0;
3622 }
3623 
3624 /*********************************************************************
3625  *		getchar (MSVCRT.@)
3626  */
3627 int CDECL getchar(void)
3628 {
3629   return fgetc(stdin);
3630 }
3631 
3632 /*********************************************************************
3633  *		getc (MSVCRT.@)
3634  */
3635 int CDECL getc(FILE* file)
3636 {
3637   return fgetc(file);
3638 }
3639 
3640 /*********************************************************************
3641  *		gets (MSVCRT.@)
3642  */
3643 char * CDECL gets(char *buf)
3644 {
3645   int    cc;
3646   char * buf_start = buf;
3647 
3648   _lock_file(stdin);
3649   for(cc = fgetc(stdin); cc != EOF && cc != '\n';
3650       cc = fgetc(stdin))
3651   if(cc != '\r') *buf++ = (char)cc;
3652 
3653   *buf = '\0';
3654 
3655   TRACE("got '%s'\n", buf_start);
3656   _unlock_file(stdin);
3657   return buf_start;
3658 }
3659 
3660 /*********************************************************************
3661  *		_getws (MSVCRT.@)
3662  */
3663 wchar_t* CDECL _getws(wchar_t* buf)
3664 {
3665     wint_t cc;
3666     wchar_t* ws = buf;
3667 
3668     _lock_file(stdin);
3669     for (cc = fgetwc(stdin); cc != WEOF && cc != '\n';
3670          cc = fgetwc(stdin))
3671     {
3672         if (cc != '\r')
3673             *buf++ = (wchar_t)cc;
3674     }
3675     *buf = '\0';
3676 
3677     TRACE("got %s\n", debugstr_w(ws));
3678     _unlock_file(stdin);
3679     return ws;
3680 }
3681 
3682 /*********************************************************************
3683  *		putc (MSVCRT.@)
3684  */
3685 int CDECL putc(int c, FILE* file)
3686 {
3687   return fputc(c, file);
3688 }
3689 
3690 /*********************************************************************
3691  *		putchar (MSVCRT.@)
3692  */
3693 int CDECL putchar(int c)
3694 {
3695   return fputc(c, stdout);
3696 }
3697 
3698 /*********************************************************************
3699  *		_putwch (MSVCRT.@)
3700  */
3701 wint_t CDECL _putwch(wchar_t c)
3702 {
3703   return fputwc(c, stdout);
3704 }
3705 
3706 /*********************************************************************
3707  *		puts (MSVCRT.@)
3708  */
3709 int CDECL puts(const char *s)
3710 {
3711     size_t len = strlen(s);
3712     int ret;
3713 
3714     _lock_file(stdout);
3715     if(fwrite(s, sizeof(*s), len, stdout) != len) {
3716         _unlock_file(stdout);
3717         return EOF;
3718     }
3719 
3720     ret = fwrite("\n",1,1,stdout) == 1 ? 0 : EOF;
3721     _unlock_file(stdout);
3722     return ret;
3723 }
3724 
3725 /*********************************************************************
3726  *		_putws (MSVCRT.@)
3727  */
3728 int CDECL _putws(const wchar_t *s)
3729 {
3730     static const wchar_t nl = '\n';
3731     size_t len = strlenW(s);
3732     int ret;
3733 
3734     _lock_file(stdout);
3735     if(fwrite(s, sizeof(*s), len, stdout) != len) {
3736         _unlock_file(stdout);
3737         return EOF;
3738     }
3739 
3740     ret = fwrite(&nl,sizeof(nl),1,stdout) == 1 ? 0 : EOF;
3741     _unlock_file(stdout);
3742     return ret;
3743 }
3744 
3745 /*********************************************************************
3746  *		remove (MSVCRT.@)
3747  */
3748 int CDECL remove(const char *path)
3749 {
3750   TRACE("(%s)\n",path);
3751   if (DeleteFileA(path))
3752     return 0;
3753   TRACE(":failed (%d)\n",GetLastError());
3754   _dosmaperr(GetLastError());
3755   return -1;
3756 }
3757 
3758 /*********************************************************************
3759  *		_wremove (MSVCRT.@)
3760  */
3761 int CDECL _wremove(const wchar_t *path)
3762 {
3763   TRACE("(%s)\n",debugstr_w(path));
3764   if (DeleteFileW(path))
3765     return 0;
3766   TRACE(":failed (%d)\n",GetLastError());
3767   _dosmaperr(GetLastError());
3768   return -1;
3769 }
3770 
3771 /*********************************************************************
3772  *		rename (MSVCRT.@)
3773  */
3774 int CDECL rename(const char *oldpath,const char *newpath)
3775 {
3776   TRACE(":from %s to %s\n",oldpath,newpath);
3777   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3778     return 0;
3779   TRACE(":failed (%d)\n",GetLastError());
3780   _dosmaperr(GetLastError());
3781   return -1;
3782 }
3783 
3784 /*********************************************************************
3785  *		_wrename (MSVCRT.@)
3786  */
3787 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
3788 {
3789   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
3790   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3791     return 0;
3792   TRACE(":failed (%d)\n",GetLastError());
3793   _dosmaperr(GetLastError());
3794   return -1;
3795 }
3796 
3797 /*********************************************************************
3798  *		setvbuf (MSVCRT.@)
3799  */
3800 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
3801 {
3802     if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
3803     if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1;
3804     if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1;
3805 
3806     _lock_file(file);
3807 
3808     fflush(file);
3809     if(file->_flag & _IOMYBUF)
3810         free(file->_base);
3811     file->_flag &= ~(_IONBF | _IOMYBUF | _USERBUF);
3812     file->_cnt = 0;
3813 
3814     if(mode == _IONBF) {
3815         file->_flag |= _IONBF;
3816         file->_base = file->_ptr = (char*)&file->_charbuf;
3817         file->_bufsiz = 2;
3818     }else if(buf) {
3819         file->_base = file->_ptr = buf;
3820         file->_flag |= _USERBUF;
3821         file->_bufsiz = size;
3822     }else {
3823         file->_base = file->_ptr = malloc(size);
3824         if(!file->_base) {
3825             file->_bufsiz = 0;
3826             _unlock_file(file);
3827             return -1;
3828         }
3829 
3830         file->_flag |= _IOMYBUF;
3831         file->_bufsiz = size;
3832     }
3833     _unlock_file(file);
3834     return 0;
3835 }
3836 
3837 /*********************************************************************
3838  *		setbuf (MSVCRT.@)
3839  */
3840 void CDECL setbuf(FILE* file, char *buf)
3841 {
3842   setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3843 }
3844 
3845 /*********************************************************************
3846  *		tmpnam (MSVCRT.@)
3847  */
3848 char * CDECL tmpnam(char *s)
3849 {
3850   char tmpstr[16];
3851   char *p;
3852   int count, size;
3853 
3854   if (!s) {
3855     thread_data_t *data = msvcrt_get_thread_data();
3856 
3857     if(!data->tmpnam_buffer)
3858       data->tmpnam_buffer = malloc(MAX_PATH);
3859 
3860     s = data->tmpnam_buffer;
3861   }
3862 
3863   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
3864   p = s + sprintf(s, "\\s%s.", tmpstr);
3865   for (count = 0; count < TMP_MAX; count++)
3866   {
3867     size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr);
3868     memcpy(p, tmpstr, size);
3869     p[size] = '\0';
3870     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
3871         GetLastError() == ERROR_FILE_NOT_FOUND)
3872       break;
3873   }
3874   return s;
3875 }
3876 
3877 /*********************************************************************
3878  *              _wtmpnam (MSVCRT.@)
3879  */
3880 wchar_t * CDECL _wtmpnam(wchar_t *s)
3881 {
3882     static const wchar_t format[] = {'\\','s','%','s','.',0};
3883     wchar_t tmpstr[16];
3884     wchar_t *p;
3885     int count, size;
3886     if (!s) {
3887         thread_data_t *data = msvcrt_get_thread_data();
3888 
3889         if(!data->wtmpnam_buffer)
3890             data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
3891 
3892         s = data->wtmpnam_buffer;
3893     }
3894 
3895     msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
3896     p = s + _snwprintf(s, MAX_PATH, format, tmpstr);
3897     for (count = 0; count < TMP_MAX; count++)
3898     {
3899         size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr);
3900         memcpy(p, tmpstr, size*sizeof(wchar_t));
3901         p[size] = '\0';
3902         if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
3903                 GetLastError() == ERROR_FILE_NOT_FOUND)
3904             break;
3905     }
3906     return s;
3907 }
3908 
3909 /*********************************************************************
3910  *		tmpfile (MSVCRT.@)
3911  */
3912 FILE* CDECL tmpfile(void)
3913 {
3914   char *filename = tmpnam(NULL);
3915   int fd;
3916   FILE* file = NULL;
3917 
3918   LOCK_FILES();
3919   fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
3920           _S_IREAD | _S_IWRITE);
3921   if (fd != -1 && (file = msvcrt_alloc_fp()))
3922   {
3923     if (msvcrt_init_fp(file, fd, _IORW) == -1)
3924     {
3925         file->_flag = 0;
3926         file = NULL;
3927     }
3928     else file->_tmpfname = _strdup(filename);
3929   }
3930 
3931   if(fd != -1 && !file)
3932       _close(fd);
3933   UNLOCK_FILES();
3934   return file;
3935 }
3936 
3937 /*********************************************************************
3938  *		ungetc (MSVCRT.@)
3939  */
3940 int CDECL ungetc(int c, FILE * file)
3941 {
3942     if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3943 
3944     if (c == EOF || !(file->_flag&_IOREAD ||
3945                 (file->_flag&_IORW && !(file->_flag&_IOWRT))))
3946         return EOF;
3947 
3948     _lock_file(file);
3949     if((!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
3950                 && msvcrt_alloc_buffer(file))
3951             || (!file->_cnt && file->_ptr==file->_base))
3952         file->_ptr++;
3953 
3954     if(file->_ptr>file->_base) {
3955         file->_ptr--;
3956         if(file->_flag & _IOSTRG) {
3957             if(*file->_ptr != c) {
3958                 file->_ptr++;
3959                 _unlock_file(file);
3960                 return EOF;
3961             }
3962         }else {
3963             *file->_ptr = c;
3964         }
3965         file->_cnt++;
3966         clearerr(file);
3967         file->_flag |= _IOREAD;
3968         _unlock_file(file);
3969         return c;
3970     }
3971 
3972     _unlock_file(file);
3973     return EOF;
3974 }
3975 
3976 /*********************************************************************
3977  *              ungetwc (MSVCRT.@)
3978  */
3979 wint_t CDECL ungetwc(wint_t wc, FILE * file)
3980 {
3981     wchar_t mwc = wc;
3982 
3983     if (wc == WEOF)
3984         return WEOF;
3985 
3986     _lock_file(file);
3987 
3988     if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
3989             || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3990         unsigned char * pp = (unsigned char *)&mwc;
3991         int i;
3992 
3993         for(i=sizeof(wchar_t)-1;i>=0;i--) {
3994             if(pp[i] != ungetc(pp[i],file)) {
3995                 _unlock_file(file);
3996                 return WEOF;
3997             }
3998         }
3999     }else {
4000         char mbs[MB_LEN_MAX];
4001         int len;
4002 
4003         len = wctomb(mbs, mwc);
4004         if(len == -1) {
4005             _unlock_file(file);
4006             return WEOF;
4007         }
4008 
4009         for(len--; len>=0; len--) {
4010             if(mbs[len] != ungetc(mbs[len], file)) {
4011                 _unlock_file(file);
4012                 return WEOF;
4013             }
4014         }
4015     }
4016 
4017     _unlock_file(file);
4018     return mwc;
4019 }
4020 
4021 
4022 
4023 /*********************************************************************
4024  *		_getmaxstdio (MSVCRT.@)
4025  */
4026 int CDECL _getmaxstdio(void)
4027 {
4028     return MSVCRT_max_streams;
4029 }
4030 
4031 /*********************************************************************
4032  *		_setmaxstdio (MSVCRT.@)
4033  */
4034 int CDECL _setmaxstdio(int newmax)
4035 {
4036     TRACE("%d\n", newmax);
4037 
4038     if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
4039         return -1;
4040 
4041     MSVCRT_max_streams = newmax;
4042     return MSVCRT_max_streams;
4043 }
4044