mshtml: Use lazy allocation for connection points.
[wine] / dlls / msvcrt / file.c
1 /*
2  * msvcrt.dll file functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  * Copyright 2004 Eric Pouech
9  * Copyright 2004 Juan Lang
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  *
25  * TODO
26  * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <sys/types.h>
38 #include <limits.h>
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winternl.h"
43 #include "msvcrt.h"
44 #include "mtdll.h"
45
46 #include "wine/unicode.h"
47
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
51
52 /* for stat mode, permissions apply to all,owner and group */
53 #define ALL_S_IREAD  (MSVCRT__S_IREAD  | (MSVCRT__S_IREAD  >> 3) | (MSVCRT__S_IREAD  >> 6))
54 #define ALL_S_IWRITE (MSVCRT__S_IWRITE | (MSVCRT__S_IWRITE >> 3) | (MSVCRT__S_IWRITE >> 6))
55 #define ALL_S_IEXEC  (MSVCRT__S_IEXEC  | (MSVCRT__S_IEXEC  >> 3) | (MSVCRT__S_IEXEC  >> 6))
56
57 /* _access() bit flags FIXME: incomplete */
58 #define MSVCRT_W_OK      0x02
59 #define MSVCRT_R_OK      0x04
60
61 /* values for wxflag in file descriptor */
62 #define WX_OPEN           0x01
63 #define WX_ATEOF          0x02
64 #define WX_READNL         0x04  /* read started with \n */
65 #define WX_PIPE           0x08
66 #define WX_DONTINHERIT    0x10
67 #define WX_APPEND         0x20
68 #define WX_TEXT           0x80
69
70 /* values for exflag - it's used differently in msvcr90.dll*/
71 #define EF_UTF8           0x01
72 #define EF_UTF16          0x02
73 #define EF_CRIT_INIT      0x04
74 #define EF_UNK_UNICODE    0x08
75
76 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
77 static char utf16_bom[2] = { 0xff, 0xfe };
78
79 /* FIXME: this should be allocated dynamically */
80 #define MSVCRT_MAX_FILES 2048
81 #define MSVCRT_FD_BLOCK_SIZE 32
82
83 /* ioinfo structure size is different in msvcrXX.dll's */
84 typedef struct {
85     HANDLE              handle;
86     unsigned char       wxflag;
87     char                lookahead[3];
88     int                 exflag;
89     CRITICAL_SECTION    crit;
90 } ioinfo;
91
92 /*********************************************************************
93  *              __pioinfo (MSVCRT.@)
94  * array of pointers to ioinfo arrays [32]
95  */
96 ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
97
98 /*********************************************************************
99  *              __badioinfo (MSVCRT.@)
100  */
101 ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
102
103 static int MSVCRT_fdstart = 3; /* first unallocated fd */
104 static int MSVCRT_fdend = 3; /* highest allocated fd */
105
106 typedef struct {
107     MSVCRT_FILE file;
108     CRITICAL_SECTION crit;
109 } file_crit;
110
111 MSVCRT_FILE MSVCRT__iob[_IOB_ENTRIES] = { { 0 } };
112 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE];
113 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
114
115 /* INTERNAL: process umask */
116 static int MSVCRT_umask = 0;
117
118 /* INTERNAL: static data for tmpnam and _wtmpname functions */
119 static int tmpnam_unique;
120
121 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
122 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
123 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
124 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
125
126 #define TOUL(x) (ULONGLONG)(x)
127 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
128 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
129 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
130 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
131
132 /* This critical section protects the tables MSVCRT___pioinfo and MSVCRT_fstreams,
133  * and their related indexes, MSVCRT_fdstart, MSVCRT_fdend,
134  * and MSVCRT_stream_idx, from race conditions.
135  * It doesn't protect against race conditions manipulating the underlying files
136  * or flags; doing so would probably be better accomplished with per-file
137  * protection, rather than locking the whole table for every change.
138  */
139 static CRITICAL_SECTION MSVCRT_file_cs;
140 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
141 {
142     0, 0, &MSVCRT_file_cs,
143     { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
144       0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
145 };
146 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
147 #define LOCK_FILES()    do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
148 #define UNLOCK_FILES()  do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
149
150 static void msvcrt_stat64_to_stat(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stat *buf)
151 {
152     buf->st_dev   = buf64->st_dev;
153     buf->st_ino   = buf64->st_ino;
154     buf->st_mode  = buf64->st_mode;
155     buf->st_nlink = buf64->st_nlink;
156     buf->st_uid   = buf64->st_uid;
157     buf->st_gid   = buf64->st_gid;
158     buf->st_rdev  = buf64->st_rdev;
159     buf->st_size  = buf64->st_size;
160     buf->st_atime = buf64->st_atime;
161     buf->st_mtime = buf64->st_mtime;
162     buf->st_ctime = buf64->st_ctime;
163 }
164
165 static void msvcrt_stat64_to_stati64(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stati64 *buf)
166 {
167     buf->st_dev   = buf64->st_dev;
168     buf->st_ino   = buf64->st_ino;
169     buf->st_mode  = buf64->st_mode;
170     buf->st_nlink = buf64->st_nlink;
171     buf->st_uid   = buf64->st_uid;
172     buf->st_gid   = buf64->st_gid;
173     buf->st_rdev  = buf64->st_rdev;
174     buf->st_size  = buf64->st_size;
175     buf->st_atime = buf64->st_atime;
176     buf->st_mtime = buf64->st_mtime;
177     buf->st_ctime = buf64->st_ctime;
178 }
179
180 static void time_to_filetime( MSVCRT___time64_t time, FILETIME *ft )
181 {
182     /* 1601 to 1970 is 369 years plus 89 leap days */
183     static const __int64 secs_1601_to_1970 = ((369 * 365 + 89) * (__int64)86400);
184
185     __int64 ticks = (time + secs_1601_to_1970) * 10000000;
186     ft->dwHighDateTime = ticks >> 32;
187     ft->dwLowDateTime = ticks;
188 }
189
190 static inline ioinfo* msvcrt_get_ioinfo(int fd)
191 {
192     ioinfo *ret = NULL;
193     if(fd < MSVCRT_MAX_FILES)
194         ret = MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
195     if(!ret)
196         return &MSVCRT___badioinfo;
197
198     return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
199 }
200
201 static inline MSVCRT_FILE* msvcrt_get_file(int i)
202 {
203     file_crit *ret;
204
205     if(i >= MSVCRT_max_streams)
206         return NULL;
207
208     if(i < _IOB_ENTRIES)
209         return &MSVCRT__iob[i];
210
211     ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
212     if(!ret) {
213         MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = MSVCRT_calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
214         if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
215             ERR("out of memory\n");
216             *MSVCRT__errno() = MSVCRT_ENOMEM;
217             return NULL;
218         }
219
220         ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
221     } else
222         ret += i%MSVCRT_FD_BLOCK_SIZE;
223
224     return &ret->file;
225 }
226
227 static inline BOOL msvcrt_is_valid_fd(int fd)
228 {
229     return fd >= 0 && fd < MSVCRT_fdend && (msvcrt_get_ioinfo(fd)->wxflag & WX_OPEN);
230 }
231
232 /* INTERNAL: Get the HANDLE for a fd
233  * This doesn't lock the table, because a failure will result in
234  * INVALID_HANDLE_VALUE being returned, which should be handled correctly.  If
235  * it returns a valid handle which is about to be closed, a subsequent call
236  * will fail, most likely in a sane way.
237  */
238 static HANDLE msvcrt_fdtoh(int fd)
239 {
240   if (!msvcrt_is_valid_fd(fd))
241   {
242     WARN(":fd (%d) - no handle!\n",fd);
243     *MSVCRT___doserrno() = 0;
244     *MSVCRT__errno() = MSVCRT_EBADF;
245     return INVALID_HANDLE_VALUE;
246   }
247   if (msvcrt_get_ioinfo(fd)->handle == INVALID_HANDLE_VALUE)
248       WARN("returning INVALID_HANDLE_VALUE for %d\n", fd);
249   return msvcrt_get_ioinfo(fd)->handle;
250 }
251
252 /* INTERNAL: free a file entry fd */
253 static void msvcrt_free_fd(int fd)
254 {
255   ioinfo *fdinfo;
256
257   LOCK_FILES();
258   fdinfo = msvcrt_get_ioinfo(fd);
259   if(fdinfo != &MSVCRT___badioinfo)
260   {
261     fdinfo->handle = INVALID_HANDLE_VALUE;
262     fdinfo->wxflag = 0;
263   }
264   TRACE(":fd (%d) freed\n",fd);
265
266   if (fd < 3)
267   {
268     switch (fd)
269     {
270     case 0:
271         SetStdHandle(STD_INPUT_HANDLE, 0);
272         break;
273     case 1:
274         SetStdHandle(STD_OUTPUT_HANDLE, 0);
275         break;
276     case 2:
277         SetStdHandle(STD_ERROR_HANDLE, 0);
278         break;
279     }
280   }
281
282   if (fd == MSVCRT_fdend - 1)
283     MSVCRT_fdend--;
284   if (fd < MSVCRT_fdstart)
285     MSVCRT_fdstart = fd;
286   UNLOCK_FILES();
287 }
288
289 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE, starting from fd */
290 /* caller must hold the files lock */
291 static int msvcrt_set_fd(HANDLE hand, int flag, int fd)
292 {
293   ioinfo *fdinfo;
294
295   if (fd >= MSVCRT_MAX_FILES)
296   {
297     WARN(":files exhausted!\n");
298     *MSVCRT__errno() = MSVCRT_ENFILE;
299     return -1;
300   }
301
302   fdinfo = msvcrt_get_ioinfo(fd);
303   if(fdinfo == &MSVCRT___badioinfo) {
304     int i;
305
306     MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE] = MSVCRT_calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
307     if(!MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE]) {
308       WARN(":out of memory!\n");
309       *MSVCRT__errno() = MSVCRT_ENOMEM;
310       return -1;
311     }
312
313     for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
314       MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][i].handle = INVALID_HANDLE_VALUE;
315
316     fdinfo = msvcrt_get_ioinfo(fd);
317   }
318
319   fdinfo->handle = hand;
320   fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE));
321   fdinfo->lookahead[0] = '\n';
322   fdinfo->lookahead[1] = '\n';
323   fdinfo->lookahead[2] = '\n';
324   fdinfo->exflag = 0;
325
326   /* locate next free slot */
327   if (fd == MSVCRT_fdstart && fd == MSVCRT_fdend)
328     MSVCRT_fdstart = MSVCRT_fdend + 1;
329   else
330     while (MSVCRT_fdstart < MSVCRT_fdend &&
331       msvcrt_get_ioinfo(MSVCRT_fdstart)->handle != INVALID_HANDLE_VALUE)
332       MSVCRT_fdstart++;
333   /* update last fd in use */
334   if (fd >= MSVCRT_fdend)
335     MSVCRT_fdend = fd + 1;
336   TRACE("fdstart is %d, fdend is %d\n", MSVCRT_fdstart, MSVCRT_fdend);
337
338   switch (fd)
339   {
340   case 0: SetStdHandle(STD_INPUT_HANDLE,  hand); break;
341   case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
342   case 2: SetStdHandle(STD_ERROR_HANDLE,  hand); break;
343   }
344
345   return fd;
346 }
347
348 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
349 static int msvcrt_alloc_fd(HANDLE hand, int flag)
350 {
351   int ret;
352
353   LOCK_FILES();
354   TRACE(":handle (%p) allocating fd (%d)\n",hand,MSVCRT_fdstart);
355   ret = msvcrt_set_fd(hand, flag, MSVCRT_fdstart);
356   UNLOCK_FILES();
357   return ret;
358 }
359
360 /* INTERNAL: Allocate a FILE* for an fd slot */
361 /* caller must hold the files lock */
362 static MSVCRT_FILE* msvcrt_alloc_fp(void)
363 {
364   int i;
365   MSVCRT_FILE *file;
366
367   for (i = 3; i < MSVCRT_max_streams; i++)
368   {
369     file = msvcrt_get_file(i);
370     if (!file)
371       return NULL;
372
373     if (file->_flag == 0)
374     {
375       if (i == MSVCRT_stream_idx)
376       {
377           if (file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
378           {
379               InitializeCriticalSection(&((file_crit*)file)->crit);
380               ((file_crit*)file)->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_crit.crit");
381           }
382           MSVCRT_stream_idx++;
383       }
384       return file;
385     }
386   }
387
388   return NULL;
389 }
390
391 /* INTERNAL: initialize a FILE* from an open fd */
392 static int msvcrt_init_fp(MSVCRT_FILE* file, int fd, unsigned stream_flags)
393 {
394   TRACE(":fd (%d) allocating FILE*\n",fd);
395   if (!msvcrt_is_valid_fd(fd))
396   {
397     WARN(":invalid fd %d\n",fd);
398     *MSVCRT___doserrno() = 0;
399     *MSVCRT__errno() = MSVCRT_EBADF;
400     return -1;
401   }
402   memset(file, 0, sizeof(*file));
403   file->_file = fd;
404   file->_flag = stream_flags;
405
406   TRACE(":got FILE* (%p)\n",file);
407   return 0;
408 }
409
410 /* INTERNAL: Create an inheritance data block (for spawned process)
411  * The inheritance block is made of:
412  *      00      int     nb of file descriptor (NBFD)
413  *      04      char    file flags (wxflag): repeated for each fd
414  *      4+NBFD  HANDLE  file handle: repeated for each fd
415  */
416 unsigned msvcrt_create_io_inherit_block(WORD *size, BYTE **block)
417 {
418   int         fd;
419   char*       wxflag_ptr;
420   HANDLE*     handle_ptr;
421   ioinfo*     fdinfo;
422
423   *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * MSVCRT_fdend;
424   *block = MSVCRT_calloc(*size, 1);
425   if (!*block)
426   {
427     *size = 0;
428     return FALSE;
429   }
430   wxflag_ptr = (char*)*block + sizeof(unsigned);
431   handle_ptr = (HANDLE*)(wxflag_ptr + MSVCRT_fdend * sizeof(char));
432
433   *(unsigned*)*block = MSVCRT_fdend;
434   for (fd = 0; fd < MSVCRT_fdend; fd++)
435   {
436     /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
437     fdinfo = msvcrt_get_ioinfo(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   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) && *handle_ptr != INVALID_HANDLE_VALUE)
478         msvcrt_set_fd(*handle_ptr, *wxflag_ptr, i);
479
480       wxflag_ptr++; handle_ptr++;
481     }
482     MSVCRT_fdend = max( 3, count );
483     for (MSVCRT_fdstart = 3; MSVCRT_fdstart < MSVCRT_fdend; MSVCRT_fdstart++)
484         if (msvcrt_get_ioinfo(MSVCRT_fdstart)->handle == INVALID_HANDLE_VALUE) break;
485   }
486
487   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDIN_FILENO);
488   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
489     msvcrt_set_fd(GetStdHandle(STD_INPUT_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDIN_FILENO);
490
491   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDOUT_FILENO);
492   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
493     msvcrt_set_fd(GetStdHandle(STD_OUTPUT_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDOUT_FILENO);
494
495   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDERR_FILENO);
496   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
497     msvcrt_set_fd(GetStdHandle(STD_ERROR_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDERR_FILENO);
498
499   TRACE(":handles (%p)(%p)(%p)\n", msvcrt_get_ioinfo(MSVCRT_STDIN_FILENO)->handle,
500         msvcrt_get_ioinfo(MSVCRT_STDOUT_FILENO)->handle,
501         msvcrt_get_ioinfo(MSVCRT_STDERR_FILENO)->handle);
502
503   memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
504   for (i = 0; i < 3; i++)
505   {
506     /* FILE structs for stdin/out/err are static and never deleted */
507     MSVCRT__iob[i]._file = i;
508     MSVCRT__iob[i]._tmpfname = NULL;
509     MSVCRT__iob[i]._flag = (i == 0) ? MSVCRT__IOREAD : MSVCRT__IOWRT;
510   }
511   MSVCRT_stream_idx = 3;
512 }
513
514 /* INTERNAL: Flush stdio file buffer */
515 static int msvcrt_flush_buffer(MSVCRT_FILE* file)
516 {
517   if(file->_bufsiz) {
518         int cnt=file->_ptr-file->_base;
519         if(cnt>0 && MSVCRT__write(file->_file, file->_base, cnt) != cnt) {
520             file->_flag |= MSVCRT__IOERR;
521             return MSVCRT_EOF;
522         }
523         file->_ptr=file->_base;
524         file->_cnt=file->_bufsiz;
525   }
526   return 0;
527 }
528
529 /*********************************************************************
530  *              _isatty (MSVCRT.@)
531  */
532 int CDECL MSVCRT__isatty(int fd)
533 {
534     HANDLE hand = msvcrt_fdtoh(fd);
535
536     TRACE(":fd (%d) handle (%p)\n",fd,hand);
537     if (hand == INVALID_HANDLE_VALUE)
538         return 0;
539
540     return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
541 }
542
543 /* INTERNAL: Allocate stdio file buffer */
544 static BOOL msvcrt_alloc_buffer(MSVCRT_FILE* file)
545 {
546     if((file->_file==MSVCRT_STDOUT_FILENO || file->_file==MSVCRT_STDERR_FILENO)
547             && MSVCRT__isatty(file->_file))
548         return FALSE;
549
550     file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1);
551     if(file->_base) {
552         file->_bufsiz = MSVCRT_BUFSIZ;
553         file->_flag |= MSVCRT__IOMYBUF;
554     } else {
555         file->_base = (char*)(&file->_charbuf);
556         /* put here 2 ??? */
557         file->_bufsiz = sizeof(file->_charbuf);
558     }
559     file->_ptr = file->_base;
560     file->_cnt = 0;
561     return TRUE;
562 }
563
564 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
565 static BOOL add_std_buffer(MSVCRT_FILE *file)
566 {
567     static char buffers[2][MSVCRT_BUFSIZ];
568
569     if((file->_file!=MSVCRT_STDOUT_FILENO && file->_file!=MSVCRT_STDERR_FILENO)
570             || !MSVCRT__isatty(file->_file) || file->_bufsiz)
571         return FALSE;
572
573     file->_ptr = file->_base = buffers[file->_file == MSVCRT_STDOUT_FILENO ? 0 : 1];
574     file->_bufsiz = file->_cnt = MSVCRT_BUFSIZ;
575     return TRUE;
576 }
577
578 /* INTERNAL: Removes temporary buffer from stdout or stderr */
579 /* Only call this function when add_std_buffer returned TRUE */
580 static void remove_std_buffer(MSVCRT_FILE *file)
581 {
582     msvcrt_flush_buffer(file);
583     file->_ptr = file->_base = NULL;
584     file->_bufsiz = file->_cnt = 0;
585 }
586
587 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
588 static int msvcrt_int_to_base32(int num, char *str)
589 {
590   char *p;
591   int n = num;
592   int digits = 0;
593
594   while (n != 0)
595   {
596     n >>= 5;
597     digits++;
598   }
599   p = str + digits;
600   *p = 0;
601   while (--p >= str)
602   {
603     *p = (num & 31) + '0';
604     if (*p > '9')
605       *p += ('a' - '0' - 10);
606     num >>= 5;
607   }
608
609   return digits;
610 }
611
612 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
613 static int msvcrt_int_to_base32_w(int num, MSVCRT_wchar_t *str)
614 {
615     MSVCRT_wchar_t *p;
616     int n = num;
617     int digits = 0;
618
619     while (n != 0)
620     {
621         n >>= 5;
622         digits++;
623     }
624     p = str + digits;
625     *p = 0;
626     while (--p >= str)
627     {
628         *p = (num & 31) + '0';
629         if (*p > '9')
630             *p += ('a' - '0' - 10);
631         num >>= 5;
632     }
633
634     return digits;
635 }
636
637 /*********************************************************************
638  *              __iob_func(MSVCRT.@)
639  */
640 MSVCRT_FILE * CDECL MSVCRT___iob_func(void)
641 {
642  return &MSVCRT__iob[0];
643 }
644
645 /*********************************************************************
646  *              _access (MSVCRT.@)
647  */
648 int CDECL MSVCRT__access(const char *filename, int mode)
649 {
650   DWORD attr = GetFileAttributesA(filename);
651
652   TRACE("(%s,%d) %d\n",filename,mode,attr);
653
654   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
655   {
656     msvcrt_set_errno(GetLastError());
657     return -1;
658   }
659   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
660   {
661     msvcrt_set_errno(ERROR_ACCESS_DENIED);
662     return -1;
663   }
664   return 0;
665 }
666
667 /*********************************************************************
668  *              _access_s (MSVCRT.@)
669  */
670 int CDECL _access_s(const char *filename, int mode)
671 {
672   if (!MSVCRT_CHECK_PMT(filename != NULL)) return -1;
673   if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return -1;
674
675   return MSVCRT__access(filename, mode);
676 }
677
678 /*********************************************************************
679  *              _waccess (MSVCRT.@)
680  */
681 int CDECL MSVCRT__waccess(const MSVCRT_wchar_t *filename, int mode)
682 {
683   DWORD attr = GetFileAttributesW(filename);
684
685   TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
686
687   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
688   {
689     msvcrt_set_errno(GetLastError());
690     return -1;
691   }
692   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
693   {
694     msvcrt_set_errno(ERROR_ACCESS_DENIED);
695     return -1;
696   }
697   return 0;
698 }
699
700 /*********************************************************************
701  *              _waccess_s (MSVCRT.@)
702  */
703 int CDECL _waccess_s(const MSVCRT_wchar_t *filename, int mode)
704 {
705   if (!MSVCRT_CHECK_PMT(filename != NULL)) return -1;
706   if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return -1;
707
708   return MSVCRT__waccess(filename, mode);
709 }
710
711 /*********************************************************************
712  *              _chmod (MSVCRT.@)
713  */
714 int CDECL MSVCRT__chmod(const char *path, int flags)
715 {
716   DWORD oldFlags = GetFileAttributesA(path);
717
718   if (oldFlags != INVALID_FILE_ATTRIBUTES)
719   {
720     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
721       oldFlags | FILE_ATTRIBUTE_READONLY;
722
723     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
724       return 0;
725   }
726   msvcrt_set_errno(GetLastError());
727   return -1;
728 }
729
730 /*********************************************************************
731  *              _wchmod (MSVCRT.@)
732  */
733 int CDECL MSVCRT__wchmod(const MSVCRT_wchar_t *path, int flags)
734 {
735   DWORD oldFlags = GetFileAttributesW(path);
736
737   if (oldFlags != INVALID_FILE_ATTRIBUTES)
738   {
739     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
740       oldFlags | FILE_ATTRIBUTE_READONLY;
741
742     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
743       return 0;
744   }
745   msvcrt_set_errno(GetLastError());
746   return -1;
747 }
748
749 /*********************************************************************
750  *              _unlink (MSVCRT.@)
751  */
752 int CDECL MSVCRT__unlink(const char *path)
753 {
754   TRACE("%s\n",debugstr_a(path));
755   if(DeleteFileA(path))
756     return 0;
757   TRACE("failed (%d)\n",GetLastError());
758   msvcrt_set_errno(GetLastError());
759   return -1;
760 }
761
762 /*********************************************************************
763  *              _wunlink (MSVCRT.@)
764  */
765 int CDECL MSVCRT__wunlink(const MSVCRT_wchar_t *path)
766 {
767   TRACE("(%s)\n",debugstr_w(path));
768   if(DeleteFileW(path))
769     return 0;
770   TRACE("failed (%d)\n",GetLastError());
771   msvcrt_set_errno(GetLastError());
772   return -1;
773 }
774
775 /*********************************************************************
776  *              _commit (MSVCRT.@)
777  */
778 int CDECL MSVCRT__commit(int fd)
779 {
780     HANDLE hand = msvcrt_fdtoh(fd);
781
782     TRACE(":fd (%d) handle (%p)\n",fd,hand);
783     if (hand == INVALID_HANDLE_VALUE)
784         return -1;
785
786     if (!FlushFileBuffers(hand))
787     {
788         if (GetLastError() == ERROR_INVALID_HANDLE)
789         {
790             /* FlushFileBuffers fails for console handles
791              * so we ignore this error.
792              */
793             return 0;
794         }
795         TRACE(":failed-last error (%d)\n",GetLastError());
796         msvcrt_set_errno(GetLastError());
797         return -1;
798     }
799     TRACE(":ok\n");
800     return 0;
801 }
802
803 /* flush_all_buffers calls MSVCRT_fflush which calls flush_all_buffers */
804 int CDECL MSVCRT_fflush(MSVCRT_FILE* file);
805
806 /* INTERNAL: Flush all stream buffer */
807 static int msvcrt_flush_all_buffers(int mask)
808 {
809   int i, num_flushed = 0;
810   MSVCRT_FILE *file;
811
812   LOCK_FILES();
813   for (i = 3; i < MSVCRT_stream_idx; i++) {
814     file = msvcrt_get_file(i);
815
816     if (file->_flag)
817     {
818       if(file->_flag & mask) {
819         MSVCRT_fflush(file);
820         num_flushed++;
821       }
822     }
823   }
824   UNLOCK_FILES();
825
826   TRACE(":flushed (%d) handles\n",num_flushed);
827   return num_flushed;
828 }
829
830 /*********************************************************************
831  *              _flushall (MSVCRT.@)
832  */
833 int CDECL MSVCRT__flushall(void)
834 {
835     return msvcrt_flush_all_buffers(MSVCRT__IOWRT | MSVCRT__IOREAD);
836 }
837
838 /*********************************************************************
839  *              fflush (MSVCRT.@)
840  */
841 int CDECL MSVCRT_fflush(MSVCRT_FILE* file)
842 {
843     if(!file) {
844         msvcrt_flush_all_buffers(MSVCRT__IOWRT);
845     } else if(file->_flag & MSVCRT__IOWRT) {
846         int res;
847
848         MSVCRT__lock_file(file);
849         res = msvcrt_flush_buffer(file);
850
851         if(!res && (file->_flag & MSVCRT__IOCOMMIT))
852             res = MSVCRT__commit(file->_file) ? MSVCRT_EOF : 0;
853         MSVCRT__unlock_file(file);
854
855         return res;
856     } else if(file->_flag & MSVCRT__IOREAD) {
857         MSVCRT__lock_file(file);
858         file->_cnt = 0;
859         file->_ptr = file->_base;
860         MSVCRT__unlock_file(file);
861
862         return 0;
863     }
864     return 0;
865 }
866
867 /*********************************************************************
868  *              _close (MSVCRT.@)
869  */
870 int CDECL MSVCRT__close(int fd)
871 {
872   HANDLE hand;
873   int ret;
874
875   LOCK_FILES();
876   hand = msvcrt_fdtoh(fd);
877   TRACE(":fd (%d) handle (%p)\n",fd,hand);
878   if (!msvcrt_is_valid_fd(fd)) {
879     ret = -1;
880   } else {
881     msvcrt_free_fd(fd);
882     ret = CloseHandle(hand) ? 0 : -1;
883     if (ret) {
884       WARN(":failed-last error (%d)\n",GetLastError());
885       msvcrt_set_errno(GetLastError());
886     }
887   }
888   UNLOCK_FILES();
889   TRACE(":ok\n");
890   return ret;
891 }
892
893 /*********************************************************************
894  *              _dup2 (MSVCRT.@)
895  * NOTES
896  * MSDN isn't clear on this point, but the remarks for _pipe
897  * indicate file descriptors duplicated with _dup and _dup2 are always
898  * inheritable.
899  */
900 int CDECL MSVCRT__dup2(int od, int nd)
901 {
902   int ret;
903
904   TRACE("(od=%d, nd=%d)\n", od, nd);
905   LOCK_FILES();
906   if (nd < MSVCRT_MAX_FILES && nd >= 0 && msvcrt_is_valid_fd(od))
907   {
908     HANDLE handle;
909
910     if (DuplicateHandle(GetCurrentProcess(), msvcrt_get_ioinfo(od)->handle,
911      GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
912     {
913       int wxflag = msvcrt_get_ioinfo(od)->wxflag & ~MSVCRT__O_NOINHERIT;
914
915       if (msvcrt_is_valid_fd(nd))
916         MSVCRT__close(nd);
917       ret = msvcrt_set_fd(handle, wxflag, nd);
918       if (ret == -1)
919       {
920         CloseHandle(handle);
921         *MSVCRT__errno() = MSVCRT_EMFILE;
922       }
923       else
924       {
925         /* _dup2 returns 0, not nd, on success */
926         ret = 0;
927       }
928     }
929     else
930     {
931       ret = -1;
932       msvcrt_set_errno(GetLastError());
933     }
934   }
935   else
936   {
937     *MSVCRT__errno() = MSVCRT_EBADF;
938     ret = -1;
939   }
940   UNLOCK_FILES();
941   return ret;
942 }
943
944 /*********************************************************************
945  *              _dup (MSVCRT.@)
946  */
947 int CDECL MSVCRT__dup(int od)
948 {
949   int fd, ret;
950  
951   LOCK_FILES();
952   fd = MSVCRT_fdstart;
953   if (MSVCRT__dup2(od, fd) == 0)
954     ret = fd;
955   else
956     ret = -1;
957   UNLOCK_FILES();
958   return ret;
959 }
960
961 /*********************************************************************
962  *              _eof (MSVCRT.@)
963  */
964 int CDECL MSVCRT__eof(int fd)
965 {
966   DWORD curpos,endpos;
967   LONG hcurpos,hendpos;
968   HANDLE hand = msvcrt_fdtoh(fd);
969
970   TRACE(":fd (%d) handle (%p)\n",fd,hand);
971
972   if (hand == INVALID_HANDLE_VALUE)
973     return -1;
974
975   if (msvcrt_get_ioinfo(fd)->wxflag & WX_ATEOF) return TRUE;
976
977   /* Otherwise we do it the hard way */
978   hcurpos = hendpos = 0;
979   curpos = SetFilePointer(hand, 0, &hcurpos, FILE_CURRENT);
980   endpos = SetFilePointer(hand, 0, &hendpos, FILE_END);
981
982   if (curpos == endpos && hcurpos == hendpos)
983   {
984     /* FIXME: shouldn't WX_ATEOF be set here? */
985     return TRUE;
986   }
987
988   SetFilePointer(hand, curpos, &hcurpos, FILE_BEGIN);
989   return FALSE;
990 }
991
992 /*********************************************************************
993  *              _fcloseall (MSVCRT.@)
994  */
995 int CDECL MSVCRT__fcloseall(void)
996 {
997   int num_closed = 0, i;
998   MSVCRT_FILE *file;
999
1000   LOCK_FILES();
1001   for (i = 3; i < MSVCRT_stream_idx; i++) {
1002     file = msvcrt_get_file(i);
1003
1004     if (file->_flag && !MSVCRT_fclose(file))
1005       num_closed++;
1006   }
1007   UNLOCK_FILES();
1008
1009   TRACE(":closed (%d) handles\n",num_closed);
1010   return num_closed;
1011 }
1012
1013 /* free everything on process exit */
1014 void msvcrt_free_io(void)
1015 {
1016     unsigned int i;
1017     int j;
1018
1019     MSVCRT__fcloseall();
1020     /* The Win32 _fcloseall() function explicitly doesn't close stdin,
1021      * stdout, and stderr (unlike GNU), so we need to fclose() them here
1022      * or they won't get flushed.
1023      */
1024     MSVCRT_fclose(&MSVCRT__iob[0]);
1025     MSVCRT_fclose(&MSVCRT__iob[1]);
1026     MSVCRT_fclose(&MSVCRT__iob[2]);
1027
1028     for(i=0; i<sizeof(MSVCRT___pioinfo)/sizeof(MSVCRT___pioinfo[0]); i++)
1029         MSVCRT_free(MSVCRT___pioinfo[i]);
1030
1031     for(j=0; j<MSVCRT_stream_idx; j++)
1032     {
1033         MSVCRT_FILE *file = msvcrt_get_file(j);
1034         if(file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
1035         {
1036             ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1037             DeleteCriticalSection(&((file_crit*)file)->crit);
1038         }
1039     }
1040
1041     for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1042         MSVCRT_free(MSVCRT_fstream[i]);
1043
1044     DeleteCriticalSection(&MSVCRT_file_cs);
1045 }
1046
1047 /*********************************************************************
1048  *              _lseeki64 (MSVCRT.@)
1049  */
1050 __int64 CDECL MSVCRT__lseeki64(int fd, __int64 offset, int whence)
1051 {
1052   HANDLE hand = msvcrt_fdtoh(fd);
1053   LARGE_INTEGER ofs;
1054
1055   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1056   if (hand == INVALID_HANDLE_VALUE)
1057     return -1;
1058
1059   if (whence < 0 || whence > 2)
1060   {
1061     *MSVCRT__errno() = MSVCRT_EINVAL;
1062     return -1;
1063   }
1064
1065   TRACE(":fd (%d) to %s pos %s\n",
1066         fd,wine_dbgstr_longlong(offset),
1067         (whence==SEEK_SET)?"SEEK_SET":
1068         (whence==SEEK_CUR)?"SEEK_CUR":
1069         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1070
1071   /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1072    * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1073   ofs.QuadPart = offset;
1074   if ((ofs.u.LowPart = SetFilePointer(hand, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1075       GetLastError() == ERROR_SUCCESS)
1076   {
1077     msvcrt_get_ioinfo(fd)->wxflag &= ~WX_ATEOF;
1078     /* FIXME: What if we seek _to_ EOF - is EOF set? */
1079
1080     return ofs.QuadPart;
1081   }
1082   TRACE(":error-last error (%d)\n",GetLastError());
1083   msvcrt_set_errno(GetLastError());
1084   return -1;
1085 }
1086
1087 /*********************************************************************
1088  *              _lseek (MSVCRT.@)
1089  */
1090 LONG CDECL MSVCRT__lseek(int fd, LONG offset, int whence)
1091 {
1092     return MSVCRT__lseeki64(fd, offset, whence);
1093 }
1094
1095 /*********************************************************************
1096  *              _lock_file (MSVCRT.@)
1097  */
1098 void CDECL MSVCRT__lock_file(MSVCRT_FILE *file)
1099 {
1100     if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1101         _lock(_STREAM_LOCKS+(file-MSVCRT__iob));
1102     else
1103         EnterCriticalSection(&((file_crit*)file)->crit);
1104 }
1105
1106 /*********************************************************************
1107  *              _unlock_file (MSVCRT.@)
1108  */
1109 void CDECL MSVCRT__unlock_file(MSVCRT_FILE *file)
1110 {
1111     if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1112         _unlock(_STREAM_LOCKS+(file-MSVCRT__iob));
1113     else
1114         LeaveCriticalSection(&((file_crit*)file)->crit);
1115 }
1116
1117 /*********************************************************************
1118  *              _locking (MSVCRT.@)
1119  *
1120  * This is untested; the underlying LockFile doesn't work yet.
1121  */
1122 int CDECL MSVCRT__locking(int fd, int mode, LONG nbytes)
1123 {
1124   BOOL ret;
1125   DWORD cur_locn;
1126   HANDLE hand = msvcrt_fdtoh(fd);
1127
1128   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1129   if (hand == INVALID_HANDLE_VALUE)
1130     return -1;
1131
1132   if (mode < 0 || mode > 4)
1133   {
1134     *MSVCRT__errno() = MSVCRT_EINVAL;
1135     return -1;
1136   }
1137
1138   TRACE(":fd (%d) by 0x%08x mode %s\n",
1139         fd,nbytes,(mode==MSVCRT__LK_UNLCK)?"_LK_UNLCK":
1140         (mode==MSVCRT__LK_LOCK)?"_LK_LOCK":
1141         (mode==MSVCRT__LK_NBLCK)?"_LK_NBLCK":
1142         (mode==MSVCRT__LK_RLCK)?"_LK_RLCK":
1143         (mode==MSVCRT__LK_NBRLCK)?"_LK_NBRLCK":
1144                           "UNKNOWN");
1145
1146   if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
1147   {
1148     FIXME ("Seek failed\n");
1149     *MSVCRT__errno() = MSVCRT_EINVAL; /* FIXME */
1150     return -1;
1151   }
1152   if (mode == MSVCRT__LK_LOCK || mode == MSVCRT__LK_RLCK)
1153   {
1154     int nretry = 10;
1155     ret = 1; /* just to satisfy gcc */
1156     while (nretry--)
1157     {
1158       ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1159       if (ret) break;
1160       Sleep(1);
1161     }
1162   }
1163   else if (mode == MSVCRT__LK_UNLCK)
1164     ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
1165   else
1166     ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1167   /* FIXME - what about error settings? */
1168   return ret ? 0 : -1;
1169 }
1170
1171 /*********************************************************************
1172  *              _fseeki64 (MSVCRT.@)
1173  */
1174 int CDECL MSVCRT__fseeki64(MSVCRT_FILE* file, __int64 offset, int whence)
1175 {
1176   int ret;
1177
1178   MSVCRT__lock_file(file);
1179   /* Flush output if needed */
1180   if(file->_flag & MSVCRT__IOWRT)
1181         msvcrt_flush_buffer(file);
1182
1183   if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) {
1184       whence = SEEK_SET;
1185       offset += MSVCRT__ftelli64(file);
1186   }
1187
1188   /* Discard buffered input */
1189   file->_cnt = 0;
1190   file->_ptr = file->_base;
1191   /* Reset direction of i/o */
1192   if(file->_flag & MSVCRT__IORW) {
1193         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
1194   }
1195   /* Clear end of file flag */
1196   file->_flag &= ~MSVCRT__IOEOF;
1197   ret = (MSVCRT__lseeki64(file->_file,offset,whence) == -1)?-1:0;
1198
1199   MSVCRT__unlock_file(file);
1200   return ret;
1201 }
1202
1203 /*********************************************************************
1204  *              fseek (MSVCRT.@)
1205  */
1206 int CDECL MSVCRT_fseek(MSVCRT_FILE* file, MSVCRT_long offset, int whence)
1207 {
1208     return MSVCRT__fseeki64( file, offset, whence );
1209 }
1210
1211 /*********************************************************************
1212  *              _chsize (MSVCRT.@)
1213  */
1214 int CDECL MSVCRT__chsize(int fd, MSVCRT_long size)
1215 {
1216     LONG cur, pos;
1217     HANDLE handle;
1218     BOOL ret = FALSE;
1219
1220     TRACE("(fd=%d, size=%d)\n", fd, size);
1221
1222     LOCK_FILES();
1223
1224     handle = msvcrt_fdtoh(fd);
1225     if (handle != INVALID_HANDLE_VALUE)
1226     {
1227         /* save the current file pointer */
1228         cur = MSVCRT__lseek(fd, 0, SEEK_CUR);
1229         if (cur >= 0)
1230         {
1231             pos = MSVCRT__lseek(fd, size, SEEK_SET);
1232             if (pos >= 0)
1233             {
1234                 ret = SetEndOfFile(handle);
1235                 if (!ret) msvcrt_set_errno(GetLastError());
1236             }
1237
1238             /* restore the file pointer */
1239             MSVCRT__lseek(fd, cur, SEEK_SET);
1240         }
1241     }
1242
1243     UNLOCK_FILES();
1244     return ret ? 0 : -1;
1245 }
1246
1247 /*********************************************************************
1248  *              clearerr (MSVCRT.@)
1249  */
1250 void CDECL MSVCRT_clearerr(MSVCRT_FILE* file)
1251 {
1252   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1253
1254   MSVCRT__lock_file(file);
1255   file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
1256   MSVCRT__unlock_file(file);
1257 }
1258
1259 /*********************************************************************
1260  *              rewind (MSVCRT.@)
1261  */
1262 void CDECL MSVCRT_rewind(MSVCRT_FILE* file)
1263 {
1264   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1265
1266   MSVCRT__lock_file(file);
1267   MSVCRT_fseek(file, 0L, SEEK_SET);
1268   MSVCRT_clearerr(file);
1269   MSVCRT__unlock_file(file);
1270 }
1271
1272 static int msvcrt_get_flags(const MSVCRT_wchar_t* mode, int *open_flags, int* stream_flags)
1273 {
1274   int plus = strchrW(mode, '+') != NULL;
1275
1276   TRACE("%s\n", debugstr_w(mode));
1277
1278   while(*mode == ' ') mode++;
1279
1280   switch(*mode++)
1281   {
1282   case 'R': case 'r':
1283     *open_flags = plus ? MSVCRT__O_RDWR : MSVCRT__O_RDONLY;
1284     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOREAD;
1285     break;
1286   case 'W': case 'w':
1287     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_TRUNC | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1288     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1289     break;
1290   case 'A': case 'a':
1291     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_APPEND | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1292     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1293     break;
1294   default:
1295     MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1296     return -1;
1297   }
1298
1299   *stream_flags |= MSVCRT__commode;
1300
1301   while (*mode && *mode!=',')
1302     switch (*mode++)
1303     {
1304     case 'B': case 'b':
1305       *open_flags |=  MSVCRT__O_BINARY;
1306       *open_flags &= ~MSVCRT__O_TEXT;
1307       break;
1308     case 't':
1309       *open_flags |=  MSVCRT__O_TEXT;
1310       *open_flags &= ~MSVCRT__O_BINARY;
1311       break;
1312     case 'D':
1313       *open_flags |= MSVCRT__O_TEMPORARY;
1314       break;
1315     case 'T':
1316       *open_flags |= MSVCRT__O_SHORT_LIVED;
1317       break;
1318     case 'c':
1319       *stream_flags |= MSVCRT__IOCOMMIT;
1320       break;
1321     case 'n':
1322       *stream_flags &= ~MSVCRT__IOCOMMIT;
1323       break;
1324     case 'N':
1325       *open_flags |= MSVCRT__O_NOINHERIT;
1326       break;
1327     case '+':
1328     case ' ':
1329     case 'a':
1330     case 'w':
1331       break;
1332     case 'S':
1333     case 'R':
1334       FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1335       break;
1336     default:
1337       MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1338       return -1;
1339     }
1340
1341   if(*mode == ',')
1342   {
1343     static const WCHAR ccs[] = {'c','c','s'};
1344     static const WCHAR utf8[] = {'u','t','f','-','8'};
1345     static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1346     static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1347
1348     mode++;
1349     while(*mode == ' ') mode++;
1350     if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1351       return -1;
1352     mode += sizeof(ccs)/sizeof(ccs[0]);
1353     while(*mode == ' ') mode++;
1354     if(!MSVCRT_CHECK_PMT(*mode == '='))
1355         return -1;
1356     mode++;
1357     while(*mode == ' ') mode++;
1358
1359     if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1360     {
1361       *open_flags |= MSVCRT__O_U8TEXT;
1362       mode += sizeof(utf8)/sizeof(utf8[0]);
1363     }
1364     else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1365     {
1366       *open_flags |= MSVCRT__O_U16TEXT;
1367       mode += sizeof(utf16le)/sizeof(utf16le[0]);
1368     }
1369     else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1370     {
1371       *open_flags |= MSVCRT__O_WTEXT;
1372       mode += sizeof(unicode)/sizeof(unicode[0]);
1373     }
1374     else
1375     {
1376       MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1377       return -1;
1378     }
1379
1380     while(*mode == ' ') mode++;
1381   }
1382
1383   if(!MSVCRT_CHECK_PMT(*mode == 0))
1384     return -1;
1385   return 0;
1386 }
1387
1388 /*********************************************************************
1389  *              _fdopen (MSVCRT.@)
1390  */
1391 MSVCRT_FILE* CDECL MSVCRT__fdopen(int fd, const char *mode)
1392 {
1393     MSVCRT_FILE *ret;
1394     MSVCRT_wchar_t *modeW = NULL;
1395
1396     if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1397
1398     ret = MSVCRT__wfdopen(fd, modeW);
1399
1400     MSVCRT_free(modeW);
1401     return ret;
1402 }
1403
1404 /*********************************************************************
1405  *              _wfdopen (MSVCRT.@)
1406  */
1407 MSVCRT_FILE* CDECL MSVCRT__wfdopen(int fd, const MSVCRT_wchar_t *mode)
1408 {
1409   int open_flags, stream_flags;
1410   MSVCRT_FILE* file;
1411
1412   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1413
1414   LOCK_FILES();
1415   if (!(file = msvcrt_alloc_fp()))
1416     file = NULL;
1417   else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1418   {
1419     file->_flag = 0;
1420     file = NULL;
1421   }
1422   else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1423   UNLOCK_FILES();
1424
1425   return file;
1426 }
1427
1428 /*********************************************************************
1429  *              _filelength (MSVCRT.@)
1430  */
1431 LONG CDECL MSVCRT__filelength(int fd)
1432 {
1433   LONG curPos = MSVCRT__lseek(fd, 0, SEEK_CUR);
1434   if (curPos != -1)
1435   {
1436     LONG endPos = MSVCRT__lseek(fd, 0, SEEK_END);
1437     if (endPos != -1)
1438     {
1439       if (endPos != curPos)
1440         MSVCRT__lseek(fd, curPos, SEEK_SET);
1441       return endPos;
1442     }
1443   }
1444   return -1;
1445 }
1446
1447 /*********************************************************************
1448  *              _filelengthi64 (MSVCRT.@)
1449  */
1450 __int64 CDECL MSVCRT__filelengthi64(int fd)
1451 {
1452   __int64 curPos = MSVCRT__lseeki64(fd, 0, SEEK_CUR);
1453   if (curPos != -1)
1454   {
1455     __int64 endPos = MSVCRT__lseeki64(fd, 0, SEEK_END);
1456     if (endPos != -1)
1457     {
1458       if (endPos != curPos)
1459         MSVCRT__lseeki64(fd, curPos, SEEK_SET);
1460       return endPos;
1461     }
1462   }
1463   return -1;
1464 }
1465
1466 /*********************************************************************
1467  *              _fileno (MSVCRT.@)
1468  */
1469 int CDECL MSVCRT__fileno(MSVCRT_FILE* file)
1470 {
1471   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1472   return file->_file;
1473 }
1474
1475 /*********************************************************************
1476  *              _fstat64 (MSVCRT.@)
1477  */
1478 int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf)
1479 {
1480   DWORD dw;
1481   DWORD type;
1482   BY_HANDLE_FILE_INFORMATION hfi;
1483   HANDLE hand = msvcrt_fdtoh(fd);
1484
1485   TRACE(":fd (%d) stat (%p)\n",fd,buf);
1486   if (hand == INVALID_HANDLE_VALUE)
1487     return -1;
1488
1489   if (!buf)
1490   {
1491     WARN(":failed-NULL buf\n");
1492     msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1493     return -1;
1494   }
1495
1496   memset(&hfi, 0, sizeof(hfi));
1497   memset(buf, 0, sizeof(struct MSVCRT__stat64));
1498   type = GetFileType(hand);
1499   if (type == FILE_TYPE_PIPE)
1500   {
1501     buf->st_dev = buf->st_rdev = fd;
1502     buf->st_mode = S_IFIFO;
1503     buf->st_nlink = 1;
1504   }
1505   else if (type == FILE_TYPE_CHAR)
1506   {
1507     buf->st_dev = buf->st_rdev = fd;
1508     buf->st_mode = S_IFCHR;
1509     buf->st_nlink = 1;
1510   }
1511   else /* FILE_TYPE_DISK etc. */
1512   {
1513     if (!GetFileInformationByHandle(hand, &hfi))
1514     {
1515       WARN(":failed-last error (%d)\n",GetLastError());
1516       msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1517       return -1;
1518     }
1519     buf->st_mode = S_IFREG | 0444;
1520     if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1521       buf->st_mode |= 0222;
1522     buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1523     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1524     buf->st_atime = dw;
1525     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1526     buf->st_mtime = buf->st_ctime = dw;
1527     buf->st_nlink = hfi.nNumberOfLinks;
1528   }
1529   TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
1530    buf->st_mode);
1531   return 0;
1532 }
1533
1534 /*********************************************************************
1535  *              _fstati64 (MSVCRT.@)
1536  */
1537 int CDECL MSVCRT__fstati64(int fd, struct MSVCRT__stati64* buf)
1538 {
1539   int ret;
1540   struct MSVCRT__stat64 buf64;
1541
1542   ret = MSVCRT__fstat64(fd, &buf64);
1543   if (!ret)
1544     msvcrt_stat64_to_stati64(&buf64, buf);
1545   return ret;
1546 }
1547
1548 /*********************************************************************
1549  *              _fstat (MSVCRT.@)
1550  */
1551 int CDECL MSVCRT__fstat(int fd, struct MSVCRT__stat* buf)
1552 { int ret;
1553   struct MSVCRT__stat64 buf64;
1554
1555   ret = MSVCRT__fstat64(fd, &buf64);
1556   if (!ret)
1557       msvcrt_stat64_to_stat(&buf64, buf);
1558   return ret;
1559 }
1560
1561 /*********************************************************************
1562  *              _futime64 (MSVCRT.@)
1563  */
1564 int CDECL _futime64(int fd, struct MSVCRT___utimbuf64 *t)
1565 {
1566   HANDLE hand = msvcrt_fdtoh(fd);
1567   FILETIME at, wt;
1568
1569   if (!t)
1570   {
1571       time_to_filetime( MSVCRT__time64(NULL), &at );
1572       wt = at;
1573   }
1574   else
1575   {
1576       time_to_filetime( t->actime, &at );
1577       time_to_filetime( t->modtime, &wt );
1578   }
1579
1580   if (!SetFileTime(hand, NULL, &at, &wt))
1581   {
1582     msvcrt_set_errno(GetLastError());
1583     return -1 ;
1584   }
1585   return 0;
1586 }
1587
1588 /*********************************************************************
1589  *              _futime32 (MSVCRT.@)
1590  */
1591 int CDECL _futime32(int fd, struct MSVCRT___utimbuf32 *t)
1592 {
1593     if (t)
1594     {
1595         struct MSVCRT___utimbuf64 t64;
1596         t64.actime = t->actime;
1597         t64.modtime = t->modtime;
1598         return _futime64( fd, &t64 );
1599     }
1600     else
1601         return _futime64( fd, NULL );
1602 }
1603
1604 /*********************************************************************
1605  *              _futime (MSVCRT.@)
1606  */
1607 #ifdef _WIN64
1608 int CDECL _futime(int fd, struct MSVCRT___utimbuf64 *t)
1609 {
1610     return _futime64( fd, t );
1611 }
1612 #else
1613 int CDECL _futime(int fd, struct MSVCRT___utimbuf32 *t)
1614 {
1615     return _futime32( fd, t );
1616 }
1617 #endif
1618
1619 /*********************************************************************
1620  *              _get_osfhandle (MSVCRT.@)
1621  */
1622 MSVCRT_intptr_t CDECL MSVCRT__get_osfhandle(int fd)
1623 {
1624   HANDLE hand = msvcrt_fdtoh(fd);
1625   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1626
1627   return (MSVCRT_intptr_t)hand;
1628 }
1629
1630 /*********************************************************************
1631  *              _mktemp (MSVCRT.@)
1632  */
1633 char * CDECL MSVCRT__mktemp(char *pattern)
1634 {
1635   int numX = 0;
1636   char *retVal = pattern;
1637   int id;
1638   char letter = 'a';
1639
1640   while(*pattern)
1641     numX = (*pattern++ == 'X')? numX + 1 : 0;
1642   if (numX < 5)
1643     return NULL;
1644   pattern--;
1645   id = GetCurrentProcessId();
1646   numX = 6;
1647   while(numX--)
1648   {
1649     int tempNum = id / 10;
1650     *pattern-- = id - (tempNum * 10) + '0';
1651     id = tempNum;
1652   }
1653   pattern++;
1654   do
1655   {
1656     *pattern = letter++;
1657     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
1658         GetLastError() == ERROR_FILE_NOT_FOUND)
1659       return retVal;
1660   } while(letter <= 'z');
1661   return NULL;
1662 }
1663
1664 /*********************************************************************
1665  *              _wmktemp (MSVCRT.@)
1666  */
1667 MSVCRT_wchar_t * CDECL MSVCRT__wmktemp(MSVCRT_wchar_t *pattern)
1668 {
1669   int numX = 0;
1670   MSVCRT_wchar_t *retVal = pattern;
1671   int id;
1672   MSVCRT_wchar_t letter = 'a';
1673
1674   while(*pattern)
1675     numX = (*pattern++ == 'X')? numX + 1 : 0;
1676   if (numX < 5)
1677     return NULL;
1678   pattern--;
1679   id = GetCurrentProcessId();
1680   numX = 6;
1681   while(numX--)
1682   {
1683     int tempNum = id / 10;
1684     *pattern-- = id - (tempNum * 10) + '0';
1685     id = tempNum;
1686   }
1687   pattern++;
1688   do
1689   {
1690     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1691         GetLastError() == ERROR_FILE_NOT_FOUND)
1692       return retVal;
1693     *pattern = letter++;
1694   } while(letter != '|');
1695   return NULL;
1696 }
1697
1698 static unsigned split_oflags(unsigned oflags)
1699 {
1700     int         wxflags = 0;
1701     unsigned unsupp; /* until we support everything */
1702
1703     if (oflags & MSVCRT__O_APPEND)              wxflags |= WX_APPEND;
1704     if (oflags & MSVCRT__O_BINARY)              {/* Nothing to do */}
1705     else if (oflags & MSVCRT__O_TEXT)           wxflags |= WX_TEXT;
1706     else if (oflags & MSVCRT__O_WTEXT)          wxflags |= WX_TEXT;
1707     else if (oflags & MSVCRT__O_U16TEXT)        wxflags |= WX_TEXT;
1708     else if (oflags & MSVCRT__O_U8TEXT)         wxflags |= WX_TEXT;
1709     else if (*__p__fmode() & MSVCRT__O_BINARY)  {/* Nothing to do */}
1710     else                                        wxflags |= WX_TEXT; /* default to TEXT*/
1711     if (oflags & MSVCRT__O_NOINHERIT)           wxflags |= WX_DONTINHERIT;
1712
1713     if ((unsupp = oflags & ~(
1714                     MSVCRT__O_BINARY|MSVCRT__O_TEXT|MSVCRT__O_APPEND|
1715                     MSVCRT__O_TRUNC|MSVCRT__O_EXCL|MSVCRT__O_CREAT|
1716                     MSVCRT__O_RDWR|MSVCRT__O_WRONLY|MSVCRT__O_TEMPORARY|
1717                     MSVCRT__O_NOINHERIT|
1718                     MSVCRT__O_SEQUENTIAL|MSVCRT__O_RANDOM|MSVCRT__O_SHORT_LIVED|
1719                     MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT
1720                     )))
1721         ERR(":unsupported oflags 0x%04x\n",unsupp);
1722
1723     return wxflags;
1724 }
1725
1726 /*********************************************************************
1727  *              _pipe (MSVCRT.@)
1728  */
1729 int CDECL MSVCRT__pipe(int *pfds, unsigned int psize, int textmode)
1730 {
1731   int ret = -1;
1732   SECURITY_ATTRIBUTES sa;
1733   HANDLE readHandle, writeHandle;
1734
1735   if (!pfds)
1736   {
1737     *MSVCRT__errno() = MSVCRT_EINVAL;
1738     return -1;
1739   }
1740
1741   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1742   sa.bInheritHandle = !(textmode & MSVCRT__O_NOINHERIT);
1743   sa.lpSecurityDescriptor = NULL;
1744   if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1745   {
1746     unsigned int wxflags = split_oflags(textmode);
1747     int fd;
1748
1749     LOCK_FILES();
1750     fd = msvcrt_alloc_fd(readHandle, wxflags|WX_PIPE);
1751     if (fd != -1)
1752     {
1753       pfds[0] = fd;
1754       fd = msvcrt_alloc_fd(writeHandle, wxflags|WX_PIPE);
1755       if (fd != -1)
1756       {
1757         pfds[1] = fd;
1758         ret = 0;
1759       }
1760       else
1761       {
1762         MSVCRT__close(pfds[0]);
1763         CloseHandle(writeHandle);
1764         *MSVCRT__errno() = MSVCRT_EMFILE;
1765       }
1766     }
1767     else
1768     {
1769       CloseHandle(readHandle);
1770       CloseHandle(writeHandle);
1771       *MSVCRT__errno() = MSVCRT_EMFILE;
1772     }
1773     UNLOCK_FILES();
1774   }
1775   else
1776     msvcrt_set_errno(GetLastError());
1777
1778   return ret;
1779 }
1780
1781 static int check_bom(HANDLE h, int oflags, BOOL seek)
1782 {
1783     char bom[sizeof(utf8_bom)];
1784     DWORD r;
1785
1786     oflags &= ~(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT);
1787
1788     if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1789         return oflags;
1790
1791     if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1792         oflags |= MSVCRT__O_U8TEXT;
1793     }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1794         if (seek && r>2)
1795             SetFilePointer(h, 2, NULL, FILE_BEGIN);
1796         oflags |= MSVCRT__O_U16TEXT;
1797     }else if (seek) {
1798         SetFilePointer(h, 0, NULL, FILE_BEGIN);
1799     }
1800
1801     return oflags;
1802 }
1803
1804 /*********************************************************************
1805  *              _wsopen_s (MSVCRT.@)
1806  */
1807 int CDECL MSVCRT__wsopen_s( int *fd, const MSVCRT_wchar_t* path, int oflags, int shflags, int pmode )
1808 {
1809   DWORD access = 0, creation = 0, attrib;
1810   SECURITY_ATTRIBUTES sa;
1811   DWORD sharing;
1812   int wxflag;
1813   HANDLE hand;
1814
1815   TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1816         fd, debugstr_w(path), oflags, shflags, pmode);
1817
1818   if (!MSVCRT_CHECK_PMT( fd != NULL )) return MSVCRT_EINVAL;
1819
1820   *fd = -1;
1821   wxflag = split_oflags(oflags);
1822   switch (oflags & (MSVCRT__O_RDONLY | MSVCRT__O_WRONLY | MSVCRT__O_RDWR))
1823   {
1824   case MSVCRT__O_RDONLY: access |= GENERIC_READ; break;
1825   case MSVCRT__O_WRONLY: access |= GENERIC_WRITE; break;
1826   case MSVCRT__O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1827   }
1828
1829   if (oflags & MSVCRT__O_CREAT)
1830   {
1831     if(pmode & ~(MSVCRT__S_IREAD | MSVCRT__S_IWRITE))
1832       FIXME(": pmode 0x%04x ignored\n", pmode);
1833     else
1834       WARN(": pmode 0x%04x ignored\n", pmode);
1835
1836     if (oflags & MSVCRT__O_EXCL)
1837       creation = CREATE_NEW;
1838     else if (oflags & MSVCRT__O_TRUNC)
1839       creation = CREATE_ALWAYS;
1840     else
1841       creation = OPEN_ALWAYS;
1842   }
1843   else  /* no MSVCRT__O_CREAT */
1844   {
1845     if (oflags & MSVCRT__O_TRUNC)
1846       creation = TRUNCATE_EXISTING;
1847     else
1848       creation = OPEN_EXISTING;
1849   }
1850
1851   switch( shflags )
1852   {
1853     case MSVCRT__SH_DENYRW:
1854       sharing = 0L;
1855       break;
1856     case MSVCRT__SH_DENYWR:
1857       sharing = FILE_SHARE_READ;
1858       break;
1859     case MSVCRT__SH_DENYRD:
1860       sharing = FILE_SHARE_WRITE;
1861       break;
1862     case MSVCRT__SH_DENYNO:
1863       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1864       break;
1865     default:
1866       ERR( "Unhandled shflags 0x%x\n", shflags );
1867       return MSVCRT_EINVAL;
1868   }
1869   attrib = FILE_ATTRIBUTE_NORMAL;
1870
1871   if (oflags & MSVCRT__O_TEMPORARY)
1872   {
1873       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1874       access |= DELETE;
1875       sharing |= FILE_SHARE_DELETE;
1876   }
1877
1878   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1879   sa.lpSecurityDescriptor = NULL;
1880   sa.bInheritHandle       = !(oflags & MSVCRT__O_NOINHERIT);
1881
1882   if ((oflags&(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT))
1883           && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1884           && !(access&GENERIC_READ))
1885   {
1886       hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1887               &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1888       if (hand != INVALID_HANDLE_VALUE)
1889       {
1890           oflags = check_bom(hand, oflags, FALSE);
1891           CloseHandle(hand);
1892       }
1893       else
1894           oflags &= ~(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT);
1895   }
1896
1897   hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1898   if (hand == INVALID_HANDLE_VALUE)  {
1899     WARN(":failed-last error (%d)\n",GetLastError());
1900     msvcrt_set_errno(GetLastError());
1901     return *MSVCRT__errno();
1902   }
1903
1904   if (oflags & (MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT))
1905   {
1906       if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1907                   || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1908                   || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1909       {
1910           if (oflags & MSVCRT__O_U8TEXT)
1911           {
1912               DWORD written = 0, tmp;
1913
1914               while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1915                           sizeof(utf8_bom)-written, &tmp, NULL))
1916                   written += tmp;
1917               if (written != sizeof(utf8_bom)) {
1918                   WARN("error writing BOM\n");
1919                   CloseHandle(hand);
1920                   msvcrt_set_errno(GetLastError());
1921                   return *MSVCRT__errno();
1922               }
1923           }
1924           else
1925           {
1926               DWORD written = 0, tmp;
1927
1928               while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1929                           sizeof(utf16_bom)-written, &tmp, NULL))
1930                   written += tmp;
1931               if (written != sizeof(utf16_bom))
1932               {
1933                   WARN("error writing BOM\n");
1934                   CloseHandle(hand);
1935                   msvcrt_set_errno(GetLastError());
1936                   return *MSVCRT__errno();
1937               }
1938           }
1939       }
1940       else if (access & GENERIC_READ)
1941           oflags = check_bom(hand, oflags, TRUE);
1942   }
1943
1944   *fd = msvcrt_alloc_fd(hand, wxflag);
1945   if (*fd == -1)
1946       return *MSVCRT__errno();
1947
1948   if (oflags & MSVCRT__O_WTEXT)
1949       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1950   else if (oflags & MSVCRT__O_U16TEXT)
1951       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF16;
1952   else if (oflags & MSVCRT__O_U8TEXT)
1953       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF8;
1954
1955   TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1956   return 0;
1957 }
1958
1959 /*********************************************************************
1960  *              _wsopen (MSVCRT.@)
1961  */
1962 int CDECL MSVCRT__wsopen( const MSVCRT_wchar_t *path, int oflags, int shflags, ... )
1963 {
1964   int pmode;
1965   int fd;
1966
1967   if (oflags & MSVCRT__O_CREAT)
1968   {
1969     __ms_va_list ap;
1970
1971     __ms_va_start(ap, shflags);
1972     pmode = va_arg(ap, int);
1973     __ms_va_end(ap);
1974   }
1975   else
1976     pmode = 0;
1977
1978   MSVCRT__wsopen_s(&fd, path, oflags, shflags, pmode);
1979   return fd;
1980 }
1981
1982 /*********************************************************************
1983  *              _sopen_s (MSVCRT.@)
1984  */
1985 int CDECL MSVCRT__sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1986 {
1987     MSVCRT_wchar_t *pathW;
1988     int ret;
1989
1990     if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
1991         return MSVCRT_EINVAL;
1992
1993     ret = MSVCRT__wsopen_s(fd, pathW, oflags, shflags, pmode);
1994     MSVCRT_free(pathW);
1995     return ret;
1996 }
1997
1998 /*********************************************************************
1999  *              _sopen (MSVCRT.@)
2000  */
2001 int CDECL MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
2002 {
2003   int pmode;
2004   int fd;
2005
2006   if (oflags & MSVCRT__O_CREAT)
2007   {
2008     __ms_va_list ap;
2009
2010     __ms_va_start(ap, shflags);
2011     pmode = va_arg(ap, int);
2012     __ms_va_end(ap);
2013   }
2014   else
2015     pmode = 0;
2016
2017   MSVCRT__sopen_s(&fd, path, oflags, shflags, pmode);
2018   return fd;
2019 }
2020
2021 /*********************************************************************
2022  *              _open (MSVCRT.@)
2023  */
2024 int CDECL MSVCRT__open( const char *path, int flags, ... )
2025 {
2026   __ms_va_list ap;
2027
2028   if (flags & MSVCRT__O_CREAT)
2029   {
2030     int pmode;
2031     __ms_va_start(ap, flags);
2032     pmode = va_arg(ap, int);
2033     __ms_va_end(ap);
2034     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO, pmode );
2035   }
2036   else
2037     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO);
2038 }
2039
2040 /*********************************************************************
2041  *              _wopen (MSVCRT.@)
2042  */
2043 int CDECL MSVCRT__wopen(const MSVCRT_wchar_t *path,int flags,...)
2044 {
2045   __ms_va_list ap;
2046
2047   if (flags & MSVCRT__O_CREAT)
2048   {
2049     int pmode;
2050     __ms_va_start(ap, flags);
2051     pmode = va_arg(ap, int);
2052     __ms_va_end(ap);
2053     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO, pmode );
2054   }
2055   else
2056     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO);
2057 }
2058
2059 /*********************************************************************
2060  *              _creat (MSVCRT.@)
2061  */
2062 int CDECL MSVCRT__creat(const char *path, int flags)
2063 {
2064   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
2065   return MSVCRT__open(path, usedFlags);
2066 }
2067
2068 /*********************************************************************
2069  *              _wcreat (MSVCRT.@)
2070  */
2071 int CDECL MSVCRT__wcreat(const MSVCRT_wchar_t *path, int flags)
2072 {
2073   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
2074   return MSVCRT__wopen(path, usedFlags);
2075 }
2076
2077 /*********************************************************************
2078  *              _open_osfhandle (MSVCRT.@)
2079  */
2080 int CDECL MSVCRT__open_osfhandle(MSVCRT_intptr_t handle, int oflags)
2081 {
2082   int fd;
2083
2084   /* MSVCRT__O_RDONLY (0) always matches, so set the read flag
2085    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2086    * file, so set the write flag. It also only sets MSVCRT__O_TEXT if it wants
2087    * text - it never sets MSVCRT__O_BINARY.
2088    */
2089   /* don't let split_oflags() decide the mode if no mode is passed */
2090   if (!(oflags & (MSVCRT__O_BINARY | MSVCRT__O_TEXT)))
2091       oflags |= MSVCRT__O_BINARY;
2092
2093   fd = msvcrt_alloc_fd((HANDLE)handle, split_oflags(oflags));
2094   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, oflags);
2095   return fd;
2096 }
2097
2098 /*********************************************************************
2099  *              _rmtmp (MSVCRT.@)
2100  */
2101 int CDECL MSVCRT__rmtmp(void)
2102 {
2103   int num_removed = 0, i;
2104   MSVCRT_FILE *file;
2105
2106   LOCK_FILES();
2107   for (i = 3; i < MSVCRT_stream_idx; i++) {
2108     file = msvcrt_get_file(i);
2109
2110     if (file->_tmpfname)
2111     {
2112       MSVCRT_fclose(file);
2113       num_removed++;
2114     }
2115   }
2116   UNLOCK_FILES();
2117
2118   if (num_removed)
2119     TRACE(":removed (%d) temp files\n",num_removed);
2120   return num_removed;
2121 }
2122
2123 static inline int get_utf8_char_len(char ch)
2124 {
2125     if((ch&0xf8) == 0xf0)
2126         return 4;
2127     else if((ch&0xf0) == 0xe0)
2128         return 3;
2129     else if((ch&0xe0) == 0xc0)
2130         return 2;
2131     return 1;
2132 }
2133
2134 /*********************************************************************
2135  * (internal) read_utf8
2136  */
2137 static int read_utf8(int fd, MSVCRT_wchar_t *buf, unsigned int count)
2138 {
2139     ioinfo *fdinfo = msvcrt_get_ioinfo(fd);
2140     HANDLE hand = fdinfo->handle;
2141     char min_buf[4], *readbuf, lookahead;
2142     DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2143
2144     /* make the buffer big enough to hold at least one character */
2145     /* read bytes have to fit to output and lookahead buffers */
2146     count /= 2;
2147     readbuf_size = count < 4 ? 4 : count;
2148     if(readbuf_size<=4 || !(readbuf = MSVCRT_malloc(readbuf_size))) {
2149         readbuf_size = 4;
2150         readbuf = min_buf;
2151     }
2152
2153     if(fdinfo->lookahead[0] != '\n') {
2154         readbuf[pos++] = fdinfo->lookahead[0];
2155         fdinfo->lookahead[0] = '\n';
2156
2157         if(fdinfo->lookahead[1] != '\n') {
2158             readbuf[pos++] = fdinfo->lookahead[1];
2159             fdinfo->lookahead[1] = '\n';
2160
2161             if(fdinfo->lookahead[2] != '\n') {
2162                 readbuf[pos++] = fdinfo->lookahead[2];
2163                 fdinfo->lookahead[2] = '\n';
2164             }
2165         }
2166     }
2167
2168     /* NOTE: this case is broken in native dll, reading
2169      *        sometimes fails when small buffer is passed
2170      */
2171     if(count < 4) {
2172         if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2173             if (GetLastError() == ERROR_BROKEN_PIPE) {
2174                 fdinfo->wxflag |= WX_ATEOF;
2175                 return 0;
2176             }else {
2177                 msvcrt_set_errno(GetLastError());
2178                 return -1;
2179             }
2180         }else if(!num_read) {
2181             fdinfo->wxflag |= WX_ATEOF;
2182             return 0;
2183         }else {
2184             pos++;
2185         }
2186
2187         char_len = get_utf8_char_len(readbuf[0]);
2188         if(char_len>pos) {
2189             if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2190                 pos += num_read;
2191         }
2192
2193         if(readbuf[0] == '\n')
2194             fdinfo->wxflag |= WX_READNL;
2195         else
2196             fdinfo->wxflag &= ~WX_READNL;
2197
2198         if(readbuf[0] == 0x1a) {
2199             fdinfo->wxflag |= WX_ATEOF;
2200             return 0;
2201         }
2202
2203         if(readbuf[0] == '\r') {
2204             if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2205                 buf[0] = '\r';
2206             else if(lookahead == '\n')
2207                 buf[0] = '\n';
2208             else {
2209                 buf[0] = '\r';
2210                 if(fdinfo->wxflag & WX_PIPE)
2211                     fdinfo->lookahead[0] = lookahead;
2212                 else
2213                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2214             }
2215             return 2;
2216         }
2217
2218         if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2219             msvcrt_set_errno(GetLastError());
2220             return -1;
2221         }
2222
2223         return num_read*2;
2224     }
2225
2226     if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2227         if(pos) {
2228             num_read = 0;
2229         }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2230             fdinfo->wxflag |= WX_ATEOF;
2231             if (readbuf != min_buf) MSVCRT_free(readbuf);
2232             return 0;
2233         }else {
2234             msvcrt_set_errno(GetLastError());
2235             if (readbuf != min_buf) MSVCRT_free(readbuf);
2236             return -1;
2237         }
2238     }else if(!pos && !num_read) {
2239         fdinfo->wxflag |= WX_ATEOF;
2240         if (readbuf != min_buf) MSVCRT_free(readbuf);
2241         return 0;
2242     }
2243
2244     pos += num_read;
2245     if(readbuf[0] == '\n')
2246         fdinfo->wxflag |= WX_READNL;
2247     else
2248         fdinfo->wxflag &= ~WX_READNL;
2249
2250     /* Find first byte of last character (may be incomplete) */
2251     for(i=pos-1; i>0 && i>pos-4; i--)
2252         if((readbuf[i]&0xc0) != 0x80)
2253             break;
2254     char_len = get_utf8_char_len(readbuf[i]);
2255     if(char_len+i <= pos)
2256         i += char_len;
2257
2258     if(fdinfo->wxflag & WX_PIPE) {
2259         if(i < pos)
2260             fdinfo->lookahead[0] = readbuf[i];
2261         if(i+1 < pos)
2262             fdinfo->lookahead[1] = readbuf[i+1];
2263         if(i+2 < pos)
2264             fdinfo->lookahead[2] = readbuf[i+2];
2265     }else if(i < pos) {
2266         SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2267     }
2268     pos = i;
2269
2270     for(i=0, j=0; i<pos; i++) {
2271         if(readbuf[i] == 0x1a) {
2272             fdinfo->wxflag |= WX_ATEOF;
2273             break;
2274         }
2275
2276         /* strip '\r' if followed by '\n' */
2277         if(readbuf[i] == '\r' && i+1==pos) {
2278             if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2279                 readbuf[j++] = '\r';
2280             }else if(lookahead == '\n' && j==0) {
2281                 readbuf[j++] = '\n';
2282             }else {
2283                 if(lookahead != '\n')
2284                     readbuf[j++] = '\r';
2285
2286                 if(fdinfo->wxflag & WX_PIPE)
2287                     fdinfo->lookahead[0] = lookahead;
2288                 else
2289                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2290             }
2291         }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2292             readbuf[j++] = readbuf[i];
2293         }
2294     }
2295     pos = j;
2296
2297     if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2298         msvcrt_set_errno(GetLastError());
2299         if (readbuf != min_buf) MSVCRT_free(readbuf);
2300         return -1;
2301     }
2302
2303     if (readbuf != min_buf) MSVCRT_free(readbuf);
2304     return num_read*2;
2305 }
2306
2307 /*********************************************************************
2308  * (internal) read_i
2309  *
2310  * When reading \r as last character in text mode, read() positions
2311  * the file pointer on the \r character while getc() goes on to
2312  * the following \n
2313  */
2314 static int read_i(int fd, void *buf, unsigned int count)
2315 {
2316     DWORD num_read, utf16;
2317     char *bufstart = buf;
2318     HANDLE hand = msvcrt_fdtoh(fd);
2319     ioinfo *fdinfo = msvcrt_get_ioinfo(fd);
2320
2321     if (count == 0)
2322         return 0;
2323
2324     if (fdinfo->wxflag & WX_ATEOF) {
2325         TRACE("already at EOF, returning 0\n");
2326         return 0;
2327     }
2328     /* Don't trace small reads, it gets *very* annoying */
2329     if (count > 4)
2330         TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
2331     if (hand == INVALID_HANDLE_VALUE)
2332     {
2333         *MSVCRT__errno() = MSVCRT_EBADF;
2334         return -1;
2335     }
2336
2337     utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2338     if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2339     {
2340         *MSVCRT__errno() = MSVCRT_EINVAL;
2341         return -1;
2342     }
2343
2344     if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2345         return read_utf8(fd, buf, count);
2346
2347     if (fdinfo->lookahead[0]!='\n' || ReadFile(hand, bufstart, count, &num_read, NULL))
2348     {
2349         if (fdinfo->lookahead[0] != '\n')
2350         {
2351             bufstart[0] = fdinfo->lookahead[0];
2352             fdinfo->lookahead[0] = '\n';
2353
2354             if (utf16)
2355             {
2356                 bufstart[1] =  fdinfo->lookahead[1];
2357                 fdinfo->lookahead[1] = '\n';
2358             }
2359
2360             if(count>1+utf16 && ReadFile(hand, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2361                 num_read += 1+utf16;
2362             else
2363                 num_read = 1+utf16;
2364         }
2365
2366         if(utf16 && (num_read&1))
2367         {
2368             /* msvcr90 uses uninitialized value from the buffer in this case */
2369             /* msvcrt ignores additional data */
2370             ERR("got odd number of bytes in UTF16 mode\n");
2371             num_read--;
2372         }
2373
2374         if (count != 0 && num_read == 0)
2375         {
2376             fdinfo->wxflag |= WX_ATEOF;
2377             TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2378         }
2379         else if (fdinfo->wxflag & WX_TEXT)
2380         {
2381             DWORD i, j;
2382
2383             if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2384                 fdinfo->wxflag |= WX_READNL;
2385             else
2386                 fdinfo->wxflag &= ~WX_READNL;
2387
2388             for (i=0, j=0; i<num_read; i+=1+utf16)
2389             {
2390                 /* in text mode, a ctrl-z signals EOF */
2391                 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2392                 {
2393                     fdinfo->wxflag |= WX_ATEOF;
2394                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2395                     break;
2396                 }
2397
2398                 /* in text mode, strip \r if followed by \n */
2399                 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2400                 {
2401                     char lookahead[2];
2402                     DWORD len;
2403
2404                     lookahead[1] = '\n';
2405                     if (ReadFile(hand, lookahead, 1+utf16, &len, NULL) && len)
2406                     {
2407                         if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2408                         {
2409                             bufstart[j++] = '\n';
2410                             if(utf16) bufstart[j++] = 0;
2411                         }
2412                         else
2413                         {
2414                             if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2415                             {
2416                                 bufstart[j++] = '\r';
2417                                 if(utf16) bufstart[j++] = 0;
2418                             }
2419
2420                             if (fdinfo->wxflag & WX_PIPE)
2421                             {
2422                                 fdinfo->lookahead[0] = lookahead[0];
2423                                 fdinfo->lookahead[1] = lookahead[1];
2424                             }
2425                             else
2426                                 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2427                         }
2428                     }
2429                     else
2430                     {
2431                         bufstart[j++] = '\r';
2432                         if(utf16) bufstart[j++] = 0;
2433                     }
2434                 }
2435                 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2436                         || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2437                 {
2438                     bufstart[j++] = bufstart[i];
2439                     if(utf16) bufstart[j++] = bufstart[i+1];
2440                 }
2441             }
2442             num_read = j;
2443         }
2444     }
2445     else
2446     {
2447         if (GetLastError() == ERROR_BROKEN_PIPE)
2448         {
2449             TRACE(":end-of-pipe\n");
2450             fdinfo->wxflag |= WX_ATEOF;
2451             return 0;
2452         }
2453         else
2454         {
2455             TRACE(":failed-last error (%d)\n",GetLastError());
2456             return -1;
2457         }
2458     }
2459
2460     if (count > 4)
2461         TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2462     return num_read;
2463 }
2464
2465 /*********************************************************************
2466  *              _read (MSVCRT.@)
2467  */
2468 int CDECL MSVCRT__read(int fd, void *buf, unsigned int count)
2469 {
2470   int num_read;
2471   num_read = read_i(fd, buf, count);
2472   return num_read;
2473 }
2474
2475 /*********************************************************************
2476  *              _setmode (MSVCRT.@)
2477  */
2478 int CDECL MSVCRT__setmode(int fd,int mode)
2479 {
2480     int ret = msvcrt_get_ioinfo(fd)->wxflag & WX_TEXT ? MSVCRT__O_TEXT : MSVCRT__O_BINARY;
2481     if(ret==MSVCRT__O_TEXT && (msvcrt_get_ioinfo(fd)->exflag & (EF_UTF8|EF_UTF16)))
2482         ret = MSVCRT__O_WTEXT;
2483
2484     if(mode!=MSVCRT__O_TEXT && mode!=MSVCRT__O_BINARY && mode!=MSVCRT__O_WTEXT
2485                 && mode!=MSVCRT__O_U16TEXT && mode!=MSVCRT__O_U8TEXT) {
2486         *MSVCRT__errno() = MSVCRT_EINVAL;
2487         return -1;
2488     }
2489
2490     if(mode == MSVCRT__O_BINARY) {
2491         msvcrt_get_ioinfo(fd)->wxflag &= ~WX_TEXT;
2492         msvcrt_get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
2493         return ret;
2494     }
2495
2496     msvcrt_get_ioinfo(fd)->wxflag |= WX_TEXT;
2497     if(mode == MSVCRT__O_TEXT)
2498         msvcrt_get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
2499     else if(mode == MSVCRT__O_U8TEXT)
2500         msvcrt_get_ioinfo(fd)->exflag = (msvcrt_get_ioinfo(fd)->exflag & ~EF_UTF16) | EF_UTF8;
2501     else
2502         msvcrt_get_ioinfo(fd)->exflag = (msvcrt_get_ioinfo(fd)->exflag & ~EF_UTF8) | EF_UTF16;
2503
2504     return ret;
2505 }
2506
2507 /*********************************************************************
2508  *              _stat64 (MSVCRT.@)
2509  */
2510 int CDECL MSVCRT_stat64(const char* path, struct MSVCRT__stat64 * buf)
2511 {
2512   DWORD dw;
2513   WIN32_FILE_ATTRIBUTE_DATA hfi;
2514   unsigned short mode = ALL_S_IREAD;
2515   int plen;
2516
2517   TRACE(":file (%s) buf(%p)\n",path,buf);
2518
2519   plen = strlen(path);
2520   while (plen && path[plen-1]==' ')
2521     plen--;
2522
2523   if (plen && (path[plen-1]=='\\' || path[plen-1]=='/'))
2524   {
2525     *MSVCRT__errno() = MSVCRT_ENOENT;
2526     return -1;
2527   }
2528
2529   if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
2530   {
2531       TRACE("failed (%d)\n",GetLastError());
2532       *MSVCRT__errno() = MSVCRT_ENOENT;
2533       return -1;
2534   }
2535
2536   memset(buf,0,sizeof(struct MSVCRT__stat64));
2537
2538   /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
2539      Bon 011120: This FIXME seems incorrect
2540                  Also a letter as first char isn't enough to be classified
2541                  as a drive letter
2542   */
2543   if (isalpha(*path)&& (*(path+1)==':'))
2544     buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
2545   else
2546     buf->st_dev = buf->st_rdev = MSVCRT__getdrive() - 1;
2547
2548   /* Dir, or regular file? */
2549   if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2550     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
2551   else
2552   {
2553     mode |= MSVCRT__S_IFREG;
2554     /* executable? */
2555     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
2556     {
2557       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
2558                                  (tolower(path[plen-3]) << 16);
2559       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
2560           mode |= ALL_S_IEXEC;
2561     }
2562   }
2563
2564   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2565     mode |= ALL_S_IWRITE;
2566
2567   buf->st_mode  = mode;
2568   buf->st_nlink = 1;
2569   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
2570   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
2571   buf->st_atime = dw;
2572   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
2573   buf->st_mtime = buf->st_ctime = dw;
2574   TRACE("%d %d 0x%08x%08x %d %d %d\n", buf->st_mode,buf->st_nlink,
2575         (int)(buf->st_size >> 32),(int)buf->st_size,
2576         (int)buf->st_atime,(int)buf->st_mtime,(int)buf->st_ctime);
2577   return 0;
2578 }
2579
2580 /*********************************************************************
2581  *              _stati64 (MSVCRT.@)
2582  */
2583 int CDECL MSVCRT_stati64(const char* path, struct MSVCRT__stati64 * buf)
2584 {
2585   int ret;
2586   struct MSVCRT__stat64 buf64;
2587
2588   ret = MSVCRT_stat64(path, &buf64);
2589   if (!ret)
2590     msvcrt_stat64_to_stati64(&buf64, buf);
2591   return ret;
2592 }
2593
2594 /*********************************************************************
2595  *              _stat (MSVCRT.@)
2596  */
2597 int CDECL MSVCRT_stat(const char* path, struct MSVCRT__stat * buf)
2598 { int ret;
2599   struct MSVCRT__stat64 buf64;
2600
2601   ret = MSVCRT_stat64( path, &buf64);
2602   if (!ret)
2603       msvcrt_stat64_to_stat(&buf64, buf);
2604   return ret;
2605 }
2606
2607 /*********************************************************************
2608  *              _wstat64 (MSVCRT.@)
2609  */
2610 int CDECL MSVCRT__wstat64(const MSVCRT_wchar_t* path, struct MSVCRT__stat64 * buf)
2611 {
2612   DWORD dw;
2613   WIN32_FILE_ATTRIBUTE_DATA hfi;
2614   unsigned short mode = ALL_S_IREAD;
2615   int plen;
2616
2617   TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
2618
2619   plen = strlenW(path);
2620   while (plen && path[plen-1]==' ')
2621     plen--;
2622
2623   if(plen && (path[plen-1]=='\\' || path[plen-1]=='/'))
2624   {
2625     *MSVCRT__errno() = MSVCRT_ENOENT;
2626     return -1;
2627   }
2628
2629   if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
2630   {
2631       TRACE("failed (%d)\n",GetLastError());
2632       *MSVCRT__errno() = MSVCRT_ENOENT;
2633       return -1;
2634   }
2635
2636   memset(buf,0,sizeof(struct MSVCRT__stat64));
2637
2638   /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
2639   if (MSVCRT_iswalpha(*path))
2640     buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
2641   else
2642     buf->st_dev = buf->st_rdev = MSVCRT__getdrive() - 1;
2643
2644   /* Dir, or regular file? */
2645   if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2646     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
2647   else
2648   {
2649     mode |= MSVCRT__S_IFREG;
2650     /* executable? */
2651     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
2652     {
2653       ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
2654                                ((ULONGLONG)tolowerW(path[plen-3]) << 32);
2655       if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
2656         mode |= ALL_S_IEXEC;
2657     }
2658   }
2659
2660   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2661     mode |= ALL_S_IWRITE;
2662
2663   buf->st_mode  = mode;
2664   buf->st_nlink = 1;
2665   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
2666   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
2667   buf->st_atime = dw;
2668   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
2669   buf->st_mtime = buf->st_ctime = dw;
2670   TRACE("%d %d 0x%08x%08x %d %d %d\n", buf->st_mode,buf->st_nlink,
2671         (int)(buf->st_size >> 32),(int)buf->st_size,
2672         (int)buf->st_atime,(int)buf->st_mtime,(int)buf->st_ctime);
2673   return 0;
2674 }
2675
2676 /*********************************************************************
2677  *              _wstati64 (MSVCRT.@)
2678  */
2679 int CDECL MSVCRT__wstati64(const MSVCRT_wchar_t* path, struct MSVCRT__stati64 * buf)
2680 {
2681   int ret;
2682   struct MSVCRT__stat64 buf64;
2683
2684   ret = MSVCRT__wstat64(path, &buf64);
2685   if (!ret)
2686     msvcrt_stat64_to_stati64(&buf64, buf);
2687   return ret;
2688 }
2689
2690 /*********************************************************************
2691  *              _wstat (MSVCRT.@)
2692  */
2693 int CDECL MSVCRT__wstat(const MSVCRT_wchar_t* path, struct MSVCRT__stat * buf)
2694 {
2695   int ret;
2696   struct MSVCRT__stat64 buf64;
2697
2698   ret = MSVCRT__wstat64( path, &buf64 );
2699   if (!ret) msvcrt_stat64_to_stat(&buf64, buf);
2700   return ret;
2701 }
2702
2703 /*********************************************************************
2704  *              _tell (MSVCRT.@)
2705  */
2706 MSVCRT_long CDECL MSVCRT__tell(int fd)
2707 {
2708   return MSVCRT__lseek(fd, 0, SEEK_CUR);
2709 }
2710
2711 /*********************************************************************
2712  *              _telli64 (MSVCRT.@)
2713  */
2714 __int64 CDECL _telli64(int fd)
2715 {
2716   return MSVCRT__lseeki64(fd, 0, SEEK_CUR);
2717 }
2718
2719 /*********************************************************************
2720  *              _tempnam (MSVCRT.@)
2721  */
2722 char * CDECL MSVCRT__tempnam(const char *dir, const char *prefix)
2723 {
2724   char tmpbuf[MAX_PATH];
2725   const char *tmp_dir = MSVCRT_getenv("TMP");
2726
2727   if (tmp_dir) dir = tmp_dir;
2728
2729   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2730   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2731   {
2732     TRACE("got name (%s)\n",tmpbuf);
2733     DeleteFileA(tmpbuf);
2734     return MSVCRT__strdup(tmpbuf);
2735   }
2736   TRACE("failed (%d)\n",GetLastError());
2737   return NULL;
2738 }
2739
2740 /*********************************************************************
2741  *              _wtempnam (MSVCRT.@)
2742  */
2743 MSVCRT_wchar_t * CDECL MSVCRT__wtempnam(const MSVCRT_wchar_t *dir, const MSVCRT_wchar_t *prefix)
2744 {
2745   static const MSVCRT_wchar_t tmpW[] = {'T','M','P',0};
2746   MSVCRT_wchar_t tmpbuf[MAX_PATH];
2747   const MSVCRT_wchar_t *tmp_dir = MSVCRT__wgetenv(tmpW);
2748
2749   if (tmp_dir) dir = tmp_dir;
2750
2751   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2752   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2753   {
2754     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2755     DeleteFileW(tmpbuf);
2756     return MSVCRT__wcsdup(tmpbuf);
2757   }
2758   TRACE("failed (%d)\n",GetLastError());
2759   return NULL;
2760 }
2761
2762 /*********************************************************************
2763  *              _umask (MSVCRT.@)
2764  */
2765 int CDECL MSVCRT__umask(int umask)
2766 {
2767   int old_umask = MSVCRT_umask;
2768   TRACE("(%d)\n",umask);
2769   MSVCRT_umask = umask;
2770   return old_umask;
2771 }
2772
2773 /*********************************************************************
2774  *              _utime64 (MSVCRT.@)
2775  */
2776 int CDECL _utime64(const char* path, struct MSVCRT___utimbuf64 *t)
2777 {
2778   int fd = MSVCRT__open(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2779
2780   if (fd > 0)
2781   {
2782     int retVal = _futime64(fd, t);
2783     MSVCRT__close(fd);
2784     return retVal;
2785   }
2786   return -1;
2787 }
2788
2789 /*********************************************************************
2790  *              _utime32 (MSVCRT.@)
2791  */
2792 int CDECL _utime32(const char* path, struct MSVCRT___utimbuf32 *t)
2793 {
2794     if (t)
2795     {
2796         struct MSVCRT___utimbuf64 t64;
2797         t64.actime = t->actime;
2798         t64.modtime = t->modtime;
2799         return _utime64( path, &t64 );
2800     }
2801     else
2802         return _utime64( path, NULL );
2803 }
2804
2805 /*********************************************************************
2806  *              _utime (MSVCRT.@)
2807  */
2808 #ifdef _WIN64
2809 int CDECL _utime(const char* path, struct MSVCRT___utimbuf64 *t)
2810 {
2811     return _utime64( path, t );
2812 }
2813 #else
2814 int CDECL _utime(const char* path, struct MSVCRT___utimbuf32 *t)
2815 {
2816     return _utime32( path, t );
2817 }
2818 #endif
2819
2820 /*********************************************************************
2821  *              _wutime64 (MSVCRT.@)
2822  */
2823 int CDECL _wutime64(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf64 *t)
2824 {
2825   int fd = MSVCRT__wopen(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2826
2827   if (fd > 0)
2828   {
2829     int retVal = _futime64(fd, t);
2830     MSVCRT__close(fd);
2831     return retVal;
2832   }
2833   return -1;
2834 }
2835
2836 /*********************************************************************
2837  *              _wutime32 (MSVCRT.@)
2838  */
2839 int CDECL _wutime32(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf32 *t)
2840 {
2841     if (t)
2842     {
2843         struct MSVCRT___utimbuf64 t64;
2844         t64.actime = t->actime;
2845         t64.modtime = t->modtime;
2846         return _wutime64( path, &t64 );
2847     }
2848     else
2849         return _wutime64( path, NULL );
2850 }
2851
2852 /*********************************************************************
2853  *              _wutime (MSVCRT.@)
2854  */
2855 #ifdef _WIN64
2856 int CDECL _wutime(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf64 *t)
2857 {
2858     return _wutime64( path, t );
2859 }
2860 #else
2861 int CDECL _wutime(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf32 *t)
2862 {
2863     return _wutime32( path, t );
2864 }
2865 #endif
2866
2867 /*********************************************************************
2868  *              _write (MSVCRT.@)
2869  */
2870 int CDECL MSVCRT__write(int fd, const void* buf, unsigned int count)
2871 {
2872     DWORD num_written;
2873     ioinfo *info = msvcrt_get_ioinfo(fd);
2874     HANDLE hand = info->handle;
2875
2876     /* Don't trace small writes, it gets *very* annoying */
2877 #if 0
2878     if (count > 32)
2879         TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2880 #endif
2881     if (hand == INVALID_HANDLE_VALUE)
2882     {
2883         *MSVCRT__errno() = MSVCRT_EBADF;
2884         return -1;
2885     }
2886
2887     if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2888     {
2889         *MSVCRT__errno() = MSVCRT_EINVAL;
2890         return -1;
2891     }
2892
2893     /* If appending, go to EOF */
2894     if (info->wxflag & WX_APPEND)
2895         MSVCRT__lseek(fd, 0, FILE_END);
2896
2897     if (!(info->wxflag & WX_TEXT))
2898     {
2899         if (WriteFile(hand, buf, count, &num_written, NULL)
2900                 &&  (num_written == count))
2901             return num_written;
2902         TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2903                 hand, GetLastError());
2904         *MSVCRT__errno() = MSVCRT_ENOSPC;
2905     }
2906     else
2907     {
2908         unsigned int i, j, nr_lf, size;
2909         char *p = NULL;
2910         const char *q;
2911         const char *s = buf, *buf_start = buf;
2912
2913         if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2914         {
2915             /* find number of \n */
2916             for (nr_lf=0, i=0; i<count; i++)
2917                 if (s[i] == '\n')
2918                     nr_lf++;
2919             if (nr_lf)
2920             {
2921                 size = count+nr_lf;
2922                 if ((q = p = MSVCRT_malloc(size)))
2923                 {
2924                     for (s = buf, i = 0, j = 0; i < count; i++)
2925                     {
2926                         if (s[i] == '\n')
2927                             p[j++] = '\r';
2928                         p[j++] = s[i];
2929                     }
2930                 }
2931                 else
2932                 {
2933                     FIXME("Malloc failed\n");
2934                     nr_lf = 0;
2935                     size = count;
2936                     q = buf;
2937                 }
2938             }
2939             else
2940             {
2941                 size = count;
2942                 q = buf;
2943             }
2944         }
2945         else if (info->exflag & EF_UTF16)
2946         {
2947             for (nr_lf=0, i=0; i<count; i+=2)
2948                 if (s[i]=='\n' && s[i+1]==0)
2949                     nr_lf += 2;
2950             if (nr_lf)
2951             {
2952                 size = count+nr_lf;
2953                 if ((q = p = MSVCRT_malloc(size)))
2954                 {
2955                     for (s=buf, i=0, j=0; i<count; i++)
2956                     {
2957                         if (s[i]=='\n' && s[i+1]==0)
2958                         {
2959                             p[j++] = '\r';
2960                             p[j++] = 0;
2961                         }
2962                         p[j++] = s[i++];
2963                         p[j++] = s[i];
2964                     }
2965                 }
2966                 else
2967                 {
2968                     FIXME("Malloc failed\n");
2969                     nr_lf = 0;
2970                     size = count;
2971                     q = buf;
2972                 }
2973             }
2974             else
2975             {
2976                 size = count;
2977                 q = buf;
2978             }
2979         }
2980         else
2981         {
2982             DWORD conv_len;
2983
2984             for(nr_lf=0, i=0; i<count; i+=2)
2985                 if (s[i]=='\n' && s[i+1]==0)
2986                     nr_lf++;
2987
2988             conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2989             if(!conv_len) {
2990                 msvcrt_set_errno(GetLastError());
2991                 MSVCRT_free(p);
2992                 return -1;
2993             }
2994
2995             size = conv_len+nr_lf;
2996             if((p = MSVCRT_malloc(count+nr_lf*2+size)))
2997             {
2998                 for (s=buf, i=0, j=0; i<count; i++)
2999                 {
3000                     if (s[i]=='\n' && s[i+1]==0)
3001                     {
3002                         p[j++] = '\r';
3003                         p[j++] = 0;
3004                     }
3005                     p[j++] = s[i++];
3006                     p[j++] = s[i];
3007                 }
3008                 q = p+count+nr_lf*2;
3009                 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
3010                         p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
3011             }
3012             else
3013             {
3014                 FIXME("Malloc failed\n");
3015                 nr_lf = 0;
3016                 size = count;
3017                 q = buf;
3018             }
3019         }
3020
3021         if (!WriteFile(hand, q, size, &num_written, NULL))
3022             num_written = -1;
3023         if(p)
3024             MSVCRT_free(p);
3025         if (num_written != size)
3026         {
3027             TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
3028                     fd, hand, GetLastError(), num_written);
3029             *MSVCRT__errno() = MSVCRT_ENOSPC;
3030             return s - buf_start;
3031         }
3032         return count;
3033     }
3034
3035     return -1;
3036 }
3037
3038 /*********************************************************************
3039  *              _putw (MSVCRT.@)
3040  */
3041 int CDECL MSVCRT__putw(int val, MSVCRT_FILE* file)
3042 {
3043   int len;
3044
3045   MSVCRT__lock_file(file);
3046   len = MSVCRT__write(file->_file, &val, sizeof(val));
3047   if (len == sizeof(val)) {
3048     MSVCRT__unlock_file(file);
3049     return val;
3050   }
3051
3052   file->_flag |= MSVCRT__IOERR;
3053   MSVCRT__unlock_file(file);
3054   return MSVCRT_EOF;
3055 }
3056
3057 /*********************************************************************
3058  *              fclose (MSVCRT.@)
3059  */
3060 int CDECL MSVCRT_fclose(MSVCRT_FILE* file)
3061 {
3062   int r, flag;
3063
3064   MSVCRT__lock_file(file);
3065   flag = file->_flag;
3066   MSVCRT_free(file->_tmpfname);
3067   file->_tmpfname = NULL;
3068   /* flush stdio buffers */
3069   if(file->_flag & MSVCRT__IOWRT)
3070       MSVCRT_fflush(file);
3071   if(file->_flag & MSVCRT__IOMYBUF)
3072       MSVCRT_free(file->_base);
3073
3074   r=MSVCRT__close(file->_file);
3075
3076   file->_flag = 0;
3077   MSVCRT__unlock_file(file);
3078
3079   return ((r == -1) || (flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
3080 }
3081
3082 /*********************************************************************
3083  *              feof (MSVCRT.@)
3084  */
3085 int CDECL MSVCRT_feof(MSVCRT_FILE* file)
3086 {
3087     return file->_flag & MSVCRT__IOEOF;
3088 }
3089
3090 /*********************************************************************
3091  *              ferror (MSVCRT.@)
3092  */
3093 int CDECL MSVCRT_ferror(MSVCRT_FILE* file)
3094 {
3095     return file->_flag & MSVCRT__IOERR;
3096 }
3097
3098 /*********************************************************************
3099  *              _filbuf (MSVCRT.@)
3100  */
3101 int CDECL MSVCRT__filbuf(MSVCRT_FILE* file)
3102 {
3103     unsigned char c;
3104     MSVCRT__lock_file(file);
3105
3106     /* Allocate buffer if needed */
3107     if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF))
3108         msvcrt_alloc_buffer(file);
3109
3110     if(!(file->_flag & MSVCRT__IOREAD)) {
3111         if(file->_flag & MSVCRT__IORW)
3112             file->_flag |= MSVCRT__IOREAD;
3113         else {
3114             MSVCRT__unlock_file(file);
3115             return MSVCRT_EOF;
3116         }
3117     }
3118
3119     if(file->_flag & MSVCRT__IONBF) {
3120         int r;
3121         if ((r = read_i(file->_file,&c,1)) != 1) {
3122             file->_flag |= (r == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
3123             MSVCRT__unlock_file(file);
3124             return MSVCRT_EOF;
3125         }
3126
3127         MSVCRT__unlock_file(file);
3128         return c;
3129     } else {
3130         file->_cnt = read_i(file->_file, file->_base, file->_bufsiz);
3131         if(file->_cnt<=0) {
3132             file->_flag |= (file->_cnt == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
3133             file->_cnt = 0;
3134             MSVCRT__unlock_file(file);
3135             return MSVCRT_EOF;
3136         }
3137
3138         file->_cnt--;
3139         file->_ptr = file->_base+1;
3140         c = *(unsigned char *)file->_base;
3141         MSVCRT__unlock_file(file);
3142         return c;
3143     }
3144 }
3145
3146 /*********************************************************************
3147  *              fgetc (MSVCRT.@)
3148  */
3149 int CDECL MSVCRT_fgetc(MSVCRT_FILE* file)
3150 {
3151   unsigned char *i;
3152   unsigned int j;
3153
3154   MSVCRT__lock_file(file);
3155   if (file->_cnt>0) {
3156     file->_cnt--;
3157     i = (unsigned char *)file->_ptr++;
3158     j = *i;
3159   } else
3160     j = MSVCRT__filbuf(file);
3161
3162   MSVCRT__unlock_file(file);
3163   return j;
3164 }
3165
3166 /*********************************************************************
3167  *              _fgetchar (MSVCRT.@)
3168  */
3169 int CDECL MSVCRT__fgetchar(void)
3170 {
3171   return MSVCRT_fgetc(MSVCRT_stdin);
3172 }
3173
3174 /*********************************************************************
3175  *              fgets (MSVCRT.@)
3176  */
3177 char * CDECL MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
3178 {
3179   int    cc = MSVCRT_EOF;
3180   char * buf_start = s;
3181
3182   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3183         file,file->_file,s,size);
3184
3185   MSVCRT__lock_file(file);
3186
3187   while ((size >1) && (cc = MSVCRT_fgetc(file)) != MSVCRT_EOF && cc != '\n')
3188     {
3189       *s++ = (char)cc;
3190       size --;
3191     }
3192   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
3193   {
3194     TRACE(":nothing read\n");
3195     MSVCRT__unlock_file(file);
3196     return NULL;
3197   }
3198   if ((cc != MSVCRT_EOF) && (size > 1))
3199     *s++ = cc;
3200   *s = '\0';
3201   TRACE(":got %s\n", debugstr_a(buf_start));
3202   MSVCRT__unlock_file(file);
3203   return buf_start;
3204 }
3205
3206 /*********************************************************************
3207  *              fgetwc (MSVCRT.@)
3208  *
3209  * In MSVCRT__O_TEXT mode, multibyte characters are read from the file, dropping
3210  * the CR from CR/LF combinations
3211  */
3212 MSVCRT_wint_t CDECL MSVCRT_fgetwc(MSVCRT_FILE* file)
3213 {
3214   int c;
3215
3216   MSVCRT__lock_file(file);
3217   if (!(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT))
3218     {
3219       MSVCRT_wchar_t wc;
3220       unsigned int i;
3221       int j;
3222       char *chp, *wcp;
3223       wcp = (char *)&wc;
3224       for(i=0; i<sizeof(wc); i++)
3225       {
3226         if (file->_cnt>0) 
3227         {
3228           file->_cnt--;
3229           chp = file->_ptr++;
3230           wcp[i] = *chp;
3231         } 
3232         else
3233         {
3234           j = MSVCRT__filbuf(file);
3235           if(file->_cnt<=0)
3236           {
3237             file->_flag |= (file->_cnt == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
3238             file->_cnt = 0;
3239
3240             MSVCRT__unlock_file(file);
3241             return MSVCRT_WEOF;
3242           }
3243           wcp[i] = j;
3244         }
3245       }
3246
3247       MSVCRT__unlock_file(file);
3248       return wc;
3249     }
3250     
3251   c = MSVCRT_fgetc(file);
3252   if ((get_locinfo()->mb_cur_max > 1) && MSVCRT_isleadbyte(c))
3253     {
3254       FIXME("Treat Multibyte characters\n");
3255     }
3256
3257   MSVCRT__unlock_file(file);
3258   if (c == MSVCRT_EOF)
3259     return MSVCRT_WEOF;
3260   else
3261     return (MSVCRT_wint_t)c;
3262 }
3263
3264 /*********************************************************************
3265  *              _getw (MSVCRT.@)
3266  */
3267 int CDECL MSVCRT__getw(MSVCRT_FILE* file)
3268 {
3269   char *ch;
3270   int i, k;
3271   unsigned int j;
3272   ch = (char *)&i;
3273
3274   MSVCRT__lock_file(file);
3275   for (j=0; j<sizeof(int); j++) {
3276     k = MSVCRT_fgetc(file);
3277     if (k == MSVCRT_EOF) {
3278       file->_flag |= MSVCRT__IOEOF;
3279       MSVCRT__unlock_file(file);
3280       return EOF;
3281     }
3282     ch[j] = k;
3283   }
3284
3285   MSVCRT__unlock_file(file);
3286   return i;
3287 }
3288
3289 /*********************************************************************
3290  *              getwc (MSVCRT.@)
3291  */
3292 MSVCRT_wint_t CDECL MSVCRT_getwc(MSVCRT_FILE* file)
3293 {
3294   return MSVCRT_fgetwc(file);
3295 }
3296
3297 /*********************************************************************
3298  *              _fgetwchar (MSVCRT.@)
3299  */
3300 MSVCRT_wint_t CDECL MSVCRT__fgetwchar(void)
3301 {
3302   return MSVCRT_fgetwc(MSVCRT_stdin);
3303 }
3304
3305 /*********************************************************************
3306  *              getwchar (MSVCRT.@)
3307  */
3308 MSVCRT_wint_t CDECL MSVCRT_getwchar(void)
3309 {
3310   return MSVCRT__fgetwchar();
3311 }
3312
3313 /*********************************************************************
3314  *              fgetws (MSVCRT.@)
3315  */
3316 MSVCRT_wchar_t * CDECL MSVCRT_fgetws(MSVCRT_wchar_t *s, int size, MSVCRT_FILE* file)
3317 {
3318   int    cc = MSVCRT_WEOF;
3319   MSVCRT_wchar_t * buf_start = s;
3320
3321   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3322         file,file->_file,s,size);
3323
3324   MSVCRT__lock_file(file);
3325
3326   while ((size >1) && (cc = MSVCRT_fgetwc(file)) != MSVCRT_WEOF && cc != '\n')
3327     {
3328       *s++ = (char)cc;
3329       size --;
3330     }
3331   if ((cc == MSVCRT_WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3332   {
3333     TRACE(":nothing read\n");
3334     MSVCRT__unlock_file(file);
3335     return NULL;
3336   }
3337   if ((cc != MSVCRT_WEOF) && (size > 1))
3338     *s++ = cc;
3339   *s = 0;
3340   TRACE(":got %s\n", debugstr_w(buf_start));
3341   MSVCRT__unlock_file(file);
3342   return buf_start;
3343 }
3344
3345 /*********************************************************************
3346  *              fwrite (MSVCRT.@)
3347  */
3348 MSVCRT_size_t CDECL MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
3349 {
3350     MSVCRT_size_t wrcnt=size * nmemb;
3351     int written = 0;
3352     if (size == 0)
3353         return 0;
3354
3355     MSVCRT__lock_file(file);
3356     if(file->_cnt) {
3357         int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3358         memcpy(file->_ptr, ptr, pcnt);
3359         file->_cnt -= pcnt;
3360         file->_ptr += pcnt;
3361         written = pcnt;
3362         wrcnt -= pcnt;
3363         ptr = (const char*)ptr + pcnt;
3364     } else if(!(file->_flag & MSVCRT__IOWRT)) {
3365         if(file->_flag & MSVCRT__IORW) {
3366             file->_flag |= MSVCRT__IOWRT;
3367         } else {
3368             MSVCRT__unlock_file(file);
3369             return 0;
3370         }
3371     }
3372     if(wrcnt) {
3373         int res;
3374
3375         if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF))
3376             msvcrt_alloc_buffer(file);
3377
3378         /* Flush buffer */
3379         res=msvcrt_flush_buffer(file);
3380         if(!res) {
3381             int pwritten = MSVCRT__write(file->_file, ptr, wrcnt);
3382             if (pwritten <= 0)
3383             {
3384                 file->_flag |= MSVCRT__IOERR;
3385                 pwritten=0;
3386             }
3387             written += pwritten;
3388         }
3389     }
3390
3391     MSVCRT__unlock_file(file);
3392     return written / size;
3393 }
3394
3395 /*********************************************************************
3396  *              fputwc (MSVCRT.@)
3397  */
3398 MSVCRT_wint_t CDECL MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
3399 {
3400     MSVCRT_wchar_t mwc=wc;
3401     ioinfo *fdinfo;
3402     MSVCRT_wint_t ret;
3403
3404     MSVCRT__lock_file(file);
3405     fdinfo = msvcrt_get_ioinfo(file->_file);
3406
3407     if((fdinfo->wxflag&WX_TEXT) && !(fdinfo->exflag&(EF_UTF8|EF_UTF16))) {
3408         char buf[MSVCRT_MB_LEN_MAX];
3409         int char_len;
3410
3411         char_len = MSVCRT_wctomb(buf, mwc);
3412         if(char_len!=-1 && MSVCRT_fwrite(buf, char_len, 1, file)==1)
3413             ret = wc;
3414         else
3415             ret = MSVCRT_WEOF;
3416     }else if(MSVCRT_fwrite(&mwc, sizeof(mwc), 1, file) == 1) {
3417         ret = wc;
3418     }else {
3419         ret = MSVCRT_WEOF;
3420     }
3421
3422     MSVCRT__unlock_file(file);
3423     return ret;
3424 }
3425
3426 /*********************************************************************
3427  *              _fputwchar (MSVCRT.@)
3428  */
3429 MSVCRT_wint_t CDECL MSVCRT__fputwchar(MSVCRT_wint_t wc)
3430 {
3431   return MSVCRT_fputwc(wc, MSVCRT_stdout);
3432 }
3433
3434 /*********************************************************************
3435  *              _wfsopen (MSVCRT.@)
3436  */
3437 MSVCRT_FILE * CDECL MSVCRT__wfsopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, int share)
3438 {
3439   MSVCRT_FILE* file;
3440   int open_flags, stream_flags, fd;
3441
3442   TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3443
3444   /* map mode string to open() flags. "man fopen" for possibilities. */
3445   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3446       return NULL;
3447
3448   LOCK_FILES();
3449   fd = MSVCRT__wsopen(path, open_flags, share, MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
3450   if (fd < 0)
3451     file = NULL;
3452   else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3453    != -1)
3454     TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3455   else if (file)
3456   {
3457     file->_flag = 0;
3458     file = NULL;
3459   }
3460
3461   TRACE(":got (%p)\n",file);
3462   if (fd >= 0 && !file)
3463     MSVCRT__close(fd);
3464   UNLOCK_FILES();
3465   return file;
3466 }
3467
3468 /*********************************************************************
3469  *              _fsopen (MSVCRT.@)
3470  */
3471 MSVCRT_FILE * CDECL MSVCRT__fsopen(const char *path, const char *mode, int share)
3472 {
3473     MSVCRT_FILE *ret;
3474     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
3475
3476     if (path && !(pathW = msvcrt_wstrdupa(path))) {
3477         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
3478         *MSVCRT__errno() = MSVCRT_EINVAL;
3479         return NULL;
3480     }
3481     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3482     {
3483         MSVCRT_free(pathW);
3484         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
3485         *MSVCRT__errno() = MSVCRT_EINVAL;
3486         return NULL;
3487     }
3488
3489     ret = MSVCRT__wfsopen(pathW, modeW, share);
3490
3491     MSVCRT_free(pathW);
3492     MSVCRT_free(modeW);
3493     return ret;
3494 }
3495
3496 /*********************************************************************
3497  *              fopen (MSVCRT.@)
3498  */
3499 MSVCRT_FILE * CDECL MSVCRT_fopen(const char *path, const char *mode)
3500 {
3501     return MSVCRT__fsopen( path, mode, MSVCRT__SH_DENYNO );
3502 }
3503
3504 /*********************************************************************
3505  *              fopen_s (MSVCRT.@)
3506  */
3507 int CDECL MSVCRT_fopen_s(MSVCRT_FILE** pFile,
3508         const char *filename, const char *mode)
3509 {
3510     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3511     if (!MSVCRT_CHECK_PMT(filename != NULL)) return MSVCRT_EINVAL;
3512     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3513
3514     *pFile = MSVCRT_fopen(filename, mode);
3515
3516     if(!*pFile)
3517         return *MSVCRT__errno();
3518     return 0;
3519 }
3520
3521 /*********************************************************************
3522  *              _wfopen (MSVCRT.@)
3523  */
3524 MSVCRT_FILE * CDECL MSVCRT__wfopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode)
3525 {
3526     return MSVCRT__wfsopen( path, mode, MSVCRT__SH_DENYNO );
3527 }
3528
3529 /*********************************************************************
3530  *              _wfopen_s (MSVCRT.@)
3531  */
3532 int CDECL MSVCRT__wfopen_s(MSVCRT_FILE** pFile, const MSVCRT_wchar_t *filename,
3533         const MSVCRT_wchar_t *mode)
3534 {
3535     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3536     if (!MSVCRT_CHECK_PMT(filename != NULL)) return MSVCRT_EINVAL;
3537     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3538
3539     *pFile = MSVCRT__wfopen(filename, mode);
3540
3541     if(!*pFile)
3542         return *MSVCRT__errno();
3543     return 0;
3544 }
3545
3546 /*********************************************************************
3547  *              _flsbuf (MSVCRT.@)
3548  */
3549 int CDECL MSVCRT__flsbuf(int c, MSVCRT_FILE* file)
3550 {
3551     /* Flush output buffer */
3552     if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
3553         msvcrt_alloc_buffer(file);
3554     }
3555     if(!(file->_flag & MSVCRT__IOWRT)) {
3556         if(file->_flag & MSVCRT__IORW)
3557             file->_flag |= MSVCRT__IOWRT;
3558         else
3559             return MSVCRT_EOF;
3560     }
3561     if(file->_bufsiz) {
3562         int res = 0;
3563
3564         if(file->_cnt <= 0)
3565             res = msvcrt_flush_buffer(file);
3566         if(!res) {
3567             *file->_ptr++ = c;
3568             file->_cnt--;
3569             res = msvcrt_flush_buffer(file);
3570         }
3571
3572         return res ? res : c&0xff;
3573     } else {
3574         unsigned char cc=c;
3575         int len;
3576         /* set _cnt to 0 for unbuffered FILEs */
3577         file->_cnt = 0;
3578         len = MSVCRT__write(file->_file, &cc, 1);
3579         if (len == 1)
3580             return c & 0xff;
3581         file->_flag |= MSVCRT__IOERR;
3582         return MSVCRT_EOF;
3583     }
3584 }
3585
3586 /*********************************************************************
3587  *              fputc (MSVCRT.@)
3588  */
3589 int CDECL MSVCRT_fputc(int c, MSVCRT_FILE* file)
3590 {
3591   int res;
3592
3593   MSVCRT__lock_file(file);
3594   if(file->_cnt>0) {
3595     *file->_ptr++=c;
3596     file->_cnt--;
3597     if (c == '\n')
3598     {
3599       res = msvcrt_flush_buffer(file);
3600       MSVCRT__unlock_file(file);
3601       return res ? res : c;
3602     }
3603     else {
3604       MSVCRT__unlock_file(file);
3605       return c & 0xff;
3606     }
3607   } else {
3608     res = MSVCRT__flsbuf(c, file);
3609     MSVCRT__unlock_file(file);
3610     return res;
3611   }
3612 }
3613
3614 /*********************************************************************
3615  *              _fputchar (MSVCRT.@)
3616  */
3617 int CDECL MSVCRT__fputchar(int c)
3618 {
3619   return MSVCRT_fputc(c, MSVCRT_stdout);
3620 }
3621
3622 /*********************************************************************
3623  *              fread (MSVCRT.@)
3624  */
3625 MSVCRT_size_t CDECL MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
3626 {
3627   MSVCRT_size_t rcnt=size * nmemb;
3628   MSVCRT_size_t read=0;
3629   int pread=0;
3630
3631   if(!rcnt)
3632         return 0;
3633
3634   MSVCRT__lock_file(file);
3635
3636   /* first buffered data */
3637   if(file->_cnt>0) {
3638         int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
3639         memcpy(ptr, file->_ptr, pcnt);
3640         file->_cnt -= pcnt;
3641         file->_ptr += pcnt;
3642         read += pcnt ;
3643         rcnt -= pcnt ;
3644         ptr = (char*)ptr + pcnt;
3645   } else if(!(file->_flag & MSVCRT__IOREAD )) {
3646         if(file->_flag & MSVCRT__IORW) {
3647                 file->_flag |= MSVCRT__IOREAD;
3648         } else {
3649         MSVCRT__unlock_file(file);
3650         return 0;
3651     }
3652   }
3653   while(rcnt>0)
3654   {
3655     int i;
3656     if (!file->_cnt && rcnt<MSVCRT_BUFSIZ && !(file->_flag & MSVCRT__IONBF)
3657             && (file->_bufsiz != 0 || msvcrt_alloc_buffer(file))) {
3658       file->_cnt = MSVCRT__read(file->_file, file->_base, file->_bufsiz);
3659       file->_ptr = file->_base;
3660       i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
3661       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
3662       if (i > 0 && i < file->_cnt) {
3663         msvcrt_get_ioinfo(file->_file)->wxflag &= ~WX_ATEOF;
3664         file->_flag &= ~MSVCRT__IOEOF;
3665       }
3666       if (i > 0) {
3667         memcpy(ptr, file->_ptr, i);
3668         file->_cnt -= i;
3669         file->_ptr += i;
3670       }
3671     } else if (rcnt > UINT_MAX) {
3672       i = MSVCRT__read(file->_file, ptr, UINT_MAX);
3673     } else if (rcnt < MSVCRT_BUFSIZ) {
3674       i = MSVCRT__read(file->_file, ptr, rcnt);
3675     } else {
3676       i = MSVCRT__read(file->_file, ptr, rcnt - MSVCRT_BUFSIZ/2);
3677     }
3678     pread += i;
3679     rcnt -= i;
3680     ptr = (char *)ptr+i;
3681     /* expose feof condition in the flags
3682      * MFC tests file->_flag for feof, and doesn't call feof())
3683      */
3684     if (msvcrt_get_ioinfo(file->_file)->wxflag & WX_ATEOF)
3685         file->_flag |= MSVCRT__IOEOF;
3686     else if (i == -1)
3687     {
3688         file->_flag |= MSVCRT__IOERR;
3689         pread = 0;
3690         rcnt = 0;
3691     }
3692     if (i < 1) break;
3693   }
3694   read+=pread;
3695   MSVCRT__unlock_file(file);
3696   return read / size;
3697 }
3698
3699 /*********************************************************************
3700  *              _wfreopen (MSVCRT.@)
3701  *
3702  */
3703 MSVCRT_FILE* CDECL MSVCRT__wfreopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, MSVCRT_FILE* file)
3704 {
3705   int fd;
3706
3707   TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file->_file);
3708
3709   LOCK_FILES();
3710   if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
3711     file = NULL;
3712   else
3713   {
3714     MSVCRT_fclose(file);
3715     file = MSVCRT__wfsopen(path, mode, MSVCRT__SH_DENYNO);
3716   }
3717   UNLOCK_FILES();
3718   return file;
3719 }
3720
3721 /*********************************************************************
3722  *      _wfreopen_s (MSVCRT.@)
3723  */
3724 int CDECL MSVCRT__wfreopen_s(MSVCRT_FILE** pFile,
3725         const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, MSVCRT_FILE* file)
3726 {
3727     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3728     if (!MSVCRT_CHECK_PMT(path != NULL)) return MSVCRT_EINVAL;
3729     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3730     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
3731
3732     *pFile = MSVCRT__wfreopen(path, mode, file);
3733
3734     if(!*pFile)
3735         return *MSVCRT__errno();
3736     return 0;
3737 }
3738
3739 /*********************************************************************
3740  *      freopen (MSVCRT.@)
3741  *
3742  */
3743 MSVCRT_FILE* CDECL MSVCRT_freopen(const char *path, const char *mode, MSVCRT_FILE* file)
3744 {
3745     MSVCRT_FILE *ret;
3746     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
3747
3748     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3749     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3750     {
3751         MSVCRT_free(pathW);
3752         return NULL;
3753     }
3754
3755     ret = MSVCRT__wfreopen(pathW, modeW, file);
3756
3757     MSVCRT_free(pathW);
3758     MSVCRT_free(modeW);
3759     return ret;
3760 }
3761
3762 /*********************************************************************
3763  *      freopen_s (MSVCRT.@)
3764  */
3765 int CDECL MSVCRT_freopen_s(MSVCRT_FILE** pFile,
3766         const char *path, const char *mode, MSVCRT_FILE* file)
3767 {
3768     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3769     if (!MSVCRT_CHECK_PMT(path != NULL)) return MSVCRT_EINVAL;
3770     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3771     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
3772
3773     *pFile = MSVCRT_freopen(path, mode, file);
3774
3775     if(!*pFile)
3776         return *MSVCRT__errno();
3777     return 0;
3778 }
3779
3780 /*********************************************************************
3781  *              fsetpos (MSVCRT.@)
3782  */
3783 int CDECL MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
3784 {
3785   int ret;
3786
3787   MSVCRT__lock_file(file);
3788   /* Note that all this has been lifted 'as is' from fseek */
3789   if(file->_flag & MSVCRT__IOWRT)
3790         msvcrt_flush_buffer(file);
3791
3792   /* Discard buffered input */
3793   file->_cnt = 0;
3794   file->_ptr = file->_base;
3795   
3796   /* Reset direction of i/o */
3797   if(file->_flag & MSVCRT__IORW) {
3798         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
3799   }
3800
3801   ret = (MSVCRT__lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3802   MSVCRT__unlock_file(file);
3803   return ret;
3804 }
3805
3806 /*********************************************************************
3807  *              _ftelli64 (MSVCRT.@)
3808  */
3809 __int64 CDECL MSVCRT__ftelli64(MSVCRT_FILE* file)
3810 {
3811     __int64 pos;
3812
3813     MSVCRT__lock_file(file);
3814     pos = _telli64(file->_file);
3815     if(pos == -1) {
3816         MSVCRT__unlock_file(file);
3817         return -1;
3818     }
3819     if(file->_bufsiz)  {
3820         if(file->_flag & MSVCRT__IOWRT) {
3821             pos += file->_ptr - file->_base;
3822
3823             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3824                 char *p;
3825
3826                 for(p=file->_base; p<file->_ptr; p++)
3827                     if(*p == '\n')
3828                         pos++;
3829             }
3830         } else if(!file->_cnt) { /* nothing to do */
3831         } else if(MSVCRT__lseeki64(file->_file, 0, SEEK_END)==pos) {
3832             int i;
3833
3834             pos -= file->_cnt;
3835             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3836                 for(i=0; i<file->_cnt; i++)
3837                     if(file->_ptr[i] == '\n')
3838                         pos--;
3839             }
3840         } else {
3841             char *p;
3842
3843             if(MSVCRT__lseeki64(file->_file, pos, SEEK_SET) != pos) {
3844                 MSVCRT__unlock_file(file);
3845                 return -1;
3846             }
3847
3848             pos -= file->_bufsiz;
3849             pos += file->_ptr - file->_base;
3850
3851             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3852                 if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_READNL)
3853                     pos--;
3854
3855                 for(p=file->_base; p<file->_ptr; p++)
3856                     if(*p == '\n')
3857                         pos++;
3858             }
3859         }
3860     }
3861
3862     MSVCRT__unlock_file(file);
3863     return pos;
3864 }
3865
3866 /*********************************************************************
3867  *              ftell (MSVCRT.@)
3868  */
3869 LONG CDECL MSVCRT_ftell(MSVCRT_FILE* file)
3870 {
3871   return MSVCRT__ftelli64(file);
3872 }
3873
3874 /*********************************************************************
3875  *              fgetpos (MSVCRT.@)
3876  */
3877 int CDECL MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
3878 {
3879     *pos = MSVCRT__ftelli64(file);
3880     if(*pos == -1)
3881         return -1;
3882     return 0;
3883 }
3884
3885 /*********************************************************************
3886  *              fputs (MSVCRT.@)
3887  */
3888 int CDECL MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
3889 {
3890     MSVCRT_size_t len = strlen(s);
3891     int ret;
3892
3893     MSVCRT__lock_file(file);
3894     ret = MSVCRT_fwrite(s, sizeof(*s), len, file) == len ? 0 : MSVCRT_EOF;
3895     MSVCRT__unlock_file(file);
3896     return ret;
3897 }
3898
3899 /*********************************************************************
3900  *              fputws (MSVCRT.@)
3901  */
3902 int CDECL MSVCRT_fputws(const MSVCRT_wchar_t *s, MSVCRT_FILE* file)
3903 {
3904     MSVCRT_size_t i, len = strlenW(s);
3905     BOOL tmp_buf;
3906     int ret;
3907
3908     MSVCRT__lock_file(file);
3909     if (!(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
3910         ret = MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
3911         MSVCRT__unlock_file(file);
3912         return ret;
3913     }
3914
3915     tmp_buf = add_std_buffer(file);
3916     for (i=0; i<len; i++) {
3917         if(MSVCRT_fputwc(s[i], file) == MSVCRT_WEOF) {
3918             if(tmp_buf) remove_std_buffer(file);
3919             MSVCRT__unlock_file(file);
3920             return MSVCRT_WEOF;
3921         }
3922     }
3923
3924     if(tmp_buf) remove_std_buffer(file);
3925     MSVCRT__unlock_file(file);
3926     return 0;
3927 }
3928
3929 /*********************************************************************
3930  *              getchar (MSVCRT.@)
3931  */
3932 int CDECL MSVCRT_getchar(void)
3933 {
3934   return MSVCRT_fgetc(MSVCRT_stdin);
3935 }
3936
3937 /*********************************************************************
3938  *              getc (MSVCRT.@)
3939  */
3940 int CDECL MSVCRT_getc(MSVCRT_FILE* file)
3941 {
3942   return MSVCRT_fgetc(file);
3943 }
3944
3945 /*********************************************************************
3946  *              gets (MSVCRT.@)
3947  */
3948 char * CDECL MSVCRT_gets(char *buf)
3949 {
3950   int    cc;
3951   char * buf_start = buf;
3952
3953   MSVCRT__lock_file(MSVCRT_stdin);
3954   for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
3955       cc = MSVCRT_fgetc(MSVCRT_stdin))
3956   if(cc != '\r') *buf++ = (char)cc;
3957
3958   *buf = '\0';
3959
3960   TRACE("got '%s'\n", buf_start);
3961   MSVCRT__unlock_file(MSVCRT_stdin);
3962   return buf_start;
3963 }
3964
3965 /*********************************************************************
3966  *              _getws (MSVCRT.@)
3967  */
3968 MSVCRT_wchar_t* CDECL MSVCRT__getws(MSVCRT_wchar_t* buf)
3969 {
3970     MSVCRT_wint_t cc;
3971     MSVCRT_wchar_t* ws = buf;
3972
3973     MSVCRT__lock_file(MSVCRT_stdin);
3974     for (cc = MSVCRT_fgetwc(MSVCRT_stdin); cc != MSVCRT_WEOF && cc != '\n';
3975          cc = MSVCRT_fgetwc(MSVCRT_stdin))
3976     {
3977         if (cc != '\r')
3978             *buf++ = (MSVCRT_wchar_t)cc;
3979     }
3980     *buf = '\0';
3981
3982     TRACE("got %s\n", debugstr_w(ws));
3983     MSVCRT__unlock_file(MSVCRT_stdin);
3984     return ws;
3985 }
3986
3987 /*********************************************************************
3988  *              putc (MSVCRT.@)
3989  */
3990 int CDECL MSVCRT_putc(int c, MSVCRT_FILE* file)
3991 {
3992   return MSVCRT_fputc(c, file);
3993 }
3994
3995 /*********************************************************************
3996  *              putchar (MSVCRT.@)
3997  */
3998 int CDECL MSVCRT_putchar(int c)
3999 {
4000   return MSVCRT_fputc(c, MSVCRT_stdout);
4001 }
4002
4003 /*********************************************************************
4004  *              _putwch (MSVCRT.@)
4005  */
4006 int CDECL MSVCRT__putwch(int c)
4007 {
4008   return MSVCRT_fputwc(c, MSVCRT_stdout);
4009 }
4010
4011 /*********************************************************************
4012  *              puts (MSVCRT.@)
4013  */
4014 int CDECL MSVCRT_puts(const char *s)
4015 {
4016     MSVCRT_size_t len = strlen(s);
4017     int ret;
4018
4019     MSVCRT__lock_file(MSVCRT_stdout);
4020     if(MSVCRT_fwrite(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4021         MSVCRT__unlock_file(MSVCRT_stdout);
4022         return MSVCRT_EOF;
4023     }
4024
4025     ret = MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
4026     MSVCRT__unlock_file(MSVCRT_stdout);
4027     return ret;
4028 }
4029
4030 /*********************************************************************
4031  *              _putws (MSVCRT.@)
4032  */
4033 int CDECL MSVCRT__putws(const MSVCRT_wchar_t *s)
4034 {
4035     static const MSVCRT_wchar_t nl = '\n';
4036     MSVCRT_size_t len = strlenW(s);
4037     int ret;
4038
4039     MSVCRT__lock_file(MSVCRT_stdout);
4040     if(MSVCRT_fwrite(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4041         MSVCRT__unlock_file(MSVCRT_stdout);
4042         return MSVCRT_EOF;
4043     }
4044
4045     ret = MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
4046     MSVCRT__unlock_file(MSVCRT_stdout);
4047     return ret;
4048 }
4049
4050 /*********************************************************************
4051  *              remove (MSVCRT.@)
4052  */
4053 int CDECL MSVCRT_remove(const char *path)
4054 {
4055   TRACE("(%s)\n",path);
4056   if (DeleteFileA(path))
4057     return 0;
4058   TRACE(":failed (%d)\n",GetLastError());
4059   msvcrt_set_errno(GetLastError());
4060   return -1;
4061 }
4062
4063 /*********************************************************************
4064  *              _wremove (MSVCRT.@)
4065  */
4066 int CDECL MSVCRT__wremove(const MSVCRT_wchar_t *path)
4067 {
4068   TRACE("(%s)\n",debugstr_w(path));
4069   if (DeleteFileW(path))
4070     return 0;
4071   TRACE(":failed (%d)\n",GetLastError());
4072   msvcrt_set_errno(GetLastError());
4073   return -1;
4074 }
4075
4076 /*********************************************************************
4077  *              rename (MSVCRT.@)
4078  */
4079 int CDECL MSVCRT_rename(const char *oldpath,const char *newpath)
4080 {
4081   TRACE(":from %s to %s\n",oldpath,newpath);
4082   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
4083     return 0;
4084   TRACE(":failed (%d)\n",GetLastError());
4085   msvcrt_set_errno(GetLastError());
4086   return -1;
4087 }
4088
4089 /*********************************************************************
4090  *              _wrename (MSVCRT.@)
4091  */
4092 int CDECL MSVCRT__wrename(const MSVCRT_wchar_t *oldpath,const MSVCRT_wchar_t *newpath)
4093 {
4094   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
4095   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
4096     return 0;
4097   TRACE(":failed (%d)\n",GetLastError());
4098   msvcrt_set_errno(GetLastError());
4099   return -1;
4100 }
4101
4102 /*********************************************************************
4103  *              setvbuf (MSVCRT.@)
4104  */
4105 int CDECL MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
4106 {
4107   MSVCRT__lock_file(file);
4108   if(file->_bufsiz) {
4109         MSVCRT_free(file->_base);
4110         file->_bufsiz = 0;
4111         file->_cnt = 0;
4112   }
4113   if(mode == MSVCRT__IOFBF) {
4114         file->_flag &= ~MSVCRT__IONBF;
4115         file->_base = file->_ptr = buf;
4116         if(buf) {
4117                 file->_bufsiz = size;
4118         }
4119   } else {
4120         file->_flag |= MSVCRT__IONBF;
4121   }
4122   MSVCRT__unlock_file(file);
4123   return 0;
4124 }
4125
4126 /*********************************************************************
4127  *              setbuf (MSVCRT.@)
4128  */
4129 void CDECL MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
4130 {
4131   MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ);
4132 }
4133
4134 /*********************************************************************
4135  *              tmpnam (MSVCRT.@)
4136  */
4137 char * CDECL MSVCRT_tmpnam(char *s)
4138 {
4139   char tmpstr[16];
4140   char *p;
4141   int count, size;
4142
4143   if (!s) {
4144     thread_data_t *data = msvcrt_get_thread_data();
4145
4146     if(!data->tmpnam_buffer)
4147       data->tmpnam_buffer = MSVCRT_malloc(MAX_PATH);
4148
4149     s = data->tmpnam_buffer;
4150   }
4151
4152   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
4153   p = s + sprintf(s, "\\s%s.", tmpstr);
4154   for (count = 0; count < MSVCRT_TMP_MAX; count++)
4155   {
4156     size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr);
4157     memcpy(p, tmpstr, size);
4158     p[size] = '\0';
4159     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
4160         GetLastError() == ERROR_FILE_NOT_FOUND)
4161       break;
4162   }
4163   return s;
4164 }
4165
4166 /*********************************************************************
4167  *              _wtmpnam (MSVCRT.@)
4168  */
4169 MSVCRT_wchar_t * CDECL MSVCRT_wtmpnam(MSVCRT_wchar_t *s)
4170 {
4171     static const MSVCRT_wchar_t format[] = {'\\','s','%','s','.',0};
4172     MSVCRT_wchar_t tmpstr[16];
4173     MSVCRT_wchar_t *p;
4174     int count, size;
4175     if (!s) {
4176         thread_data_t *data = msvcrt_get_thread_data();
4177
4178         if(!data->wtmpnam_buffer)
4179             data->wtmpnam_buffer = MSVCRT_malloc(sizeof(MSVCRT_wchar_t[MAX_PATH]));
4180
4181         s = data->wtmpnam_buffer;
4182     }
4183
4184     msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
4185     p = s + MSVCRT__snwprintf(s, MAX_PATH, format, tmpstr);
4186     for (count = 0; count < MSVCRT_TMP_MAX; count++)
4187     {
4188         size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr);
4189         memcpy(p, tmpstr, size*sizeof(MSVCRT_wchar_t));
4190         p[size] = '\0';
4191         if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
4192                 GetLastError() == ERROR_FILE_NOT_FOUND)
4193             break;
4194     }
4195     return s;
4196 }
4197
4198 /*********************************************************************
4199  *              tmpfile (MSVCRT.@)
4200  */
4201 MSVCRT_FILE* CDECL MSVCRT_tmpfile(void)
4202 {
4203   char *filename = MSVCRT_tmpnam(NULL);
4204   int fd;
4205   MSVCRT_FILE* file = NULL;
4206
4207   LOCK_FILES();
4208   fd = MSVCRT__open(filename, MSVCRT__O_CREAT | MSVCRT__O_BINARY | MSVCRT__O_RDWR | MSVCRT__O_TEMPORARY,
4209           MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
4210   if (fd != -1 && (file = msvcrt_alloc_fp()))
4211   {
4212     if (msvcrt_init_fp(file, fd, MSVCRT__IORW) == -1)
4213     {
4214         file->_flag = 0;
4215         file = NULL;
4216     }
4217     else file->_tmpfname = MSVCRT__strdup(filename);
4218   }
4219
4220   if(fd != -1 && !file)
4221       MSVCRT__close(fd);
4222   UNLOCK_FILES();
4223   return file;
4224 }
4225
4226 /*********************************************************************
4227  *      tmpfile_s (MSVCRT.@)
4228  */
4229 int CDECL MSVCRT_tmpfile_s(MSVCRT_FILE** file)
4230 {
4231     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
4232
4233     *file = MSVCRT_tmpfile();
4234     return 0;
4235 }
4236
4237 static int puts_clbk_file_a(void *file, int len, const char *str)
4238 {
4239     return MSVCRT_fwrite(str, sizeof(char), len, file);
4240 }
4241
4242 static int puts_clbk_file_w(void *file, int len, const MSVCRT_wchar_t *str)
4243 {
4244     int i, ret;
4245
4246     MSVCRT__lock_file(file);
4247
4248     if(!(msvcrt_get_ioinfo(((MSVCRT_FILE*)file)->_file)->wxflag & WX_TEXT)) {
4249         ret = MSVCRT_fwrite(str, sizeof(MSVCRT_wchar_t), len, file);
4250         MSVCRT__unlock_file(file);
4251         return ret;
4252     }
4253
4254     for(i=0; i<len; i++) {
4255         if(MSVCRT_fputwc(str[i], file) == MSVCRT_WEOF) {
4256             MSVCRT__unlock_file(file);
4257             return -1;
4258         }
4259     }
4260
4261     MSVCRT__unlock_file(file);
4262     return len;
4263 }
4264
4265 /*********************************************************************
4266  *              vfprintf (MSVCRT.@)
4267  */
4268 int CDECL MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, __ms_va_list valist)
4269 {
4270     BOOL tmp_buf;
4271     int ret;
4272
4273     MSVCRT__lock_file(file);
4274     tmp_buf = add_std_buffer(file);
4275     ret = pf_printf_a(puts_clbk_file_a, file, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4276     if(tmp_buf) remove_std_buffer(file);
4277     MSVCRT__unlock_file(file);
4278
4279     return ret;
4280 }
4281
4282 /*********************************************************************
4283  *              vfprintf_s (MSVCRT.@)
4284  */
4285 int CDECL MSVCRT_vfprintf_s(MSVCRT_FILE* file, const char *format, __ms_va_list valist)
4286 {
4287     BOOL tmp_buf;
4288     int ret;
4289
4290     if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
4291
4292     MSVCRT__lock_file(file);
4293     tmp_buf = add_std_buffer(file);
4294     ret = pf_printf_a(puts_clbk_file_a, file, format, NULL, FALSE, TRUE, arg_clbk_valist, NULL, &valist);
4295     if(tmp_buf) remove_std_buffer(file);
4296     MSVCRT__unlock_file(file);
4297
4298     return ret;
4299 }
4300
4301 /*********************************************************************
4302  *              vfwprintf (MSVCRT.@)
4303  */
4304 int CDECL MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, __ms_va_list valist)
4305 {
4306     BOOL tmp_buf;
4307     int ret;
4308
4309     MSVCRT__lock_file(file);
4310     tmp_buf = add_std_buffer(file);
4311     ret = pf_printf_w(puts_clbk_file_w, file, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4312     if(tmp_buf) remove_std_buffer(file);
4313     MSVCRT__unlock_file(file);
4314
4315     return ret;
4316 }
4317
4318 /*********************************************************************
4319  *              vfwprintf_s (MSVCRT.@)
4320  */
4321 int CDECL MSVCRT_vfwprintf_s(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, __ms_va_list valist)
4322 {
4323     BOOL tmp_buf;
4324     int ret;
4325
4326     if (!MSVCRT_CHECK_PMT( file != NULL )) return -1;
4327
4328     MSVCRT__lock_file(file);
4329     tmp_buf = add_std_buffer(file);
4330     ret = pf_printf_w(puts_clbk_file_w, file, format, NULL, FALSE, TRUE, arg_clbk_valist, NULL, &valist);
4331     if(tmp_buf) remove_std_buffer(file);
4332     MSVCRT__unlock_file(file);
4333
4334     return ret;
4335 }
4336
4337 /*********************************************************************
4338  *              _vfwprintf_l (MSVCRT.@)
4339  */
4340 int CDECL MSVCRT__vfwprintf_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format,
4341         MSVCRT__locale_t locale, __ms_va_list valist)
4342 {
4343     BOOL tmp_buf;
4344     int ret;
4345
4346     if (!MSVCRT_CHECK_PMT( file != NULL )) return -1;
4347
4348     MSVCRT__lock_file(file);
4349     tmp_buf = add_std_buffer(file);
4350     ret = pf_printf_w(puts_clbk_file_w, file, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4351     if(tmp_buf) remove_std_buffer(file);
4352     MSVCRT__unlock_file(file);
4353
4354     return ret;
4355 }
4356
4357 /*********************************************************************
4358  *              vprintf (MSVCRT.@)
4359  */
4360 int CDECL MSVCRT_vprintf(const char *format, __ms_va_list valist)
4361 {
4362   return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
4363 }
4364
4365 /*********************************************************************
4366  *              vprintf_s (MSVCRT.@)
4367  */
4368 int CDECL MSVCRT_vprintf_s(const char *format, __ms_va_list valist)
4369 {
4370   return MSVCRT_vfprintf_s(MSVCRT_stdout,format,valist);
4371 }
4372
4373 /*********************************************************************
4374  *              vwprintf (MSVCRT.@)
4375  */
4376 int CDECL MSVCRT_vwprintf(const MSVCRT_wchar_t *format, __ms_va_list valist)
4377 {
4378   return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
4379 }
4380
4381 /*********************************************************************
4382  *              vwprintf_s (MSVCRT.@)
4383  */
4384 int CDECL MSVCRT_vwprintf_s(const MSVCRT_wchar_t *format, __ms_va_list valist)
4385 {
4386   return MSVCRT_vfwprintf_s(MSVCRT_stdout,format,valist);
4387 }
4388
4389 /*********************************************************************
4390  *              fprintf (MSVCRT.@)
4391  */
4392 int CDECL MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
4393 {
4394     __ms_va_list valist;
4395     int res;
4396     __ms_va_start(valist, format);
4397     res = MSVCRT_vfprintf(file, format, valist);
4398     __ms_va_end(valist);
4399     return res;
4400 }
4401
4402 /*********************************************************************
4403  *              fprintf_s (MSVCRT.@)
4404  */
4405 int CDECL MSVCRT_fprintf_s(MSVCRT_FILE* file, const char *format, ...)
4406 {
4407     __ms_va_list valist;
4408     int res;
4409     __ms_va_start(valist, format);
4410     res = MSVCRT_vfprintf_s(file, format, valist);
4411     __ms_va_end(valist);
4412     return res;
4413 }
4414
4415 /*********************************************************************
4416  *              fwprintf (MSVCRT.@)
4417  */
4418 int CDECL MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
4419 {
4420     __ms_va_list valist;
4421     int res;
4422     __ms_va_start(valist, format);
4423     res = MSVCRT_vfwprintf(file, format, valist);
4424     __ms_va_end(valist);
4425     return res;
4426 }
4427
4428 /*********************************************************************
4429  *              fwprintf_s (MSVCRT.@)
4430  */
4431 int CDECL MSVCRT_fwprintf_s(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
4432 {
4433     __ms_va_list valist;
4434     int res;
4435     __ms_va_start(valist, format);
4436     res = MSVCRT_vfwprintf_s(file, format, valist);
4437     __ms_va_end(valist);
4438     return res;
4439 }
4440
4441 /*********************************************************************
4442  *              _fwprintf_l (MSVCRT.@)
4443  */
4444 int CDECL MSVCRT__fwprintf_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, ...)
4445 {
4446     __ms_va_list valist;
4447     int res;
4448     __ms_va_start(valist, locale);
4449     res = MSVCRT__vfwprintf_l(file, format, locale, valist);
4450     __ms_va_end(valist);
4451     return res;
4452 }
4453
4454 /*********************************************************************
4455  *              printf (MSVCRT.@)
4456  */
4457 int CDECL MSVCRT_printf(const char *format, ...)
4458 {
4459     __ms_va_list valist;
4460     int res;
4461     __ms_va_start(valist, format);
4462     res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
4463     __ms_va_end(valist);
4464     return res;
4465 }
4466
4467 /*********************************************************************
4468  *              printf_s (MSVCRT.@)
4469  */
4470 int CDECL MSVCRT_printf_s(const char *format, ...)
4471 {
4472     __ms_va_list valist;
4473     int res;
4474     __ms_va_start(valist, format);
4475     res = MSVCRT_vprintf_s(format, valist);
4476     __ms_va_end(valist);
4477     return res;
4478 }
4479
4480 /*********************************************************************
4481  *              ungetc (MSVCRT.@)
4482  */
4483 int CDECL MSVCRT_ungetc(int c, MSVCRT_FILE * file)
4484 {
4485     if (c == MSVCRT_EOF)
4486         return MSVCRT_EOF;
4487
4488     MSVCRT__lock_file(file);
4489     if(file->_bufsiz == 0 && msvcrt_alloc_buffer(file))
4490         file->_ptr++;
4491     if(file->_ptr>file->_base) {
4492         file->_ptr--;
4493         *file->_ptr=c;
4494         file->_cnt++;
4495         MSVCRT_clearerr(file);
4496         MSVCRT__unlock_file(file);
4497         return c;
4498     }
4499
4500     MSVCRT__unlock_file(file);
4501     return MSVCRT_EOF;
4502 }
4503
4504 /*********************************************************************
4505  *              ungetwc (MSVCRT.@)
4506  */
4507 MSVCRT_wint_t CDECL MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file)
4508 {
4509     MSVCRT_wchar_t mwc = wc;
4510     unsigned char * pp = (unsigned char *)&mwc;
4511     int i;
4512
4513     if (wc == MSVCRT_WEOF)
4514         return MSVCRT_WEOF;
4515
4516     MSVCRT__lock_file(file);
4517     for(i=sizeof(MSVCRT_wchar_t)-1;i>=0;i--) {
4518         if(pp[i] != MSVCRT_ungetc(pp[i],file)) {
4519             MSVCRT__unlock_file(file);
4520             return MSVCRT_WEOF;
4521         }
4522     }
4523
4524     MSVCRT__unlock_file(file);
4525     return mwc;
4526 }
4527
4528 /*********************************************************************
4529  *              wprintf (MSVCRT.@)
4530  */
4531 int CDECL MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
4532 {
4533     __ms_va_list valist;
4534     int res;
4535     __ms_va_start(valist, format);
4536     res = MSVCRT_vwprintf(format, valist);
4537     __ms_va_end(valist);
4538     return res;
4539 }
4540
4541 /*********************************************************************
4542  *              wprintf_s (MSVCRT.@)
4543  */
4544 int CDECL MSVCRT_wprintf_s(const MSVCRT_wchar_t *format, ...)
4545 {
4546     __ms_va_list valist;
4547     int res;
4548     __ms_va_start(valist, format);
4549     res = MSVCRT_vwprintf_s(format, valist);
4550     __ms_va_end(valist);
4551     return res;
4552 }
4553
4554 /*********************************************************************
4555  *              _getmaxstdio (MSVCRT.@)
4556  */
4557 int CDECL MSVCRT__getmaxstdio(void)
4558 {
4559     return MSVCRT_max_streams;
4560 }
4561
4562 /*********************************************************************
4563  *              _setmaxstdio (MSVCRT.@)
4564  */
4565 int CDECL MSVCRT__setmaxstdio(int newmax)
4566 {
4567     TRACE("%d\n", newmax);
4568
4569     if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
4570         return -1;
4571
4572     MSVCRT_max_streams = newmax;
4573     return MSVCRT_max_streams;
4574 }