loader: Merge the first and second stage loaders into a single wine binary.
[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 <time.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <sys/types.h>
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winternl.h"
43 #include "msvcrt.h"
44
45 #include "wine/unicode.h"
46
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
50
51 /* for stat mode, permissions apply to all,owner and group */
52 #define ALL_S_IREAD  (MSVCRT__S_IREAD  | (MSVCRT__S_IREAD  >> 3) | (MSVCRT__S_IREAD  >> 6))
53 #define ALL_S_IWRITE (MSVCRT__S_IWRITE | (MSVCRT__S_IWRITE >> 3) | (MSVCRT__S_IWRITE >> 6))
54 #define ALL_S_IEXEC  (MSVCRT__S_IEXEC  | (MSVCRT__S_IEXEC  >> 3) | (MSVCRT__S_IEXEC  >> 6))
55
56 /* _access() bit flags FIXME: incomplete */
57 #define MSVCRT_W_OK      0x02
58
59 /* values for wxflag in file descriptor */
60 #define WX_OPEN           0x01
61 #define WX_ATEOF          0x02
62 #define WX_READEOF        0x04  /* like ATEOF, but for underlying file rather than buffer */
63 #define WX_DONTINHERIT    0x10
64 #define WX_APPEND         0x20
65 #define WX_TEXT           0x80
66
67 /* FIXME: this should be allocated dynamically */
68 #define MSVCRT_MAX_FILES 2048
69
70 typedef struct {
71     HANDLE              handle;
72     unsigned char       wxflag;
73     DWORD               unkn[7]; /* critical section and init flag */       
74 } ioinfo;
75
76 static ioinfo MSVCRT_fdesc[MSVCRT_MAX_FILES];
77
78 MSVCRT_FILE MSVCRT__iob[3] = { { 0 } };
79
80 static int MSVCRT_fdstart = 3; /* first unallocated fd */
81 static int MSVCRT_fdend = 3; /* highest allocated fd */
82
83 static MSVCRT_FILE* MSVCRT_fstreams[2048];
84 static int   MSVCRT_stream_idx;
85
86 /* INTERNAL: process umask */
87 static int MSVCRT_umask = 0;
88
89 /* INTERNAL: Static buffer for temp file name */
90 static char MSVCRT_tmpname[MAX_PATH];
91
92 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
93 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
94 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
95 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
96
97 #define TOUL(x) (ULONGLONG)(x)
98 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
99 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
100 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
101 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
102
103 /* This critical section protects the tables MSVCRT_fdesc and MSVCRT_fstreams,
104  * and their related indexes, MSVCRT_fdstart, MSVCRT_fdend,
105  * and MSVCRT_stream_idx, from race conditions.
106  * It doesn't protect against race conditions manipulating the underlying files
107  * or flags; doing so would probably be better accomplished with per-file
108  * protection, rather than locking the whole table for every change.
109  */
110 static CRITICAL_SECTION MSVCRT_file_cs;
111 #define LOCK_FILES()    do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
112 #define UNLOCK_FILES()  do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
113
114 static void msvcrt_stat64_to_stat(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stat *buf)
115 {
116     buf->st_dev   = buf64->st_dev;
117     buf->st_ino   = buf64->st_ino;
118     buf->st_mode  = buf64->st_mode;
119     buf->st_nlink = buf64->st_nlink;
120     buf->st_uid   = buf64->st_uid;
121     buf->st_gid   = buf64->st_gid;
122     buf->st_rdev  = buf64->st_rdev;
123     buf->st_size  = buf64->st_size;
124     buf->st_atime = buf64->st_atime;
125     buf->st_mtime = buf64->st_mtime;
126     buf->st_ctime = buf64->st_ctime;
127 }
128
129 static void msvcrt_stat64_to_stati64(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stati64 *buf)
130 {
131     buf->st_dev   = buf64->st_dev;
132     buf->st_ino   = buf64->st_ino;
133     buf->st_mode  = buf64->st_mode;
134     buf->st_nlink = buf64->st_nlink;
135     buf->st_uid   = buf64->st_uid;
136     buf->st_gid   = buf64->st_gid;
137     buf->st_rdev  = buf64->st_rdev;
138     buf->st_size  = buf64->st_size;
139     buf->st_atime = buf64->st_atime;
140     buf->st_mtime = buf64->st_mtime;
141     buf->st_ctime = buf64->st_ctime;
142 }
143
144 static inline BOOL msvcrt_is_valid_fd(int fd)
145 {
146   return fd >= 0 && fd < MSVCRT_fdend && (MSVCRT_fdesc[fd].wxflag & WX_OPEN);
147 }
148
149 /* INTERNAL: Get the HANDLE for a fd
150  * This doesn't lock the table, because a failure will result in
151  * INVALID_HANDLE_VALUE being returned, which should be handled correctly.  If
152  * it returns a valid handle which is about to be closed, a subsequent call
153  * will fail, most likely in a sane way.
154  */
155 static HANDLE msvcrt_fdtoh(int fd)
156 {
157   if (!msvcrt_is_valid_fd(fd))
158   {
159     WARN(":fd (%d) - no handle!\n",fd);
160     *MSVCRT___doserrno() = 0;
161     *MSVCRT__errno() = MSVCRT_EBADF;
162     return INVALID_HANDLE_VALUE;
163   }
164   if (MSVCRT_fdesc[fd].handle == INVALID_HANDLE_VALUE) FIXME("wtf\n");
165   return MSVCRT_fdesc[fd].handle;
166 }
167
168 /* INTERNAL: free a file entry fd */
169 static void msvcrt_free_fd(int fd)
170 {
171   HANDLE old_handle;
172
173   LOCK_FILES();
174   old_handle = MSVCRT_fdesc[fd].handle;
175   MSVCRT_fdesc[fd].handle = INVALID_HANDLE_VALUE;
176   MSVCRT_fdesc[fd].wxflag = 0;
177   TRACE(":fd (%d) freed\n",fd);
178   if (fd < 3) /* don't use 0,1,2 for user files */
179   {
180     switch (fd)
181     {
182     case 0:
183         if (GetStdHandle(STD_INPUT_HANDLE) == old_handle) SetStdHandle(STD_INPUT_HANDLE, 0);
184         break;
185     case 1:
186         if (GetStdHandle(STD_OUTPUT_HANDLE) == old_handle) SetStdHandle(STD_OUTPUT_HANDLE, 0);
187         break;
188     case 2:
189         if (GetStdHandle(STD_ERROR_HANDLE) == old_handle) SetStdHandle(STD_ERROR_HANDLE, 0);
190         break;
191     }
192   }
193   else
194   {
195     if (fd == MSVCRT_fdend - 1)
196       MSVCRT_fdend--;
197     if (fd < MSVCRT_fdstart)
198       MSVCRT_fdstart = fd;
199   }
200   UNLOCK_FILES();
201 }
202
203 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE, starting from fd */
204 /* caller must hold the files lock */
205 static int msvcrt_alloc_fd_from(HANDLE hand, int flag, int fd)
206 {
207   if (fd >= MSVCRT_MAX_FILES)
208   {
209     WARN(":files exhausted!\n");
210     return -1;
211   }
212   MSVCRT_fdesc[fd].handle = hand;
213   MSVCRT_fdesc[fd].wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT));
214
215   /* locate next free slot */
216   if (fd == MSVCRT_fdstart && fd == MSVCRT_fdend)
217     MSVCRT_fdstart = MSVCRT_fdend + 1;
218   else
219     while (MSVCRT_fdstart < MSVCRT_fdend &&
220      MSVCRT_fdesc[MSVCRT_fdstart].handle != INVALID_HANDLE_VALUE)
221       MSVCRT_fdstart++;
222   /* update last fd in use */
223   if (fd >= MSVCRT_fdend)
224     MSVCRT_fdend = fd + 1;
225   TRACE("fdstart is %d, fdend is %d\n", MSVCRT_fdstart, MSVCRT_fdend);
226
227   switch (fd)
228   {
229   case 0: SetStdHandle(STD_INPUT_HANDLE,  hand); break;
230   case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
231   case 2: SetStdHandle(STD_ERROR_HANDLE,  hand); break;
232   }
233
234   return fd;
235 }
236
237 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
238 static int msvcrt_alloc_fd(HANDLE hand, int flag)
239 {
240   int ret;
241
242   LOCK_FILES();
243   TRACE(":handle (%p) allocating fd (%d)\n",hand,MSVCRT_fdstart);
244   ret = msvcrt_alloc_fd_from(hand, flag, MSVCRT_fdstart);
245   UNLOCK_FILES();
246   return ret;
247 }
248
249 /* INTERNAL: Allocate a FILE* for an fd slot */
250 /* caller must hold the files lock */
251 static MSVCRT_FILE* msvcrt_alloc_fp(void)
252 {
253   unsigned int i;
254
255   for (i = 3; i < sizeof(MSVCRT_fstreams) / sizeof(MSVCRT_fstreams[0]); i++)
256   {
257     if (!MSVCRT_fstreams[i] || MSVCRT_fstreams[i]->_flag == 0)
258     {
259       if (!MSVCRT_fstreams[i])
260       {
261         if (!(MSVCRT_fstreams[i] = MSVCRT_calloc(sizeof(MSVCRT_FILE),1)))
262           return NULL;
263         if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++;
264       }
265       return MSVCRT_fstreams[i];
266     }
267   }
268   return NULL;
269 }
270
271 /* INTERNAL: initialize a FILE* from an open fd */
272 static int msvcrt_init_fp(MSVCRT_FILE* file, int fd, unsigned stream_flags)
273 {
274   TRACE(":fd (%d) allocating FILE*\n",fd);
275   if (!msvcrt_is_valid_fd(fd))
276   {
277     WARN(":invalid fd %d\n",fd);
278     *MSVCRT___doserrno() = 0;
279     *MSVCRT__errno() = MSVCRT_EBADF;
280     return -1;
281   }
282   memset(file, 0, sizeof(*file));
283   file->_file = fd;
284   file->_flag = stream_flags;
285
286   TRACE(":got FILE* (%p)\n",file);
287   return 0;
288 }
289
290 /* INTERNAL: Create an inheritance data block (for spawned process)
291  * The inheritance block is made of:
292  *      00      int     nb of file descriptor (NBFD)
293  *      04      char    file flags (wxflag): repeated for each fd
294  *      4+NBFD  HANDLE  file handle: repeated for each fd
295  */
296 unsigned msvcrt_create_io_inherit_block(WORD *size, BYTE **block)
297 {
298   int         fd;
299   char*       wxflag_ptr;
300   HANDLE*     handle_ptr;
301
302   *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * MSVCRT_fdend;
303   *block = MSVCRT_calloc(*size, 1);
304   if (!*block)
305   {
306     *size = 0;
307     return FALSE;
308   }
309   wxflag_ptr = (char*)*block + sizeof(unsigned);
310   handle_ptr = (HANDLE*)(wxflag_ptr + MSVCRT_fdend * sizeof(char));
311
312   *(unsigned*)*block = MSVCRT_fdend;
313   for (fd = 0; fd < MSVCRT_fdend; fd++)
314   {
315     /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
316     if ((MSVCRT_fdesc[fd].wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
317     {
318       *wxflag_ptr = MSVCRT_fdesc[fd].wxflag;
319       *handle_ptr = MSVCRT_fdesc[fd].handle;
320     }
321     else
322     {
323       *wxflag_ptr = 0;
324       *handle_ptr = INVALID_HANDLE_VALUE;
325     }
326     wxflag_ptr++; handle_ptr++;
327   } 
328   return TRUE;
329 }
330
331 /* INTERNAL: Set up all file descriptors, 
332  * as well as default streams (stdin, stderr and stdout) 
333  */
334 void msvcrt_init_io(void)
335 {
336   STARTUPINFOA  si;
337   int           i;
338
339   InitializeCriticalSection(&MSVCRT_file_cs);
340   MSVCRT_file_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs");
341   GetStartupInfoA(&si);
342   if (si.cbReserved2 != 0 && si.lpReserved2 != NULL)
343   {
344     char*       wxflag_ptr;
345     HANDLE*     handle_ptr;
346
347     MSVCRT_fdend = *(unsigned*)si.lpReserved2;
348
349     wxflag_ptr = (char*)(si.lpReserved2 + sizeof(unsigned));
350     handle_ptr = (HANDLE*)(wxflag_ptr + MSVCRT_fdend * sizeof(char));
351
352     MSVCRT_fdend = min(MSVCRT_fdend, sizeof(MSVCRT_fdesc) / sizeof(MSVCRT_fdesc[0]));
353     for (i = 0; i < MSVCRT_fdend; i++)
354     {
355       if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
356       {
357         MSVCRT_fdesc[i].wxflag  = *wxflag_ptr;
358         MSVCRT_fdesc[i].handle = *handle_ptr;
359       }
360       else
361       {
362         MSVCRT_fdesc[i].wxflag  = 0;
363         MSVCRT_fdesc[i].handle = INVALID_HANDLE_VALUE;
364       }
365       wxflag_ptr++; handle_ptr++;
366     }
367     for (MSVCRT_fdstart = 3; MSVCRT_fdstart < MSVCRT_fdend; MSVCRT_fdstart++)
368         if (MSVCRT_fdesc[MSVCRT_fdstart].handle == INVALID_HANDLE_VALUE) break;
369   }
370
371   if (!(MSVCRT_fdesc[0].wxflag & WX_OPEN) || MSVCRT_fdesc[0].handle == INVALID_HANDLE_VALUE)
372   {
373       HANDLE std = GetStdHandle(STD_INPUT_HANDLE);
374       if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
375                                                          GetCurrentProcess(), &MSVCRT_fdesc[0].handle,
376                                                          0, TRUE, DUPLICATE_SAME_ACCESS))
377           MSVCRT_fdesc[0].wxflag = WX_OPEN | WX_TEXT;
378   }
379   if (!(MSVCRT_fdesc[1].wxflag & WX_OPEN) || MSVCRT_fdesc[1].handle == INVALID_HANDLE_VALUE)
380   {
381       HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);
382       if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
383                                                          GetCurrentProcess(), &MSVCRT_fdesc[1].handle,
384                                                          0, TRUE, DUPLICATE_SAME_ACCESS))
385           MSVCRT_fdesc[1].wxflag = WX_OPEN | WX_TEXT;
386   }
387   if (!(MSVCRT_fdesc[2].wxflag & WX_OPEN) || MSVCRT_fdesc[2].handle == INVALID_HANDLE_VALUE)
388   {
389       HANDLE std = GetStdHandle(STD_ERROR_HANDLE);
390       if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
391                                                          GetCurrentProcess(), &MSVCRT_fdesc[2].handle,
392                                                          0, TRUE, DUPLICATE_SAME_ACCESS))
393           MSVCRT_fdesc[2].wxflag = WX_OPEN | WX_TEXT;
394   }
395
396   TRACE(":handles (%p)(%p)(%p)\n",MSVCRT_fdesc[0].handle,
397         MSVCRT_fdesc[1].handle,MSVCRT_fdesc[2].handle);
398
399   memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
400   for (i = 0; i < 3; i++)
401   {
402     /* FILE structs for stdin/out/err are static and never deleted */
403     MSVCRT_fstreams[i] = &MSVCRT__iob[i];
404     MSVCRT__iob[i]._file = i;
405     MSVCRT__iob[i]._tmpfname = NULL;
406     MSVCRT__iob[i]._flag = (i == 0) ? MSVCRT__IOREAD : MSVCRT__IOWRT;
407   }
408   MSVCRT_stream_idx = 3;
409 }
410
411 /* INTERNAL: Flush stdio file buffer */
412 static int msvcrt_flush_buffer(MSVCRT_FILE* file)
413 {
414   if(file->_bufsiz) {
415         int cnt=file->_ptr-file->_base;
416         if(cnt>0 && MSVCRT__write(file->_file, file->_base, cnt) != cnt) {
417             file->_flag |= MSVCRT__IOERR;
418             return MSVCRT_EOF;
419         }
420         file->_ptr=file->_base;
421         file->_cnt=file->_bufsiz;
422   }
423   return 0;
424 }
425
426 /* INTERNAL: Allocate stdio file buffer */
427 static void msvcrt_alloc_buffer(MSVCRT_FILE* file)
428 {
429         file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1);
430         if(file->_base) {
431                 file->_bufsiz = MSVCRT_BUFSIZ;
432                 file->_flag |= MSVCRT__IOMYBUF;
433         } else {
434                 file->_base = (char*)(&file->_charbuf);
435                 /* put here 2 ??? */
436                 file->_bufsiz = sizeof(file->_charbuf);
437         }
438         file->_ptr = file->_base;
439         file->_cnt = 0;
440 }
441
442 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
443 static void msvcrt_int_to_base32(int num, char *str)
444 {
445   char *p;
446   int n = num;
447   int digits = 0;
448
449   while (n != 0)
450   {
451     n >>= 5;
452     digits++;
453   }
454   p = str + digits;
455   *p = 0;
456   while (--p >= str)
457   {
458     *p = (num & 31) + '0';
459     if (*p > '9')
460       *p += ('a' - '0' - 10);
461     num >>= 5;
462   }
463 }
464
465 /*********************************************************************
466  *              __iob_func(MSVCRT.@)
467  */
468 MSVCRT_FILE * CDECL MSVCRT___iob_func(void)
469 {
470  return &MSVCRT__iob[0];
471 }
472
473 /*********************************************************************
474  *              _access (MSVCRT.@)
475  */
476 int CDECL MSVCRT__access(const char *filename, int mode)
477 {
478   DWORD attr = GetFileAttributesA(filename);
479
480   TRACE("(%s,%d) %d\n",filename,mode,attr);
481
482   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
483   {
484     msvcrt_set_errno(GetLastError());
485     return -1;
486   }
487   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
488   {
489     msvcrt_set_errno(ERROR_ACCESS_DENIED);
490     return -1;
491   }
492   return 0;
493 }
494
495 /*********************************************************************
496  *              _waccess (MSVCRT.@)
497  */
498 int CDECL _waccess(const MSVCRT_wchar_t *filename, int mode)
499 {
500   DWORD attr = GetFileAttributesW(filename);
501
502   TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
503
504   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
505   {
506     msvcrt_set_errno(GetLastError());
507     return -1;
508   }
509   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
510   {
511     msvcrt_set_errno(ERROR_ACCESS_DENIED);
512     return -1;
513   }
514   return 0;
515 }
516
517 /*********************************************************************
518  *              _chmod (MSVCRT.@)
519  */
520 int CDECL MSVCRT__chmod(const char *path, int flags)
521 {
522   DWORD oldFlags = GetFileAttributesA(path);
523
524   if (oldFlags != INVALID_FILE_ATTRIBUTES)
525   {
526     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
527       oldFlags | FILE_ATTRIBUTE_READONLY;
528
529     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
530       return 0;
531   }
532   msvcrt_set_errno(GetLastError());
533   return -1;
534 }
535
536 /*********************************************************************
537  *              _wchmod (MSVCRT.@)
538  */
539 int CDECL _wchmod(const MSVCRT_wchar_t *path, int flags)
540 {
541   DWORD oldFlags = GetFileAttributesW(path);
542
543   if (oldFlags != INVALID_FILE_ATTRIBUTES)
544   {
545     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
546       oldFlags | FILE_ATTRIBUTE_READONLY;
547
548     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
549       return 0;
550   }
551   msvcrt_set_errno(GetLastError());
552   return -1;
553 }
554
555 /*********************************************************************
556  *              _unlink (MSVCRT.@)
557  */
558 int CDECL MSVCRT__unlink(const char *path)
559 {
560   TRACE("%s\n",debugstr_a(path));
561   if(DeleteFileA(path))
562     return 0;
563   TRACE("failed (%d)\n",GetLastError());
564   msvcrt_set_errno(GetLastError());
565   return -1;
566 }
567
568 /*********************************************************************
569  *              _wunlink (MSVCRT.@)
570  */
571 int CDECL _wunlink(const MSVCRT_wchar_t *path)
572 {
573   TRACE("(%s)\n",debugstr_w(path));
574   if(DeleteFileW(path))
575     return 0;
576   TRACE("failed (%d)\n",GetLastError());
577   msvcrt_set_errno(GetLastError());
578   return -1;
579 }
580
581 /* _flushall calls MSVCRT_fflush which calls _flushall */
582 int CDECL MSVCRT_fflush(MSVCRT_FILE* file);
583
584 /*********************************************************************
585  *              _flushall (MSVCRT.@)
586  */
587 int CDECL _flushall(void)
588 {
589   int i, num_flushed = 0;
590
591   LOCK_FILES();
592   for (i = 3; i < MSVCRT_stream_idx; i++)
593     if (MSVCRT_fstreams[i] && MSVCRT_fstreams[i]->_flag)
594     {
595 #if 0
596       /* FIXME: flush, do not commit */
597       if (_commit(i) == -1)
598         if (MSVCRT_fstreams[i])
599           MSVCRT_fstreams[i]->_flag |= MSVCRT__IOERR;
600 #endif
601       if(MSVCRT_fstreams[i]->_flag & MSVCRT__IOWRT) {
602         MSVCRT_fflush(MSVCRT_fstreams[i]);
603         num_flushed++;
604       }
605     }
606   UNLOCK_FILES();
607
608   TRACE(":flushed (%d) handles\n",num_flushed);
609   return num_flushed;
610 }
611
612 /*********************************************************************
613  *              fflush (MSVCRT.@)
614  */
615 int CDECL MSVCRT_fflush(MSVCRT_FILE* file)
616 {
617   if(!file) {
618         _flushall();
619   } else if(file->_flag & MSVCRT__IOWRT) {
620         int res=msvcrt_flush_buffer(file);
621         return res;
622   }
623   return 0;
624 }
625
626 /*********************************************************************
627  *              _close (MSVCRT.@)
628  */
629 int CDECL MSVCRT__close(int fd)
630 {
631   HANDLE hand;
632   int ret;
633
634   LOCK_FILES();
635   hand = msvcrt_fdtoh(fd);
636   TRACE(":fd (%d) handle (%p)\n",fd,hand);
637   if (hand == INVALID_HANDLE_VALUE)
638     ret = -1;
639   else if (!CloseHandle(hand))
640   {
641     WARN(":failed-last error (%d)\n",GetLastError());
642     msvcrt_set_errno(GetLastError());
643     ret = -1;
644   }
645   else
646   {
647     msvcrt_free_fd(fd);
648     ret = 0;
649   }
650   UNLOCK_FILES();
651   TRACE(":ok\n");
652   return ret;
653 }
654
655 /*********************************************************************
656  *              _commit (MSVCRT.@)
657  */
658 int CDECL _commit(int fd)
659 {
660   HANDLE hand = msvcrt_fdtoh(fd);
661
662   TRACE(":fd (%d) handle (%p)\n",fd,hand);
663   if (hand == INVALID_HANDLE_VALUE)
664     return -1;
665
666   if (!FlushFileBuffers(hand))
667   {
668     if (GetLastError() == ERROR_INVALID_HANDLE)
669     {
670       /* FlushFileBuffers fails for console handles
671        * so we ignore this error.
672        */
673       return 0;
674     }
675     TRACE(":failed-last error (%d)\n",GetLastError());
676     msvcrt_set_errno(GetLastError());
677     return -1;
678   }
679   TRACE(":ok\n");
680   return 0;
681 }
682
683 /*********************************************************************
684  *              _dup2 (MSVCRT.@)
685  * NOTES
686  * MSDN isn't clear on this point, but the remarks for _pipe
687  * indicate file descriptors duplicated with _dup and _dup2 are always
688  * inheritable.
689  */
690 int CDECL MSVCRT__dup2(int od, int nd)
691 {
692   int ret;
693
694   TRACE("(od=%d, nd=%d)\n", od, nd);
695   LOCK_FILES();
696   if (nd < MSVCRT_MAX_FILES && msvcrt_is_valid_fd(od))
697   {
698     HANDLE handle;
699
700     if (DuplicateHandle(GetCurrentProcess(), MSVCRT_fdesc[od].handle,
701      GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
702     {
703       int wxflag = MSVCRT_fdesc[od].wxflag & ~MSVCRT__O_NOINHERIT;
704
705       if (msvcrt_is_valid_fd(nd))
706         MSVCRT__close(nd);
707       ret = msvcrt_alloc_fd_from(handle, wxflag, nd);
708       if (ret == -1)
709       {
710         CloseHandle(handle);
711         *MSVCRT__errno() = MSVCRT_EMFILE;
712       }
713       else
714       {
715         /* _dup2 returns 0, not nd, on success */
716         ret = 0;
717       }
718     }
719     else
720     {
721       ret = -1;
722       msvcrt_set_errno(GetLastError());
723     }
724   }
725   else
726   {
727     *MSVCRT__errno() = MSVCRT_EBADF;
728     ret = -1;
729   }
730   UNLOCK_FILES();
731   return ret;
732 }
733
734 /*********************************************************************
735  *              _dup (MSVCRT.@)
736  */
737 int CDECL MSVCRT__dup(int od)
738 {
739   int fd, ret;
740  
741   LOCK_FILES();
742   fd = MSVCRT_fdstart;
743   if (MSVCRT__dup2(od, fd) == 0)
744     ret = fd;
745   else
746     ret = -1;
747   UNLOCK_FILES();
748   return ret;
749 }
750
751 /*********************************************************************
752  *              _eof (MSVCRT.@)
753  */
754 int CDECL _eof(int fd)
755 {
756   DWORD curpos,endpos;
757   LONG hcurpos,hendpos;
758   HANDLE hand = msvcrt_fdtoh(fd);
759
760   TRACE(":fd (%d) handle (%p)\n",fd,hand);
761
762   if (hand == INVALID_HANDLE_VALUE)
763     return -1;
764
765   if (MSVCRT_fdesc[fd].wxflag & WX_ATEOF) return TRUE;
766
767   /* Otherwise we do it the hard way */
768   hcurpos = hendpos = 0;
769   curpos = SetFilePointer(hand, 0, &hcurpos, FILE_CURRENT);
770   endpos = SetFilePointer(hand, 0, &hendpos, FILE_END);
771
772   if (curpos == endpos && hcurpos == hendpos)
773   {
774     /* FIXME: shouldn't WX_ATEOF be set here? */
775     return TRUE;
776   }
777
778   SetFilePointer(hand, curpos, &hcurpos, FILE_BEGIN);
779   return FALSE;
780 }
781
782 /*********************************************************************
783  *              _fcloseall (MSVCRT.@)
784  */
785 int CDECL MSVCRT__fcloseall(void)
786 {
787   int num_closed = 0, i;
788
789   LOCK_FILES();
790   for (i = 3; i < MSVCRT_stream_idx; i++)
791     if (MSVCRT_fstreams[i] && MSVCRT_fstreams[i]->_flag &&
792         !MSVCRT_fclose(MSVCRT_fstreams[i]))
793       num_closed++;
794   UNLOCK_FILES();
795
796   TRACE(":closed (%d) handles\n",num_closed);
797   return num_closed;
798 }
799
800 /* free everything on process exit */
801 void msvcrt_free_io(void)
802 {
803     MSVCRT__fcloseall();
804     /* The Win32 _fcloseall() function explicitly doesn't close stdin,
805      * stdout, and stderr (unlike GNU), so we need to fclose() them here
806      * or they won't get flushed.
807      */
808     MSVCRT_fclose(&MSVCRT__iob[0]);
809     MSVCRT_fclose(&MSVCRT__iob[1]);
810     MSVCRT_fclose(&MSVCRT__iob[2]);
811     MSVCRT_file_cs.DebugInfo->Spare[0] = 0;
812     DeleteCriticalSection(&MSVCRT_file_cs);
813 }
814
815 /*********************************************************************
816  *              _lseeki64 (MSVCRT.@)
817  */
818 __int64 CDECL MSVCRT__lseeki64(int fd, __int64 offset, int whence)
819 {
820   HANDLE hand = msvcrt_fdtoh(fd);
821   LARGE_INTEGER ofs, ret;
822
823   TRACE(":fd (%d) handle (%p)\n",fd,hand);
824   if (hand == INVALID_HANDLE_VALUE)
825     return -1;
826
827   if (whence < 0 || whence > 2)
828   {
829     *MSVCRT__errno() = MSVCRT_EINVAL;
830     return -1;
831   }
832
833   TRACE(":fd (%d) to %s pos %s\n",
834         fd,wine_dbgstr_longlong(offset),
835         (whence==SEEK_SET)?"SEEK_SET":
836         (whence==SEEK_CUR)?"SEEK_CUR":
837         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
838
839   ofs.QuadPart = offset;
840   if (SetFilePointerEx(hand, ofs, &ret, whence))
841   {
842     MSVCRT_fdesc[fd].wxflag &= ~(WX_ATEOF|WX_READEOF);
843     /* FIXME: What if we seek _to_ EOF - is EOF set? */
844
845     return ret.QuadPart;
846   }
847   TRACE(":error-last error (%d)\n",GetLastError());
848   msvcrt_set_errno(GetLastError());
849   return -1;
850 }
851
852 /*********************************************************************
853  *              _lseek (MSVCRT.@)
854  */
855 LONG CDECL MSVCRT__lseek(int fd, LONG offset, int whence)
856 {
857     return MSVCRT__lseeki64(fd, offset, whence);
858 }
859
860 /*********************************************************************
861  *              _locking (MSVCRT.@)
862  *
863  * This is untested; the underlying LockFile doesn't work yet.
864  */
865 int CDECL MSVCRT__locking(int fd, int mode, LONG nbytes)
866 {
867   BOOL ret;
868   DWORD cur_locn;
869   HANDLE hand = msvcrt_fdtoh(fd);
870
871   TRACE(":fd (%d) handle (%p)\n",fd,hand);
872   if (hand == INVALID_HANDLE_VALUE)
873     return -1;
874
875   if (mode < 0 || mode > 4)
876   {
877     *MSVCRT__errno() = MSVCRT_EINVAL;
878     return -1;
879   }
880
881   TRACE(":fd (%d) by 0x%08x mode %s\n",
882         fd,nbytes,(mode==MSVCRT__LK_UNLCK)?"_LK_UNLCK":
883         (mode==MSVCRT__LK_LOCK)?"_LK_LOCK":
884         (mode==MSVCRT__LK_NBLCK)?"_LK_NBLCK":
885         (mode==MSVCRT__LK_RLCK)?"_LK_RLCK":
886         (mode==MSVCRT__LK_NBRLCK)?"_LK_NBRLCK":
887                           "UNKNOWN");
888
889   if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
890   {
891     FIXME ("Seek failed\n");
892     *MSVCRT__errno() = MSVCRT_EINVAL; /* FIXME */
893     return -1;
894   }
895   if (mode == MSVCRT__LK_LOCK || mode == MSVCRT__LK_RLCK)
896   {
897     int nretry = 10;
898     ret = 1; /* just to satisfy gcc */
899     while (nretry--)
900     {
901       ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
902       if (ret) break;
903       Sleep(1);
904     }
905   }
906   else if (mode == MSVCRT__LK_UNLCK)
907     ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
908   else
909     ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
910   /* FIXME - what about error settings? */
911   return ret ? 0 : -1;
912 }
913
914 /*********************************************************************
915  *              fseek (MSVCRT.@)
916  */
917 int CDECL MSVCRT_fseek(MSVCRT_FILE* file, long offset, int whence)
918 {
919   /* Flush output if needed */
920   if(file->_flag & MSVCRT__IOWRT)
921         msvcrt_flush_buffer(file);
922
923   if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) {
924         offset -= file->_cnt;
925         if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT) {
926                 /* Black magic correction for CR removal */
927                 int i;
928                 for (i=0; i<file->_cnt; i++) {
929                         if (file->_ptr[i] == '\n')
930                                 offset--;
931                 }
932         }
933   }
934   /* Discard buffered input */
935   file->_cnt = 0;
936   file->_ptr = file->_base;
937   /* Reset direction of i/o */
938   if(file->_flag & MSVCRT__IORW) {
939         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
940   }
941   /* Clear end of file flag */
942   file->_flag &= ~MSVCRT__IOEOF;
943   return (MSVCRT__lseek(file->_file,offset,whence) == -1)?-1:0;
944 }
945
946 /*********************************************************************
947  *              _chsize (MSVCRT.@)
948  */
949 int CDECL _chsize(int fd, long size)
950 {
951     LONG cur, pos;
952     HANDLE handle;
953     BOOL ret = FALSE;
954
955     TRACE("(fd=%d, size=%ld)\n", fd, size);
956
957     LOCK_FILES();
958
959     handle = msvcrt_fdtoh(fd);
960     if (handle != INVALID_HANDLE_VALUE)
961     {
962         /* save the current file pointer */
963         cur = MSVCRT__lseek(fd, 0, SEEK_CUR);
964         if (cur >= 0)
965         {
966             pos = MSVCRT__lseek(fd, size, SEEK_SET);
967             if (pos >= 0)
968             {
969                 ret = SetEndOfFile(handle);
970                 if (!ret) msvcrt_set_errno(GetLastError());
971             }
972
973             /* restore the file pointer */
974             MSVCRT__lseek(fd, cur, SEEK_SET);
975         }
976     }
977
978     UNLOCK_FILES();
979     return ret ? 0 : -1;
980 }
981
982 /*********************************************************************
983  *              clearerr (MSVCRT.@)
984  */
985 void CDECL MSVCRT_clearerr(MSVCRT_FILE* file)
986 {
987   TRACE(":file (%p) fd (%d)\n",file,file->_file);
988   file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
989 }
990
991 /*********************************************************************
992  *              rewind (MSVCRT.@)
993  */
994 void CDECL MSVCRT_rewind(MSVCRT_FILE* file)
995 {
996   TRACE(":file (%p) fd (%d)\n",file,file->_file);
997   MSVCRT_fseek(file, 0L, SEEK_SET);
998   MSVCRT_clearerr(file);
999 }
1000
1001 static int msvcrt_get_flags(const MSVCRT_wchar_t* mode, int *open_flags, int* stream_flags)
1002 {
1003   int plus = strchrW(mode, '+') != NULL;
1004
1005   switch(*mode++)
1006   {
1007   case 'R': case 'r':
1008     *open_flags = plus ? MSVCRT__O_RDWR : MSVCRT__O_RDONLY;
1009     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOREAD;
1010     break;
1011   case 'W': case 'w':
1012     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_TRUNC | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1013     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1014     break;
1015   case 'A': case 'a':
1016     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_APPEND | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1017     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1018     break;
1019   default:
1020     return -1;
1021   }
1022
1023   while (*mode)
1024     switch (*mode++)
1025     {
1026     case 'B': case 'b':
1027       *open_flags |=  MSVCRT__O_BINARY;
1028       *open_flags &= ~MSVCRT__O_TEXT;
1029       break;
1030     case 'T': case 't':
1031       *open_flags |=  MSVCRT__O_TEXT;
1032       *open_flags &= ~MSVCRT__O_BINARY;
1033       break;
1034     case '+':
1035       break;
1036     default:
1037       FIXME(":unknown flag %c not supported\n",mode[-1]);
1038     }
1039   return 0;
1040 }
1041
1042 /*********************************************************************
1043  *              _fdopen (MSVCRT.@)
1044  */
1045 MSVCRT_FILE* CDECL MSVCRT__fdopen(int fd, const char *mode)
1046 {
1047     MSVCRT_FILE *ret;
1048     MSVCRT_wchar_t *modeW = NULL;
1049
1050     if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1051
1052     ret = MSVCRT__wfdopen(fd, modeW);
1053
1054     MSVCRT_free(modeW);
1055     return ret;
1056 }
1057
1058 /*********************************************************************
1059  *              _wfdopen (MSVCRT.@)
1060  */
1061 MSVCRT_FILE* CDECL MSVCRT__wfdopen(int fd, const MSVCRT_wchar_t *mode)
1062 {
1063   int open_flags, stream_flags;
1064   MSVCRT_FILE* file;
1065
1066   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1067
1068   LOCK_FILES();
1069   if (!(file = msvcrt_alloc_fp()))
1070     file = NULL;
1071   else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1072   {
1073     file->_flag = 0;
1074     file = NULL;
1075   }
1076   else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1077   UNLOCK_FILES();
1078
1079   return file;
1080 }
1081
1082 /*********************************************************************
1083  *              _filelength (MSVCRT.@)
1084  */
1085 LONG CDECL MSVCRT__filelength(int fd)
1086 {
1087   LONG curPos = MSVCRT__lseek(fd, 0, SEEK_CUR);
1088   if (curPos != -1)
1089   {
1090     LONG endPos = MSVCRT__lseek(fd, 0, SEEK_END);
1091     if (endPos != -1)
1092     {
1093       if (endPos != curPos)
1094         MSVCRT__lseek(fd, curPos, SEEK_SET);
1095       return endPos;
1096     }
1097   }
1098   return -1;
1099 }
1100
1101 /*********************************************************************
1102  *              _filelengthi64 (MSVCRT.@)
1103  */
1104 __int64 CDECL MSVCRT__filelengthi64(int fd)
1105 {
1106   __int64 curPos = MSVCRT__lseeki64(fd, 0, SEEK_CUR);
1107   if (curPos != -1)
1108   {
1109     __int64 endPos = MSVCRT__lseeki64(fd, 0, SEEK_END);
1110     if (endPos != -1)
1111     {
1112       if (endPos != curPos)
1113         MSVCRT__lseeki64(fd, curPos, SEEK_SET);
1114       return endPos;
1115     }
1116   }
1117   return -1;
1118 }
1119
1120 /*********************************************************************
1121  *              _fileno (MSVCRT.@)
1122  */
1123 int CDECL MSVCRT__fileno(MSVCRT_FILE* file)
1124 {
1125   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1126   return file->_file;
1127 }
1128
1129 /*********************************************************************
1130  *              _fstat64 (MSVCRT.@)
1131  */
1132 int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf)
1133 {
1134   DWORD dw;
1135   DWORD type;
1136   BY_HANDLE_FILE_INFORMATION hfi;
1137   HANDLE hand = msvcrt_fdtoh(fd);
1138
1139   TRACE(":fd (%d) stat (%p)\n",fd,buf);
1140   if (hand == INVALID_HANDLE_VALUE)
1141     return -1;
1142
1143   if (!buf)
1144   {
1145     WARN(":failed-NULL buf\n");
1146     msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1147     return -1;
1148   }
1149
1150   memset(&hfi, 0, sizeof(hfi));
1151   memset(buf, 0, sizeof(struct MSVCRT__stat64));
1152   type = GetFileType(hand);
1153   if (type == FILE_TYPE_PIPE)
1154   {
1155     buf->st_dev = buf->st_rdev = fd;
1156     buf->st_mode = S_IFIFO;
1157     buf->st_nlink = 1;
1158   }
1159   else if (type == FILE_TYPE_CHAR)
1160   {
1161     buf->st_dev = buf->st_rdev = fd;
1162     buf->st_mode = S_IFCHR;
1163     buf->st_nlink = 1;
1164   }
1165   else /* FILE_TYPE_DISK etc. */
1166   {
1167     if (!GetFileInformationByHandle(hand, &hfi))
1168     {
1169       WARN(":failed-last error (%d)\n",GetLastError());
1170       msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1171       return -1;
1172     }
1173     buf->st_mode = S_IFREG | 0444;
1174     if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1175       buf->st_mode |= 0222;
1176     buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1177     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1178     buf->st_atime = dw;
1179     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1180     buf->st_mtime = buf->st_ctime = dw;
1181     buf->st_nlink = hfi.nNumberOfLinks;
1182   }
1183   TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
1184    buf->st_mode);
1185   return 0;
1186 }
1187
1188 /*********************************************************************
1189  *              _fstati64 (MSVCRT.@)
1190  */
1191 int CDECL MSVCRT__fstati64(int fd, struct MSVCRT__stati64* buf)
1192 {
1193   int ret;
1194   struct MSVCRT__stat64 buf64;
1195
1196   ret = MSVCRT__fstat64(fd, &buf64);
1197   if (!ret)
1198     msvcrt_stat64_to_stati64(&buf64, buf);
1199   return ret;
1200 }
1201
1202 /*********************************************************************
1203  *              _fstat (MSVCRT.@)
1204  */
1205 int CDECL MSVCRT__fstat(int fd, struct MSVCRT__stat* buf)
1206 { int ret;
1207   struct MSVCRT__stat64 buf64;
1208
1209   ret = MSVCRT__fstat64(fd, &buf64);
1210   if (!ret)
1211       msvcrt_stat64_to_stat(&buf64, buf);
1212   return ret;
1213 }
1214
1215 /*********************************************************************
1216  *              _futime (MSVCRT.@)
1217  */
1218 int CDECL _futime(int fd, struct MSVCRT__utimbuf *t)
1219 {
1220   HANDLE hand = msvcrt_fdtoh(fd);
1221   FILETIME at, wt;
1222
1223   if (!t)
1224   {
1225     MSVCRT_time_t currTime;
1226     MSVCRT_time(&currTime);
1227     RtlSecondsSince1970ToTime(currTime, (LARGE_INTEGER *)&at);
1228     wt = at;
1229   }
1230   else
1231   {
1232     RtlSecondsSince1970ToTime(t->actime, (LARGE_INTEGER *)&at);
1233     if (t->actime == t->modtime)
1234       wt = at;
1235     else
1236       RtlSecondsSince1970ToTime(t->modtime, (LARGE_INTEGER *)&wt);
1237   }
1238
1239   if (!SetFileTime(hand, NULL, &at, &wt))
1240   {
1241     msvcrt_set_errno(GetLastError());
1242     return -1 ;
1243   }
1244   return 0;
1245 }
1246
1247 /*********************************************************************
1248  *              _get_osfhandle (MSVCRT.@)
1249  */
1250 MSVCRT_intptr_t CDECL _get_osfhandle(int fd)
1251 {
1252   HANDLE hand = msvcrt_fdtoh(fd);
1253   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1254
1255   return (MSVCRT_intptr_t)hand;
1256 }
1257
1258 /*********************************************************************
1259  *              _isatty (MSVCRT.@)
1260  */
1261 int CDECL _isatty(int fd)
1262 {
1263   HANDLE hand = msvcrt_fdtoh(fd);
1264
1265   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1266   if (hand == INVALID_HANDLE_VALUE)
1267     return 0;
1268
1269   return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
1270 }
1271
1272 /*********************************************************************
1273  *              _mktemp (MSVCRT.@)
1274  */
1275 char * CDECL _mktemp(char *pattern)
1276 {
1277   int numX = 0;
1278   char *retVal = pattern;
1279   int id;
1280   char letter = 'a';
1281
1282   while(*pattern)
1283     numX = (*pattern++ == 'X')? numX + 1 : 0;
1284   if (numX < 5)
1285     return NULL;
1286   pattern--;
1287   id = GetCurrentProcessId();
1288   numX = 6;
1289   while(numX--)
1290   {
1291     int tempNum = id / 10;
1292     *pattern-- = id - (tempNum * 10) + '0';
1293     id = tempNum;
1294   }
1295   pattern++;
1296   do
1297   {
1298     *pattern = letter++;
1299     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
1300         GetLastError() == ERROR_FILE_NOT_FOUND)
1301       return retVal;
1302   } while(letter <= 'z');
1303   return NULL;
1304 }
1305
1306 /*********************************************************************
1307  *              _wmktemp (MSVCRT.@)
1308  */
1309 MSVCRT_wchar_t * CDECL _wmktemp(MSVCRT_wchar_t *pattern)
1310 {
1311   int numX = 0;
1312   MSVCRT_wchar_t *retVal = pattern;
1313   int id;
1314   MSVCRT_wchar_t letter = 'a';
1315
1316   while(*pattern)
1317     numX = (*pattern++ == 'X')? numX + 1 : 0;
1318   if (numX < 5)
1319     return NULL;
1320   pattern--;
1321   id = GetCurrentProcessId();
1322   numX = 6;
1323   while(numX--)
1324   {
1325     int tempNum = id / 10;
1326     *pattern-- = id - (tempNum * 10) + '0';
1327     id = tempNum;
1328   }
1329   pattern++;
1330   do
1331   {
1332     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1333         GetLastError() == ERROR_FILE_NOT_FOUND)
1334       return retVal;
1335     *pattern = letter++;
1336   } while(letter != '|');
1337   return NULL;
1338 }
1339
1340 static unsigned split_oflags(unsigned oflags)
1341 {
1342     int         wxflags = 0;
1343     unsigned unsupp; /* until we support everything */
1344
1345     if (oflags & MSVCRT__O_APPEND)              wxflags |= WX_APPEND;
1346     if (oflags & MSVCRT__O_BINARY)              {/* Nothing to do */}
1347     else if (oflags & MSVCRT__O_TEXT)           wxflags |= WX_TEXT;
1348     else if (*__p__fmode() & MSVCRT__O_BINARY)  {/* Nothing to do */}
1349     else                                        wxflags |= WX_TEXT; /* default to TEXT*/
1350     if (oflags & MSVCRT__O_NOINHERIT)           wxflags |= WX_DONTINHERIT;
1351
1352     if ((unsupp = oflags & ~(
1353                     MSVCRT__O_BINARY|MSVCRT__O_TEXT|MSVCRT__O_APPEND|
1354                     MSVCRT__O_TRUNC|MSVCRT__O_EXCL|MSVCRT__O_CREAT|
1355                     MSVCRT__O_RDWR|MSVCRT__O_WRONLY|MSVCRT__O_TEMPORARY|
1356                     MSVCRT__O_NOINHERIT|
1357                     MSVCRT__O_SEQUENTIAL|MSVCRT__O_RANDOM|MSVCRT__O_SHORT_LIVED
1358                     )))
1359         ERR(":unsupported oflags 0x%04x\n",unsupp);
1360
1361     return wxflags;
1362 }
1363
1364 /*********************************************************************
1365  *              _pipe (MSVCRT.@)
1366  */
1367 int CDECL MSVCRT__pipe(int *pfds, unsigned int psize, int textmode)
1368 {
1369   int ret = -1;
1370   SECURITY_ATTRIBUTES sa;
1371   HANDLE readHandle, writeHandle;
1372
1373   if (!pfds)
1374   {
1375     *MSVCRT__errno() = MSVCRT_EINVAL;
1376     return -1;
1377   }
1378
1379   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1380   sa.bInheritHandle = !(textmode & MSVCRT__O_NOINHERIT);
1381   sa.lpSecurityDescriptor = NULL;
1382   if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1383   {
1384     unsigned int wxflags = split_oflags(textmode);
1385     int fd;
1386
1387     LOCK_FILES();
1388     fd = msvcrt_alloc_fd(readHandle, wxflags);
1389     if (fd != -1)
1390     {
1391       pfds[0] = fd;
1392       fd = msvcrt_alloc_fd(writeHandle, wxflags);
1393       if (fd != -1)
1394       {
1395         pfds[1] = fd;
1396         ret = 0;
1397       }
1398       else
1399       {
1400         MSVCRT__close(pfds[0]);
1401         CloseHandle(writeHandle);
1402         *MSVCRT__errno() = MSVCRT_EMFILE;
1403       }
1404     }
1405     else
1406     {
1407       CloseHandle(readHandle);
1408       CloseHandle(writeHandle);
1409       *MSVCRT__errno() = MSVCRT_EMFILE;
1410     }
1411     UNLOCK_FILES();
1412   }
1413   else
1414     msvcrt_set_errno(GetLastError());
1415
1416   return ret;
1417 }
1418
1419 /*********************************************************************
1420  *              _sopen (MSVCRT.@)
1421  */
1422 int CDECL MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
1423 {
1424   __ms_va_list ap;
1425   int pmode;
1426   DWORD access = 0, creation = 0, attrib;
1427   DWORD sharing;
1428   int wxflag = 0, fd;
1429   HANDLE hand;
1430   SECURITY_ATTRIBUTES sa;
1431
1432
1433   TRACE(":file (%s) oflags: 0x%04x shflags: 0x%04x\n",
1434         path, oflags, shflags);
1435
1436   wxflag = split_oflags(oflags);
1437   switch (oflags & (MSVCRT__O_RDONLY | MSVCRT__O_WRONLY | MSVCRT__O_RDWR))
1438   {
1439   case MSVCRT__O_RDONLY: access |= GENERIC_READ; break;
1440   case MSVCRT__O_WRONLY: access |= GENERIC_WRITE; break;
1441   case MSVCRT__O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1442   }
1443
1444   if (oflags & MSVCRT__O_CREAT)
1445   {
1446     __ms_va_start(ap, shflags);
1447     pmode = va_arg(ap, int);
1448     __ms_va_end(ap);
1449
1450     if(pmode & ~(MSVCRT__S_IREAD | MSVCRT__S_IWRITE))
1451       FIXME(": pmode 0x%04x ignored\n", pmode);
1452     else
1453       WARN(": pmode 0x%04x ignored\n", pmode);
1454
1455     if (oflags & MSVCRT__O_EXCL)
1456       creation = CREATE_NEW;
1457     else if (oflags & MSVCRT__O_TRUNC)
1458       creation = CREATE_ALWAYS;
1459     else
1460       creation = OPEN_ALWAYS;
1461   }
1462   else  /* no MSVCRT__O_CREAT */
1463   {
1464     if (oflags & MSVCRT__O_TRUNC)
1465       creation = TRUNCATE_EXISTING;
1466     else
1467       creation = OPEN_EXISTING;
1468   }
1469   
1470   switch( shflags )
1471   {
1472     case MSVCRT__SH_DENYRW:
1473       sharing = 0L;
1474       break;
1475     case MSVCRT__SH_DENYWR:
1476       sharing = FILE_SHARE_READ;
1477       break;
1478     case MSVCRT__SH_DENYRD:
1479       sharing = FILE_SHARE_WRITE;
1480       break;
1481     case MSVCRT__SH_DENYNO:
1482       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1483       break;
1484     default:
1485       ERR( "Unhandled shflags 0x%x\n", shflags );
1486       return -1;
1487   }
1488   attrib = FILE_ATTRIBUTE_NORMAL;
1489
1490   if (oflags & MSVCRT__O_TEMPORARY)
1491   {
1492       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1493       access |= DELETE;
1494       sharing |= FILE_SHARE_DELETE;
1495   }
1496
1497   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1498   sa.lpSecurityDescriptor = NULL;
1499   sa.bInheritHandle       = (oflags & MSVCRT__O_NOINHERIT) ? FALSE : TRUE;
1500
1501   hand = CreateFileA(path, access, sharing, &sa, creation, attrib, 0);
1502
1503   if (hand == INVALID_HANDLE_VALUE)  {
1504     WARN(":failed-last error (%d)\n",GetLastError());
1505     msvcrt_set_errno(GetLastError());
1506     return -1;
1507   }
1508
1509   fd = msvcrt_alloc_fd(hand, wxflag);
1510
1511   TRACE(":fd (%d) handle (%p)\n",fd, hand);
1512   return fd;
1513 }
1514
1515 /*********************************************************************
1516  *              _wsopen (MSVCRT.@)
1517  */
1518 int CDECL MSVCRT__wsopen( const MSVCRT_wchar_t* path, int oflags, int shflags, ... )
1519 {
1520   __ms_va_list ap;
1521   int pmode;
1522   DWORD access = 0, creation = 0, attrib;
1523   DWORD sharing;
1524   int wxflag = 0, fd;
1525   HANDLE hand;
1526   SECURITY_ATTRIBUTES sa;
1527
1528
1529   TRACE(":file (%s) oflags: 0x%04x shflags: 0x%04x\n",
1530         debugstr_w(path), oflags, shflags);
1531
1532   wxflag = split_oflags(oflags);
1533   switch (oflags & (MSVCRT__O_RDONLY | MSVCRT__O_WRONLY | MSVCRT__O_RDWR))
1534   {
1535   case MSVCRT__O_RDONLY: access |= GENERIC_READ; break;
1536   case MSVCRT__O_WRONLY: access |= GENERIC_WRITE; break;
1537   case MSVCRT__O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1538   }
1539
1540   if (oflags & MSVCRT__O_CREAT)
1541   {
1542     __ms_va_start(ap, shflags);
1543     pmode = va_arg(ap, int);
1544     __ms_va_end(ap);
1545
1546     if(pmode & ~(MSVCRT__S_IREAD | MSVCRT__S_IWRITE))
1547       FIXME(": pmode 0x%04x ignored\n", pmode);
1548     else
1549       WARN(": pmode 0x%04x ignored\n", pmode);
1550
1551     if (oflags & MSVCRT__O_EXCL)
1552       creation = CREATE_NEW;
1553     else if (oflags & MSVCRT__O_TRUNC)
1554       creation = CREATE_ALWAYS;
1555     else
1556       creation = OPEN_ALWAYS;
1557   }
1558   else  /* no MSVCRT__O_CREAT */
1559   {
1560     if (oflags & MSVCRT__O_TRUNC)
1561       creation = TRUNCATE_EXISTING;
1562     else
1563       creation = OPEN_EXISTING;
1564   }
1565
1566   switch( shflags )
1567   {
1568     case MSVCRT__SH_DENYRW:
1569       sharing = 0L;
1570       break;
1571     case MSVCRT__SH_DENYWR:
1572       sharing = FILE_SHARE_READ;
1573       break;
1574     case MSVCRT__SH_DENYRD:
1575       sharing = FILE_SHARE_WRITE;
1576       break;
1577     case MSVCRT__SH_DENYNO:
1578       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1579       break;
1580     default:
1581       ERR( "Unhandled shflags 0x%x\n", shflags );
1582       return -1;
1583   }
1584   attrib = FILE_ATTRIBUTE_NORMAL;
1585
1586   if (oflags & MSVCRT__O_TEMPORARY)
1587   {
1588       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1589       access |= DELETE;
1590       sharing |= FILE_SHARE_DELETE;
1591   }
1592
1593   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1594   sa.lpSecurityDescriptor = NULL;
1595   sa.bInheritHandle       = (oflags & MSVCRT__O_NOINHERIT) ? FALSE : TRUE;
1596
1597   hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1598
1599   if (hand == INVALID_HANDLE_VALUE)  {
1600     WARN(":failed-last error (%d)\n",GetLastError());
1601     msvcrt_set_errno(GetLastError());
1602     return -1;
1603   }
1604
1605   fd = msvcrt_alloc_fd(hand, wxflag);
1606
1607   TRACE(":fd (%d) handle (%p)\n",fd, hand);
1608   return fd;
1609 }
1610
1611 /*********************************************************************
1612  *              _open (MSVCRT.@)
1613  */
1614 int CDECL MSVCRT__open( const char *path, int flags, ... )
1615 {
1616   __ms_va_list ap;
1617
1618   if (flags & MSVCRT__O_CREAT)
1619   {
1620     int pmode;
1621     __ms_va_start(ap, flags);
1622     pmode = va_arg(ap, int);
1623     __ms_va_end(ap);
1624     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO, pmode );
1625   }
1626   else
1627     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO);
1628 }
1629
1630 /*********************************************************************
1631  *              _wopen (MSVCRT.@)
1632  */
1633 int CDECL _wopen(const MSVCRT_wchar_t *path,int flags,...)
1634 {
1635   __ms_va_list ap;
1636
1637   if (flags & MSVCRT__O_CREAT)
1638   {
1639     int pmode;
1640     __ms_va_start(ap, flags);
1641     pmode = va_arg(ap, int);
1642     __ms_va_end(ap);
1643     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO, pmode );
1644   }
1645   else
1646     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO);
1647 }
1648
1649 /*********************************************************************
1650  *              _creat (MSVCRT.@)
1651  */
1652 int CDECL MSVCRT__creat(const char *path, int flags)
1653 {
1654   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
1655   return MSVCRT__open(path, usedFlags);
1656 }
1657
1658 /*********************************************************************
1659  *              _wcreat (MSVCRT.@)
1660  */
1661 int CDECL _wcreat(const MSVCRT_wchar_t *path, int flags)
1662 {
1663   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
1664   return _wopen(path, usedFlags);
1665 }
1666
1667 /*********************************************************************
1668  *              _open_osfhandle (MSVCRT.@)
1669  */
1670 int CDECL _open_osfhandle(MSVCRT_intptr_t handle, int oflags)
1671 {
1672   int fd;
1673
1674   /* MSVCRT__O_RDONLY (0) always matches, so set the read flag
1675    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
1676    * file, so set the write flag. It also only sets MSVCRT__O_TEXT if it wants
1677    * text - it never sets MSVCRT__O_BINARY.
1678    */
1679   /* don't let split_oflags() decide the mode if no mode is passed */
1680   if (!(oflags & (MSVCRT__O_BINARY | MSVCRT__O_TEXT)))
1681       oflags |= MSVCRT__O_BINARY;
1682
1683   fd = msvcrt_alloc_fd((HANDLE)handle, split_oflags(oflags));
1684   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, oflags);
1685   return fd;
1686 }
1687
1688 /*********************************************************************
1689  *              _rmtmp (MSVCRT.@)
1690  */
1691 int CDECL _rmtmp(void)
1692 {
1693   int num_removed = 0, i;
1694
1695   LOCK_FILES();
1696   for (i = 3; i < MSVCRT_stream_idx; i++)
1697     if (MSVCRT_fstreams[i] && MSVCRT_fstreams[i]->_tmpfname)
1698     {
1699       MSVCRT_fclose(MSVCRT_fstreams[i]);
1700       num_removed++;
1701     }
1702   UNLOCK_FILES();
1703
1704   if (num_removed)
1705     TRACE(":removed (%d) temp files\n",num_removed);
1706   return num_removed;
1707 }
1708
1709 /*********************************************************************
1710  * (internal) read_i
1711  */
1712 static int read_i(int fd, void *buf, unsigned int count)
1713 {
1714   DWORD num_read;
1715   char *bufstart = buf;
1716   HANDLE hand = msvcrt_fdtoh(fd);
1717
1718   if (MSVCRT_fdesc[fd].wxflag & WX_READEOF) {
1719      MSVCRT_fdesc[fd].wxflag |= WX_ATEOF;
1720      TRACE("already at EOF, returning 0\n");
1721      return 0;
1722   }
1723   /* Don't trace small reads, it gets *very* annoying */
1724   if (count > 4)
1725     TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
1726   if (hand == INVALID_HANDLE_VALUE)
1727     return -1;
1728
1729   /* Reading single bytes in O_TEXT mode makes things slow
1730    * So read big chunks
1731    */
1732     if (ReadFile(hand, bufstart, count, &num_read, NULL))
1733     {
1734         if (MSVCRT_fdesc[fd].wxflag & WX_TEXT)
1735         {
1736             DWORD i, j;
1737             for (i=0, j=0; i<num_read; i++)
1738             {
1739                 /* in text mode, a ctrl-z signals EOF */
1740                 if (bufstart[i] == 0x1a)
1741                 {
1742                     MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
1743                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
1744                     break;
1745                 }
1746                 /* in text mode, strip \r if followed by \n.
1747                  * BUG: should save state across calls somehow, so CR LF that
1748                  * straddles buffer boundary gets recognized properly?
1749                  */
1750                 if ((bufstart[i] != '\r')
1751                 ||  ((i+1) < num_read && bufstart[i+1] != '\n'))
1752                     bufstart[j++] = bufstart[i];
1753             }
1754             num_read = j;
1755         }
1756         if (count != 0 && num_read == 0)
1757         {
1758             MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
1759             TRACE(":EOF %s\n",debugstr_an(buf,num_read));
1760         }
1761     }
1762     else
1763     {
1764         if (GetLastError() == ERROR_BROKEN_PIPE)
1765         {
1766             TRACE(":end-of-pipe\n");
1767             MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
1768             return 0;
1769         }
1770         else
1771         {
1772             TRACE(":failed-last error (%d)\n",GetLastError());
1773             return -1;
1774         }
1775     }
1776
1777   if (count > 4)
1778       TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
1779   return num_read;
1780 }
1781
1782 /*********************************************************************
1783  *              _read (MSVCRT.@)
1784  */
1785 int CDECL MSVCRT__read(int fd, void *buf, unsigned int count)
1786 {
1787   int num_read;
1788   num_read = read_i(fd, buf, count);
1789   return num_read;
1790 }
1791
1792 /*********************************************************************
1793  *              _setmode (MSVCRT.@)
1794  */
1795 int CDECL _setmode(int fd,int mode)
1796 {
1797   int ret = MSVCRT_fdesc[fd].wxflag & WX_TEXT ? MSVCRT__O_TEXT : MSVCRT__O_BINARY;
1798   if (mode & (~(MSVCRT__O_TEXT|MSVCRT__O_BINARY)))
1799     FIXME("fd (%d) mode (0x%08x) unknown\n",fd,mode);
1800   if ((mode & MSVCRT__O_TEXT) == MSVCRT__O_TEXT)
1801     MSVCRT_fdesc[fd].wxflag |= WX_TEXT;
1802   else
1803     MSVCRT_fdesc[fd].wxflag &= ~WX_TEXT;
1804   return ret;
1805 }
1806
1807 /*********************************************************************
1808  *              _stat64 (MSVCRT.@)
1809  */
1810 int CDECL MSVCRT__stat64(const char* path, struct MSVCRT__stat64 * buf)
1811 {
1812   DWORD dw;
1813   WIN32_FILE_ATTRIBUTE_DATA hfi;
1814   unsigned short mode = ALL_S_IREAD;
1815   int plen;
1816
1817   TRACE(":file (%s) buf(%p)\n",path,buf);
1818
1819   if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
1820   {
1821       TRACE("failed (%d)\n",GetLastError());
1822       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1823       return -1;
1824   }
1825
1826   memset(buf,0,sizeof(struct MSVCRT__stat64));
1827
1828   /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
1829      Bon 011120: This FIXME seems incorrect
1830                  Also a letter as first char isn't enough to be classified
1831                  as a drive letter
1832   */
1833   if (isalpha(*path)&& (*(path+1)==':'))
1834     buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
1835   else
1836     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1837
1838   plen = strlen(path);
1839
1840   /* Dir, or regular file? */
1841   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1842       (path[plen-1] == '\\'))
1843     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
1844   else
1845   {
1846     mode |= MSVCRT__S_IFREG;
1847     /* executable? */
1848     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
1849     {
1850       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
1851                                  (tolower(path[plen-3]) << 16);
1852       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
1853           mode |= ALL_S_IEXEC;
1854     }
1855   }
1856
1857   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1858     mode |= ALL_S_IWRITE;
1859
1860   buf->st_mode  = mode;
1861   buf->st_nlink = 1;
1862   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1863   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1864   buf->st_atime = dw;
1865   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1866   buf->st_mtime = buf->st_ctime = dw;
1867   TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
1868         (long)(buf->st_size >> 32),(long)buf->st_size,
1869         (long)buf->st_atime,(long)buf->st_mtime,(long)buf->st_ctime);
1870   return 0;
1871 }
1872
1873 /*********************************************************************
1874  *              _stati64 (MSVCRT.@)
1875  */
1876 int CDECL MSVCRT__stati64(const char* path, struct MSVCRT__stati64 * buf)
1877 {
1878   int ret;
1879   struct MSVCRT__stat64 buf64;
1880
1881   ret = MSVCRT__stat64(path, &buf64);
1882   if (!ret)
1883     msvcrt_stat64_to_stati64(&buf64, buf);
1884   return ret;
1885 }
1886
1887 /*********************************************************************
1888  *              _stat (MSVCRT.@)
1889  */
1890 int CDECL MSVCRT__stat(const char* path, struct MSVCRT__stat * buf)
1891 { int ret;
1892   struct MSVCRT__stat64 buf64;
1893
1894   ret = MSVCRT__stat64( path, &buf64);
1895   if (!ret)
1896       msvcrt_stat64_to_stat(&buf64, buf);
1897   return ret;
1898 }
1899
1900 /*********************************************************************
1901  *              _wstat64 (MSVCRT.@)
1902  */
1903 int CDECL MSVCRT__wstat64(const MSVCRT_wchar_t* path, struct MSVCRT__stat64 * buf)
1904 {
1905   DWORD dw;
1906   WIN32_FILE_ATTRIBUTE_DATA hfi;
1907   unsigned short mode = ALL_S_IREAD;
1908   int plen;
1909
1910   TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
1911
1912   if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
1913   {
1914       TRACE("failed (%d)\n",GetLastError());
1915       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1916       return -1;
1917   }
1918
1919   memset(buf,0,sizeof(struct MSVCRT__stat64));
1920
1921   /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
1922   if (MSVCRT_iswalpha(*path))
1923     buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
1924   else
1925     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1926
1927   plen = strlenW(path);
1928
1929   /* Dir, or regular file? */
1930   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1931       (path[plen-1] == '\\'))
1932     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
1933   else
1934   {
1935     mode |= MSVCRT__S_IFREG;
1936     /* executable? */
1937     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
1938     {
1939       ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
1940                                ((ULONGLONG)tolowerW(path[plen-3]) << 32);
1941       if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
1942         mode |= ALL_S_IEXEC;
1943     }
1944   }
1945
1946   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1947     mode |= ALL_S_IWRITE;
1948
1949   buf->st_mode  = mode;
1950   buf->st_nlink = 1;
1951   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1952   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1953   buf->st_atime = dw;
1954   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1955   buf->st_mtime = buf->st_ctime = dw;
1956   TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
1957         (long)(buf->st_size >> 32),(long)buf->st_size,
1958         (long)buf->st_atime,(long)buf->st_mtime,(long)buf->st_ctime);
1959   return 0;
1960 }
1961
1962 /*********************************************************************
1963  *              _wstati64 (MSVCRT.@)
1964  */
1965 int CDECL MSVCRT__wstati64(const MSVCRT_wchar_t* path, struct MSVCRT__stati64 * buf)
1966 {
1967   int ret;
1968   struct MSVCRT__stat64 buf64;
1969
1970   ret = MSVCRT__wstat64(path, &buf64);
1971   if (!ret)
1972     msvcrt_stat64_to_stati64(&buf64, buf);
1973   return ret;
1974 }
1975
1976 /*********************************************************************
1977  *              _wstat (MSVCRT.@)
1978  */
1979 int CDECL MSVCRT__wstat(const MSVCRT_wchar_t* path, struct MSVCRT__stat * buf)
1980 {
1981   int ret;
1982   struct MSVCRT__stat64 buf64;
1983
1984   ret = MSVCRT__wstat64( path, &buf64 );
1985   if (!ret) msvcrt_stat64_to_stat(&buf64, buf);
1986   return ret;
1987 }
1988
1989 /*********************************************************************
1990  *              _tell (MSVCRT.@)
1991  */
1992 long CDECL _tell(int fd)
1993 {
1994   return MSVCRT__lseek(fd, 0, SEEK_CUR);
1995 }
1996
1997 /*********************************************************************
1998  *              _telli64 (MSVCRT.@)
1999  */
2000 __int64 CDECL _telli64(int fd)
2001 {
2002   return MSVCRT__lseeki64(fd, 0, SEEK_CUR);
2003 }
2004
2005 /*********************************************************************
2006  *              _tempnam (MSVCRT.@)
2007  */
2008 char * CDECL _tempnam(const char *dir, const char *prefix)
2009 {
2010   char tmpbuf[MAX_PATH];
2011   const char *tmp_dir = MSVCRT_getenv("TMP");
2012
2013   if (tmp_dir) dir = tmp_dir;
2014
2015   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2016   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2017   {
2018     TRACE("got name (%s)\n",tmpbuf);
2019     DeleteFileA(tmpbuf);
2020     return _strdup(tmpbuf);
2021   }
2022   TRACE("failed (%d)\n",GetLastError());
2023   return NULL;
2024 }
2025
2026 /*********************************************************************
2027  *              _wtempnam (MSVCRT.@)
2028  */
2029 MSVCRT_wchar_t * CDECL _wtempnam(const MSVCRT_wchar_t *dir, const MSVCRT_wchar_t *prefix)
2030 {
2031   MSVCRT_wchar_t tmpbuf[MAX_PATH];
2032
2033   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2034   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2035   {
2036     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2037     DeleteFileW(tmpbuf);
2038     return _wcsdup(tmpbuf);
2039   }
2040   TRACE("failed (%d)\n",GetLastError());
2041   return NULL;
2042 }
2043
2044 /*********************************************************************
2045  *              _umask (MSVCRT.@)
2046  */
2047 int CDECL MSVCRT__umask(int umask)
2048 {
2049   int old_umask = MSVCRT_umask;
2050   TRACE("(%d)\n",umask);
2051   MSVCRT_umask = umask;
2052   return old_umask;
2053 }
2054
2055 /*********************************************************************
2056  *              _utime (MSVCRT.@)
2057  */
2058 int CDECL _utime(const char* path, struct MSVCRT__utimbuf *t)
2059 {
2060   int fd = MSVCRT__open(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2061
2062   if (fd > 0)
2063   {
2064     int retVal = _futime(fd, t);
2065     MSVCRT__close(fd);
2066     return retVal;
2067   }
2068   return -1;
2069 }
2070
2071 /*********************************************************************
2072  *              _wutime (MSVCRT.@)
2073  */
2074 int CDECL _wutime(const MSVCRT_wchar_t* path, struct MSVCRT__utimbuf *t)
2075 {
2076   int fd = _wopen(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2077
2078   if (fd > 0)
2079   {
2080     int retVal = _futime(fd, t);
2081     MSVCRT__close(fd);
2082     return retVal;
2083   }
2084   return -1;
2085 }
2086
2087 /*********************************************************************
2088  *              _write (MSVCRT.@)
2089  */
2090 int CDECL MSVCRT__write(int fd, const void* buf, unsigned int count)
2091 {
2092   DWORD num_written;
2093   HANDLE hand = msvcrt_fdtoh(fd);
2094
2095   /* Don't trace small writes, it gets *very* annoying */
2096 #if 0
2097   if (count > 32)
2098     TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2099 #endif
2100   if (hand == INVALID_HANDLE_VALUE)
2101     {
2102       *MSVCRT__errno() = MSVCRT_EBADF;
2103       return -1;
2104     }
2105
2106   /* If appending, go to EOF */
2107   if (MSVCRT_fdesc[fd].wxflag & WX_APPEND)
2108     MSVCRT__lseek(fd, 0, FILE_END);
2109
2110   if (!(MSVCRT_fdesc[fd].wxflag & WX_TEXT))
2111     {
2112       if (WriteFile(hand, buf, count, &num_written, NULL)
2113           &&  (num_written == count))
2114         return num_written;
2115       TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2116        hand, GetLastError());
2117       *MSVCRT__errno() = MSVCRT_ENOSPC;
2118     }
2119   else
2120   {
2121       unsigned int i, j, nr_lf;
2122       char *p = NULL;
2123       const char *q;
2124       const char *s = buf, *buf_start = buf;
2125       /* find number of \n ( without preceding \r ) */
2126       for ( nr_lf=0,i = 0; i <count; i++)
2127       {
2128           if (s[i]== '\n')
2129           {
2130               nr_lf++;
2131               /*if ((i >1) && (s[i-1] == '\r')) nr_lf--; */
2132           }
2133       }
2134       if (nr_lf)
2135       {
2136           if ((q = p = MSVCRT_malloc(count + nr_lf)))
2137           {
2138               for (s = buf, i = 0, j = 0; i < count; i++)
2139               {
2140                   if (s[i]== '\n')
2141                   {
2142                       p[j++] = '\r';
2143                       /*if ((i >1) && (s[i-1] == '\r'))j--;*/
2144                   }
2145                   p[j++] = s[i];
2146               }
2147           }
2148           else
2149           {
2150               FIXME("Malloc failed\n");
2151               nr_lf =0;
2152               q = buf;
2153           }
2154       }
2155       else
2156           q = buf;
2157
2158       if ((WriteFile(hand, q, count+nr_lf, &num_written, NULL) == 0 ) || (num_written != count+nr_lf))
2159       {
2160           TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2161            fd, hand, GetLastError(), num_written);
2162           *MSVCRT__errno() = MSVCRT_ENOSPC;
2163           if(nr_lf)
2164               MSVCRT_free(p);
2165           return s - buf_start;
2166       }
2167       else
2168       {
2169           if(nr_lf)
2170               MSVCRT_free(p);
2171           return count;
2172       }
2173   }
2174   return -1;
2175 }
2176
2177 /*********************************************************************
2178  *              _putw (MSVCRT.@)
2179  */
2180 int CDECL MSVCRT__putw(int val, MSVCRT_FILE* file)
2181 {
2182   int len;
2183   len = MSVCRT__write(file->_file, &val, sizeof(val));
2184   if (len == sizeof(val)) return val;
2185   file->_flag |= MSVCRT__IOERR;
2186   return MSVCRT_EOF;
2187 }
2188
2189 /*********************************************************************
2190  *              fclose (MSVCRT.@)
2191  */
2192 int CDECL MSVCRT_fclose(MSVCRT_FILE* file)
2193 {
2194   int r, flag;
2195
2196   flag = file->_flag;
2197   MSVCRT_free(file->_tmpfname);
2198   file->_tmpfname = NULL;
2199   /* flush stdio buffers */
2200   if(file->_flag & MSVCRT__IOWRT)
2201       MSVCRT_fflush(file);
2202   if(file->_flag & MSVCRT__IOMYBUF)
2203       MSVCRT_free(file->_base);
2204
2205   r=MSVCRT__close(file->_file);
2206
2207   file->_flag = 0;
2208
2209   return ((r == -1) || (flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
2210 }
2211
2212 /*********************************************************************
2213  *              feof (MSVCRT.@)
2214  */
2215 int CDECL MSVCRT_feof(MSVCRT_FILE* file)
2216 {
2217   return file->_flag & MSVCRT__IOEOF;
2218 }
2219
2220 /*********************************************************************
2221  *              ferror (MSVCRT.@)
2222  */
2223 int CDECL MSVCRT_ferror(MSVCRT_FILE* file)
2224 {
2225   return file->_flag & MSVCRT__IOERR;
2226 }
2227
2228 /*********************************************************************
2229  *              _filbuf (MSVCRT.@)
2230  */
2231 int CDECL MSVCRT__filbuf(MSVCRT_FILE* file)
2232 {
2233   /* Allocate buffer if needed */
2234   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF) ) {
2235         msvcrt_alloc_buffer(file);
2236   }
2237   if(!(file->_flag & MSVCRT__IOREAD)) {
2238         if(file->_flag & MSVCRT__IORW) {
2239                 file->_flag |= MSVCRT__IOREAD;
2240         } else {
2241                 return MSVCRT_EOF;
2242         }
2243   }
2244   if(file->_flag & MSVCRT__IONBF) {
2245         unsigned char c;
2246         int r;
2247         if ((r = read_i(file->_file,&c,1)) != 1) {
2248             file->_flag |= (r == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
2249             return MSVCRT_EOF;
2250         }
2251         return c;
2252   } else {
2253         file->_cnt = read_i(file->_file, file->_base, file->_bufsiz);
2254         if(file->_cnt<=0) {
2255             file->_flag |= (file->_cnt == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
2256             file->_cnt = 0;
2257             return MSVCRT_EOF;
2258         }
2259         file->_cnt--;
2260         file->_ptr = file->_base+1;
2261         return *(unsigned char *)file->_base;
2262   }
2263 }
2264
2265 /*********************************************************************
2266  *              fgetc (MSVCRT.@)
2267  */
2268 int CDECL MSVCRT_fgetc(MSVCRT_FILE* file)
2269 {
2270   unsigned char *i;
2271   unsigned int j;
2272   if (file->_cnt>0) {
2273     file->_cnt--;
2274     i = (unsigned char *)file->_ptr++;
2275     j = *i;
2276   } else
2277     j = MSVCRT__filbuf(file);
2278   return j;
2279 }
2280
2281 /*********************************************************************
2282  *              _fgetchar (MSVCRT.@)
2283  */
2284 int CDECL _fgetchar(void)
2285 {
2286   return MSVCRT_fgetc(MSVCRT_stdin);
2287 }
2288
2289 /*********************************************************************
2290  *              fgets (MSVCRT.@)
2291  */
2292 char * CDECL MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
2293 {
2294   int    cc = MSVCRT_EOF;
2295   char * buf_start = s;
2296
2297   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2298         file,file->_file,s,size);
2299
2300   while ((size >1) && (cc = MSVCRT_fgetc(file)) != MSVCRT_EOF && cc != '\n')
2301     {
2302       *s++ = (char)cc;
2303       size --;
2304     }
2305   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
2306   {
2307     TRACE(":nothing read\n");
2308     return NULL;
2309   }
2310   if ((cc != MSVCRT_EOF) && (size > 1))
2311     *s++ = cc;
2312   *s = '\0';
2313   TRACE(":got %s\n", debugstr_a(buf_start));
2314   return buf_start;
2315 }
2316
2317 /*********************************************************************
2318  *              fgetwc (MSVCRT.@)
2319  *
2320  * In MSVCRT__O_TEXT mode, multibyte characters are read from the file, dropping
2321  * the CR from CR/LF combinations
2322  */
2323 MSVCRT_wint_t CDECL MSVCRT_fgetwc(MSVCRT_FILE* file)
2324 {
2325   char c;
2326
2327   if (!(MSVCRT_fdesc[file->_file].wxflag & WX_TEXT))
2328     {
2329       MSVCRT_wchar_t wc;
2330       unsigned int i;
2331       int j;
2332       char *chp, *wcp;
2333       wcp = (char *)&wc;
2334       for(i=0; i<sizeof(wc); i++)
2335       {
2336         if (file->_cnt>0) 
2337         {
2338           file->_cnt--;
2339           chp = file->_ptr++;
2340           wcp[i] = *chp;
2341         } 
2342         else
2343         {
2344           j = MSVCRT__filbuf(file);
2345           if(file->_cnt<=0)
2346           {
2347             file->_flag |= (file->_cnt == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
2348             file->_cnt = 0;
2349             return MSVCRT_WEOF;
2350           }
2351           wcp[i] = j;
2352         }
2353       }
2354       return wc;
2355     }
2356     
2357   c = MSVCRT_fgetc(file);
2358   if ((MSVCRT___mb_cur_max > 1) && MSVCRT_isleadbyte(c))
2359     {
2360       FIXME("Treat Multibyte characters\n");
2361     }
2362   if (c == MSVCRT_EOF)
2363     return MSVCRT_WEOF;
2364   else
2365     return (MSVCRT_wint_t)c;
2366 }
2367
2368 /*********************************************************************
2369  *              _getw (MSVCRT.@)
2370  */
2371 int CDECL MSVCRT__getw(MSVCRT_FILE* file)
2372 {
2373   char *ch;
2374   int i, k;
2375   unsigned int j;
2376   ch = (char *)&i;
2377   for (j=0; j<sizeof(int); j++) {
2378     k = MSVCRT_fgetc(file);
2379     if (k == MSVCRT_EOF) {
2380       file->_flag |= MSVCRT__IOEOF;
2381       return EOF;
2382     }
2383     ch[j] = k;
2384   }
2385   return i;
2386 }
2387
2388 /*********************************************************************
2389  *              getwc (MSVCRT.@)
2390  */
2391 MSVCRT_wint_t CDECL MSVCRT_getwc(MSVCRT_FILE* file)
2392 {
2393   return MSVCRT_fgetwc(file);
2394 }
2395
2396 /*********************************************************************
2397  *              _fgetwchar (MSVCRT.@)
2398  */
2399 MSVCRT_wint_t CDECL _fgetwchar(void)
2400 {
2401   return MSVCRT_fgetwc(MSVCRT_stdin);
2402 }
2403
2404 /*********************************************************************
2405  *              getwchar (MSVCRT.@)
2406  */
2407 MSVCRT_wint_t CDECL MSVCRT_getwchar(void)
2408 {
2409   return _fgetwchar();
2410 }
2411
2412 /*********************************************************************
2413  *              fgetws (MSVCRT.@)
2414  */
2415 MSVCRT_wchar_t * CDECL MSVCRT_fgetws(MSVCRT_wchar_t *s, int size, MSVCRT_FILE* file)
2416 {
2417   int    cc = MSVCRT_WEOF;
2418   MSVCRT_wchar_t * buf_start = s;
2419
2420   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2421         file,file->_file,s,size);
2422
2423   while ((size >1) && (cc = MSVCRT_fgetwc(file)) != MSVCRT_WEOF && cc != '\n')
2424     {
2425       *s++ = (char)cc;
2426       size --;
2427     }
2428   if ((cc == MSVCRT_WEOF) && (s == buf_start)) /* If nothing read, return 0*/
2429   {
2430     TRACE(":nothing read\n");
2431     return NULL;
2432   }
2433   if ((cc != MSVCRT_WEOF) && (size > 1))
2434     *s++ = cc;
2435   *s = 0;
2436   TRACE(":got %s\n", debugstr_w(buf_start));
2437   return buf_start;
2438 }
2439
2440 /*********************************************************************
2441  *              fwrite (MSVCRT.@)
2442  */
2443 MSVCRT_size_t CDECL MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
2444 {
2445   MSVCRT_size_t wrcnt=size * nmemb;
2446   int written = 0;
2447   if (size == 0)
2448       return 0;
2449   if(file->_cnt) {
2450         int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
2451         memcpy(file->_ptr, ptr, pcnt);
2452         file->_cnt -= pcnt;
2453         file->_ptr += pcnt;
2454         written = pcnt;
2455         wrcnt -= pcnt;
2456         ptr = (const char*)ptr + pcnt;
2457   } else if(!(file->_flag & MSVCRT__IOWRT)) {
2458         if(file->_flag & MSVCRT__IORW) {
2459                 file->_flag |= MSVCRT__IOWRT;
2460         } else
2461                 return 0;
2462   }
2463   if(wrcnt) {
2464         /* Flush buffer */
2465         int res=msvcrt_flush_buffer(file);
2466         if(!res) {
2467                 int pwritten = MSVCRT__write(file->_file, ptr, wrcnt);
2468                 if (pwritten <= 0)
2469                 {
2470                     file->_flag |= MSVCRT__IOERR;
2471                     pwritten=0;
2472                 }
2473                 written += pwritten;
2474         }
2475   }
2476   return written / size;
2477 }
2478
2479 /*********************************************************************
2480  *              fputwc (MSVCRT.@)
2481  */
2482 MSVCRT_wint_t CDECL MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
2483 {
2484   MSVCRT_wchar_t mwc=wc;
2485   if (MSVCRT_fwrite( &mwc, sizeof(mwc), 1, file) != 1)
2486     return MSVCRT_WEOF;
2487   return wc;
2488 }
2489
2490 /*********************************************************************
2491  *              _fputwchar (MSVCRT.@)
2492  */
2493 MSVCRT_wint_t CDECL _fputwchar(MSVCRT_wint_t wc)
2494 {
2495   return MSVCRT_fputwc(wc, MSVCRT_stdout);
2496 }
2497
2498 /*********************************************************************
2499  *              _wfsopen (MSVCRT.@)
2500  */
2501 MSVCRT_FILE * CDECL MSVCRT__wfsopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, int share)
2502 {
2503   MSVCRT_FILE* file;
2504   int open_flags, stream_flags, fd;
2505
2506   TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
2507
2508   /* map mode string to open() flags. "man fopen" for possibilities. */
2509   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
2510       return NULL;
2511
2512   LOCK_FILES();
2513   fd = MSVCRT__wsopen(path, open_flags, share, MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
2514   if (fd < 0)
2515     file = NULL;
2516   else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
2517    != -1)
2518     TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
2519   else if (file)
2520   {
2521     file->_flag = 0;
2522     file = NULL;
2523   }
2524
2525   TRACE(":got (%p)\n",file);
2526   if (fd >= 0 && !file)
2527     MSVCRT__close(fd);
2528   UNLOCK_FILES();
2529   return file;
2530 }
2531
2532 /*********************************************************************
2533  *              _fsopen (MSVCRT.@)
2534  */
2535 MSVCRT_FILE * CDECL MSVCRT__fsopen(const char *path, const char *mode, int share)
2536 {
2537     MSVCRT_FILE *ret;
2538     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
2539
2540     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
2541     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
2542     {
2543         MSVCRT_free(pathW);
2544         return NULL;
2545     }
2546
2547     ret = MSVCRT__wfsopen(pathW, modeW, share);
2548
2549     MSVCRT_free(pathW);
2550     MSVCRT_free(modeW);
2551     return ret;
2552 }
2553
2554 /*********************************************************************
2555  *              fopen (MSVCRT.@)
2556  */
2557 MSVCRT_FILE * CDECL MSVCRT_fopen(const char *path, const char *mode)
2558 {
2559     return MSVCRT__fsopen( path, mode, MSVCRT__SH_DENYNO );
2560 }
2561
2562 /*********************************************************************
2563  *              _wfopen (MSVCRT.@)
2564  */
2565 MSVCRT_FILE * CDECL MSVCRT__wfopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode)
2566 {
2567     return MSVCRT__wfsopen( path, mode, MSVCRT__SH_DENYNO );
2568 }
2569
2570 /* MSVCRT_fputc calls MSVCRT__flsbuf which calls MSVCRT_fputc */
2571 int CDECL MSVCRT__flsbuf(int c, MSVCRT_FILE* file);
2572
2573 /*********************************************************************
2574  *              fputc (MSVCRT.@)
2575  */
2576 int CDECL MSVCRT_fputc(int c, MSVCRT_FILE* file)
2577 {
2578   if(file->_cnt>0) {
2579     *file->_ptr++=c;
2580     file->_cnt--;
2581     if (c == '\n')
2582     {
2583       int res = msvcrt_flush_buffer(file);
2584       return res ? res : c;
2585     }
2586     else
2587       return c & 0xff;
2588   } else {
2589     return MSVCRT__flsbuf(c, file);
2590   }
2591 }
2592
2593 /*********************************************************************
2594  *              _flsbuf (MSVCRT.@)
2595  */
2596 int CDECL MSVCRT__flsbuf(int c, MSVCRT_FILE* file)
2597 {
2598   /* Flush output buffer */
2599   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
2600         msvcrt_alloc_buffer(file);
2601   }
2602   if(!(file->_flag & MSVCRT__IOWRT)) {
2603         if(file->_flag & MSVCRT__IORW) {
2604                 file->_flag |= MSVCRT__IOWRT;
2605         } else {
2606                 return MSVCRT_EOF;
2607         }
2608   }
2609   if(file->_bufsiz) {
2610         int res=msvcrt_flush_buffer(file);
2611         return res?res : MSVCRT_fputc(c, file);
2612   } else {
2613         unsigned char cc=c;
2614         int len;
2615         /* set _cnt to 0 for unbuffered FILEs */
2616         file->_cnt = 0;
2617         len = MSVCRT__write(file->_file, &cc, 1);
2618         if (len == 1) return c & 0xff;
2619         file->_flag |= MSVCRT__IOERR;
2620         return MSVCRT_EOF;
2621   }
2622 }
2623
2624 /*********************************************************************
2625  *              _fputchar (MSVCRT.@)
2626  */
2627 int CDECL _fputchar(int c)
2628 {
2629   return MSVCRT_fputc(c, MSVCRT_stdout);
2630 }
2631
2632 /*********************************************************************
2633  *              fread (MSVCRT.@)
2634  */
2635 MSVCRT_size_t CDECL MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
2636 { MSVCRT_size_t rcnt=size * nmemb;
2637   MSVCRT_size_t read=0;
2638   int pread=0;
2639
2640   if(!rcnt)
2641         return 0;
2642
2643   /* first buffered data */
2644   if(file->_cnt>0) {
2645         int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
2646         memcpy(ptr, file->_ptr, pcnt);
2647         file->_cnt -= pcnt;
2648         file->_ptr += pcnt;
2649         read += pcnt ;
2650         rcnt -= pcnt ;
2651         ptr = (char*)ptr + pcnt;
2652   } else if(!(file->_flag & MSVCRT__IOREAD )) {
2653         if(file->_flag & MSVCRT__IORW) {
2654                 file->_flag |= MSVCRT__IOREAD;
2655         } else
2656             return 0;
2657   }
2658   while(rcnt>0)
2659   {
2660     int i;
2661     /* Fill the buffer on small reads.
2662      * TODO: Use a better buffering strategy.
2663      */
2664     if (!file->_cnt && size*nmemb <= MSVCRT_BUFSIZ/2 && !(file->_flag & MSVCRT__IONBF)) {
2665       if (file->_bufsiz == 0) {
2666         msvcrt_alloc_buffer(file);
2667       }
2668       file->_cnt = MSVCRT__read(file->_file, file->_base, file->_bufsiz);
2669       file->_ptr = file->_base;
2670       i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
2671       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
2672       if (i > 0 && i < file->_cnt) {
2673         MSVCRT_fdesc[file->_file].wxflag &= ~WX_ATEOF;
2674         file->_flag &= ~MSVCRT__IOEOF;
2675       }
2676       if (i > 0) {
2677         memcpy(ptr, file->_ptr, i);
2678         file->_cnt -= i;
2679         file->_ptr += i;
2680       }
2681     } else {
2682       i = MSVCRT__read(file->_file,ptr, rcnt);
2683     }
2684     pread += i;
2685     rcnt -= i;
2686     ptr = (char *)ptr+i;
2687     /* expose feof condition in the flags
2688      * MFC tests file->_flag for feof, and doesn't call feof())
2689      */
2690     if ( MSVCRT_fdesc[file->_file].wxflag & WX_ATEOF)
2691         file->_flag |= MSVCRT__IOEOF;
2692     else if (i == -1)
2693     {
2694         file->_flag |= MSVCRT__IOERR;
2695         pread = 0;
2696         rcnt = 0;
2697     }
2698     if (i < 1) break;
2699   }
2700   read+=pread;
2701   return read / size;
2702 }
2703
2704 /*********************************************************************
2705  *              _wfreopen (MSVCRT.@)
2706  *
2707  */
2708 MSVCRT_FILE* CDECL _wfreopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, MSVCRT_FILE* file)
2709 {
2710   int open_flags, stream_flags, fd;
2711
2712   TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file->_file);
2713
2714   LOCK_FILES();
2715   if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
2716     file = NULL;
2717   else
2718   {
2719     MSVCRT_fclose(file);
2720     /* map mode string to open() flags. "man fopen" for possibilities. */
2721     if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
2722       file = NULL;
2723     else
2724     {
2725       fd = _wopen(path, open_flags, MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
2726       if (fd < 0)
2727         file = NULL;
2728       else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
2729       {
2730           file->_flag = 0;
2731           WARN(":failed-last error (%d)\n",GetLastError());
2732           msvcrt_set_errno(GetLastError());
2733           file = NULL;
2734       }
2735     }
2736   }
2737   UNLOCK_FILES();
2738   return file;
2739 }
2740
2741 /*********************************************************************
2742  *      freopen (MSVCRT.@)
2743  *
2744  */
2745 MSVCRT_FILE* CDECL MSVCRT_freopen(const char *path, const char *mode, MSVCRT_FILE* file)
2746 {
2747     MSVCRT_FILE *ret;
2748     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
2749
2750     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
2751     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
2752     {
2753         MSVCRT_free(pathW);
2754         return NULL;
2755     }
2756
2757     ret = _wfreopen(pathW, modeW, file);
2758
2759     MSVCRT_free(pathW);
2760     MSVCRT_free(modeW);
2761     return ret;
2762 }
2763
2764 /*********************************************************************
2765  *              fsetpos (MSVCRT.@)
2766  */
2767 int CDECL MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
2768 {
2769   /* Note that all this has been lifted 'as is' from fseek */
2770   if(file->_flag & MSVCRT__IOWRT)
2771         msvcrt_flush_buffer(file);
2772
2773   /* Discard buffered input */
2774   file->_cnt = 0;
2775   file->_ptr = file->_base;
2776   
2777   /* Reset direction of i/o */
2778   if(file->_flag & MSVCRT__IORW) {
2779         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
2780   }
2781
2782   return (MSVCRT__lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
2783 }
2784
2785 /*********************************************************************
2786  *              ftell (MSVCRT.@)
2787  */
2788 LONG CDECL MSVCRT_ftell(MSVCRT_FILE* file)
2789 {
2790   /* TODO: just call fgetpos and return lower half of result */
2791   int off=0;
2792   long pos;
2793   pos = _tell(file->_file);
2794   if(pos == -1) return -1;
2795   if(file->_bufsiz)  {
2796         if( file->_flag & MSVCRT__IOWRT ) {
2797                 off = file->_ptr - file->_base;
2798         } else {
2799                 off = -file->_cnt;
2800                 if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT) {
2801                         /* Black magic correction for CR removal */
2802                         int i;
2803                         for (i=0; i<file->_cnt; i++) {
2804                                 if (file->_ptr[i] == '\n')
2805                                         off--;
2806                         }
2807                 }
2808         }
2809   }
2810   return off + pos;
2811 }
2812
2813 /*********************************************************************
2814  *              fgetpos (MSVCRT.@)
2815  */
2816 int CDECL MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
2817 {
2818   int off=0;
2819   *pos = MSVCRT__lseeki64(file->_file,0,SEEK_CUR);
2820   if(*pos == -1) return -1;
2821   if(file->_bufsiz)  {
2822         if( file->_flag & MSVCRT__IOWRT ) {
2823                 off = file->_ptr - file->_base;
2824         } else {
2825                 off = -file->_cnt;
2826                 if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT) {
2827                         /* Black magic correction for CR removal */
2828                         int i;
2829                         for (i=0; i<file->_cnt; i++) {
2830                                 if (file->_ptr[i] == '\n')
2831                                         off--;
2832                         }
2833                 }
2834         }
2835   }
2836   *pos += off;
2837   return 0;
2838 }
2839
2840 /*********************************************************************
2841  *              fputs (MSVCRT.@)
2842  */
2843 int CDECL MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
2844 {
2845     size_t i, len = strlen(s);
2846     if (!(MSVCRT_fdesc[file->_file].wxflag & WX_TEXT))
2847       return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
2848     for (i=0; i<len; i++)
2849       if (MSVCRT_fputc(s[i], file) == MSVCRT_EOF) 
2850         return MSVCRT_EOF;
2851     return 0;
2852 }
2853
2854 /*********************************************************************
2855  *              fputws (MSVCRT.@)
2856  */
2857 int CDECL MSVCRT_fputws(const MSVCRT_wchar_t *s, MSVCRT_FILE* file)
2858 {
2859     size_t i, len = strlenW(s);
2860     if (!(MSVCRT_fdesc[file->_file].wxflag & WX_TEXT))
2861       return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
2862     for (i=0; i<len; i++)
2863       {
2864         if ((s[i] == '\n') && (MSVCRT_fputc('\r', file) == MSVCRT_EOF))
2865           return MSVCRT_WEOF;
2866         if (MSVCRT_fputwc(s[i], file) == MSVCRT_WEOF)
2867           return MSVCRT_WEOF; 
2868       }
2869     return 0;
2870 }
2871
2872 /*********************************************************************
2873  *              getchar (MSVCRT.@)
2874  */
2875 int CDECL MSVCRT_getchar(void)
2876 {
2877   return MSVCRT_fgetc(MSVCRT_stdin);
2878 }
2879
2880 /*********************************************************************
2881  *              getc (MSVCRT.@)
2882  */
2883 int CDECL MSVCRT_getc(MSVCRT_FILE* file)
2884 {
2885   return MSVCRT_fgetc(file);
2886 }
2887
2888 /*********************************************************************
2889  *              gets (MSVCRT.@)
2890  */
2891 char * CDECL MSVCRT_gets(char *buf)
2892 {
2893   int    cc;
2894   char * buf_start = buf;
2895
2896   for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
2897       cc = MSVCRT_fgetc(MSVCRT_stdin))
2898   if(cc != '\r') *buf++ = (char)cc;
2899
2900   *buf = '\0';
2901
2902   TRACE("got '%s'\n", buf_start);
2903   return buf_start;
2904 }
2905
2906 /*********************************************************************
2907  *              _getws (MSVCRT.@)
2908  */
2909 MSVCRT_wchar_t* CDECL MSVCRT__getws(MSVCRT_wchar_t* buf)
2910 {
2911     MSVCRT_wint_t cc;
2912     MSVCRT_wchar_t* ws = buf;
2913
2914     for (cc = MSVCRT_fgetwc(MSVCRT_stdin); cc != MSVCRT_WEOF && cc != '\n';
2915          cc = MSVCRT_fgetwc(MSVCRT_stdin))
2916     {
2917         if (cc != '\r')
2918             *buf++ = (MSVCRT_wchar_t)cc;
2919     }
2920     *buf = '\0';
2921
2922     TRACE("got %s\n", debugstr_w(ws));
2923     return ws;
2924 }
2925
2926 /*********************************************************************
2927  *              putc (MSVCRT.@)
2928  */
2929 int CDECL MSVCRT_putc(int c, MSVCRT_FILE* file)
2930 {
2931   return MSVCRT_fputc(c, file);
2932 }
2933
2934 /*********************************************************************
2935  *              putchar (MSVCRT.@)
2936  */
2937 int CDECL MSVCRT_putchar(int c)
2938 {
2939   return MSVCRT_fputc(c, MSVCRT_stdout);
2940 }
2941
2942 /*********************************************************************
2943  *              puts (MSVCRT.@)
2944  */
2945 int CDECL MSVCRT_puts(const char *s)
2946 {
2947     size_t len = strlen(s);
2948     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2949     return MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2950 }
2951
2952 /*********************************************************************
2953  *              _putws (MSVCRT.@)
2954  */
2955 int CDECL _putws(const MSVCRT_wchar_t *s)
2956 {
2957     static const MSVCRT_wchar_t nl = '\n';
2958     size_t len = strlenW(s);
2959     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2960     return MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2961 }
2962
2963 /*********************************************************************
2964  *              remove (MSVCRT.@)
2965  */
2966 int CDECL MSVCRT_remove(const char *path)
2967 {
2968   TRACE("(%s)\n",path);
2969   if (DeleteFileA(path))
2970     return 0;
2971   TRACE(":failed (%d)\n",GetLastError());
2972   msvcrt_set_errno(GetLastError());
2973   return -1;
2974 }
2975
2976 /*********************************************************************
2977  *              _wremove (MSVCRT.@)
2978  */
2979 int CDECL _wremove(const MSVCRT_wchar_t *path)
2980 {
2981   TRACE("(%s)\n",debugstr_w(path));
2982   if (DeleteFileW(path))
2983     return 0;
2984   TRACE(":failed (%d)\n",GetLastError());
2985   msvcrt_set_errno(GetLastError());
2986   return -1;
2987 }
2988
2989 /*********************************************************************
2990  *              rename (MSVCRT.@)
2991  */
2992 int CDECL MSVCRT_rename(const char *oldpath,const char *newpath)
2993 {
2994   TRACE(":from %s to %s\n",oldpath,newpath);
2995   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
2996     return 0;
2997   TRACE(":failed (%d)\n",GetLastError());
2998   msvcrt_set_errno(GetLastError());
2999   return -1;
3000 }
3001
3002 /*********************************************************************
3003  *              _wrename (MSVCRT.@)
3004  */
3005 int CDECL _wrename(const MSVCRT_wchar_t *oldpath,const MSVCRT_wchar_t *newpath)
3006 {
3007   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
3008   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3009     return 0;
3010   TRACE(":failed (%d)\n",GetLastError());
3011   msvcrt_set_errno(GetLastError());
3012   return -1;
3013 }
3014
3015 /*********************************************************************
3016  *              setvbuf (MSVCRT.@)
3017  */
3018 int CDECL MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
3019 {
3020   /* TODO: Check if file busy */
3021   if(file->_bufsiz) {
3022         MSVCRT_free(file->_base);
3023         file->_bufsiz = 0;
3024         file->_cnt = 0;
3025   }
3026   if(mode == MSVCRT__IOFBF) {
3027         file->_flag &= ~MSVCRT__IONBF;
3028         file->_base = file->_ptr = buf;
3029         if(buf) {
3030                 file->_bufsiz = size;
3031         }
3032   } else {
3033         file->_flag |= MSVCRT__IONBF;
3034   }
3035   return 0;
3036 }
3037
3038 /*********************************************************************
3039  *              setbuf (MSVCRT.@)
3040  */
3041 void CDECL MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
3042 {
3043   MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ);
3044 }
3045
3046 /*********************************************************************
3047  *              tmpnam (MSVCRT.@)
3048  */
3049 char * CDECL MSVCRT_tmpnam(char *s)
3050 {
3051   static int unique;
3052   char tmpstr[16];
3053   char *p;
3054   int count;
3055   if (s == 0)
3056     s = MSVCRT_tmpname;
3057   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
3058   p = s + sprintf(s, "\\s%s.", tmpstr);
3059   for (count = 0; count < MSVCRT_TMP_MAX; count++)
3060   {
3061     msvcrt_int_to_base32(unique++, tmpstr);
3062     strcpy(p, tmpstr);
3063     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
3064         GetLastError() == ERROR_FILE_NOT_FOUND)
3065       break;
3066   }
3067   return s;
3068 }
3069
3070 /*********************************************************************
3071  *              tmpfile (MSVCRT.@)
3072  */
3073 MSVCRT_FILE* CDECL MSVCRT_tmpfile(void)
3074 {
3075   char *filename = MSVCRT_tmpnam(NULL);
3076   int fd;
3077   MSVCRT_FILE* file = NULL;
3078
3079   LOCK_FILES();
3080   fd = MSVCRT__open(filename, MSVCRT__O_CREAT | MSVCRT__O_BINARY | MSVCRT__O_RDWR | MSVCRT__O_TEMPORARY);
3081   if (fd != -1 && (file = msvcrt_alloc_fp()))
3082   {
3083     if (msvcrt_init_fp(file, fd, MSVCRT__O_RDWR) == -1)
3084     {
3085         file->_flag = 0;
3086         file = NULL;
3087     }
3088     else file->_tmpfname = _strdup(filename);
3089   }
3090   UNLOCK_FILES();
3091   return file;
3092 }
3093
3094 /*********************************************************************
3095  *              vfprintf (MSVCRT.@)
3096  */
3097 int CDECL MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, __ms_va_list valist)
3098 {
3099   char buf[2048], *mem = buf;
3100   int written, resize = sizeof(buf), retval;
3101   /* There are two conventions for vsnprintf failing:
3102    * Return -1 if we truncated, or
3103    * Return the number of bytes that would have been written
3104    * The code below handles both cases
3105    */
3106   while ((written = MSVCRT_vsnprintf(mem, resize, format, valist)) == -1 ||
3107           written > resize)
3108   {
3109     resize = (written == -1 ? resize * 2 : written + 1);
3110     if (mem != buf)
3111       MSVCRT_free (mem);
3112     if (!(mem = MSVCRT_malloc(resize)))
3113       return MSVCRT_EOF;
3114   }
3115   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
3116   if (mem != buf)
3117     MSVCRT_free (mem);
3118   return retval;
3119 }
3120
3121 /*********************************************************************
3122  *              vfwprintf (MSVCRT.@)
3123  * FIXME:
3124  * Is final char included in written (then resize is too big) or not
3125  * (then we must test for equality too)?
3126  */
3127 int CDECL MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, __ms_va_list valist)
3128 {
3129   MSVCRT_wchar_t buf[2048], *mem = buf;
3130   int written, resize = sizeof(buf) / sizeof(MSVCRT_wchar_t), retval;
3131   /* See vfprintf comments */
3132   while ((written = MSVCRT_vsnwprintf(mem, resize, format, valist)) == -1 ||
3133           written > resize)
3134   {
3135     resize = (written == -1 ? resize * 2 : written + sizeof(MSVCRT_wchar_t));
3136     if (mem != buf)
3137       MSVCRT_free (mem);
3138     if (!(mem = MSVCRT_malloc(resize*sizeof(*mem))))
3139       return MSVCRT_EOF;
3140   }
3141   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
3142   if (mem != buf)
3143     MSVCRT_free (mem);
3144   return retval;
3145 }
3146
3147 /*********************************************************************
3148  *              vprintf (MSVCRT.@)
3149  */
3150 int CDECL MSVCRT_vprintf(const char *format, __ms_va_list valist)
3151 {
3152   return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
3153 }
3154
3155 /*********************************************************************
3156  *              vwprintf (MSVCRT.@)
3157  */
3158 int CDECL MSVCRT_vwprintf(const MSVCRT_wchar_t *format, __ms_va_list valist)
3159 {
3160   return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
3161 }
3162
3163 /*********************************************************************
3164  *              fprintf (MSVCRT.@)
3165  */
3166 int CDECL MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
3167 {
3168     __ms_va_list valist;
3169     int res;
3170     __ms_va_start(valist, format);
3171     res = MSVCRT_vfprintf(file, format, valist);
3172     __ms_va_end(valist);
3173     return res;
3174 }
3175
3176 /*********************************************************************
3177  *              fwprintf (MSVCRT.@)
3178  */
3179 int CDECL MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
3180 {
3181     __ms_va_list valist;
3182     int res;
3183     __ms_va_start(valist, format);
3184     res = MSVCRT_vfwprintf(file, format, valist);
3185     __ms_va_end(valist);
3186     return res;
3187 }
3188
3189 /*********************************************************************
3190  *              printf (MSVCRT.@)
3191  */
3192 int CDECL MSVCRT_printf(const char *format, ...)
3193 {
3194     __ms_va_list valist;
3195     int res;
3196     __ms_va_start(valist, format);
3197     res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
3198     __ms_va_end(valist);
3199     return res;
3200 }
3201
3202 /*********************************************************************
3203  *              ungetc (MSVCRT.@)
3204  */
3205 int CDECL MSVCRT_ungetc(int c, MSVCRT_FILE * file)
3206 {
3207         if (c == MSVCRT_EOF)
3208                 return MSVCRT_EOF;
3209         if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
3210                 msvcrt_alloc_buffer(file);
3211                 file->_ptr++;
3212         }
3213         if(file->_ptr>file->_base) {
3214                 file->_ptr--;
3215                 *file->_ptr=c;
3216                 file->_cnt++;
3217                 MSVCRT_clearerr(file);
3218                 return c;
3219         }
3220         return MSVCRT_EOF;
3221 }
3222
3223 /*********************************************************************
3224  *              ungetwc (MSVCRT.@)
3225  */
3226 MSVCRT_wint_t CDECL MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file)
3227 {
3228         MSVCRT_wchar_t mwc = wc;
3229         char * pp = (char *)&mwc;
3230         int i;
3231         for(i=sizeof(MSVCRT_wchar_t)-1;i>=0;i--) {
3232                 if(pp[i] != MSVCRT_ungetc(pp[i],file))
3233                         return MSVCRT_WEOF;
3234         }
3235         return mwc;
3236 }
3237
3238 /*********************************************************************
3239  *              wprintf (MSVCRT.@)
3240  */
3241 int CDECL MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
3242 {
3243     __ms_va_list valist;
3244     int res;
3245     __ms_va_start(valist, format);
3246     res = MSVCRT_vwprintf(format, valist);
3247     __ms_va_end(valist);
3248     return res;
3249 }
3250
3251 /*********************************************************************
3252  *              _getmaxstdio (MSVCRT.@)
3253  */
3254 int CDECL _getmaxstdio(void)
3255 {
3256     FIXME("stub, always returns 512\n");
3257     return 512;
3258 }
3259
3260 /*********************************************************************
3261  *              _setmaxstdio_ (MSVCRT.@)
3262  */
3263 int CDECL _setmaxstdio(int newmax)
3264 {
3265     int res;
3266     if( newmax > 2048)
3267       res = -1;
3268     else
3269       res = newmax;
3270     FIXME("stub: setting new maximum for number of simultaneously open files not implemented,returning %d\n",res);
3271     return res;
3272 }
3273
3274 /*********************************************************************
3275  *              __pioinfo (MSVCRT.@)
3276  * FIXME: see MSVCRT_MAX_FILES define.
3277  */
3278 ioinfo * MSVCRT___pioinfo[] = { /* array of pointers to ioinfo arrays [64] */
3279     &MSVCRT_fdesc[0 * 64], &MSVCRT_fdesc[1 * 64], &MSVCRT_fdesc[2 * 64],
3280     &MSVCRT_fdesc[3 * 64], &MSVCRT_fdesc[4 * 64], &MSVCRT_fdesc[5 * 64],
3281     &MSVCRT_fdesc[6 * 64], &MSVCRT_fdesc[7 * 64], &MSVCRT_fdesc[8 * 64],
3282     &MSVCRT_fdesc[9 * 64], &MSVCRT_fdesc[10 * 64], &MSVCRT_fdesc[11 * 64],
3283     &MSVCRT_fdesc[12 * 64], &MSVCRT_fdesc[13 * 64], &MSVCRT_fdesc[14 * 64],
3284     &MSVCRT_fdesc[15 * 64], &MSVCRT_fdesc[16 * 64], &MSVCRT_fdesc[17 * 64],
3285     &MSVCRT_fdesc[18 * 64], &MSVCRT_fdesc[19 * 64], &MSVCRT_fdesc[20 * 64],
3286     &MSVCRT_fdesc[21 * 64], &MSVCRT_fdesc[22 * 64], &MSVCRT_fdesc[23 * 64],
3287     &MSVCRT_fdesc[24 * 64], &MSVCRT_fdesc[25 * 64], &MSVCRT_fdesc[26 * 64],
3288     &MSVCRT_fdesc[27 * 64], &MSVCRT_fdesc[28 * 64], &MSVCRT_fdesc[29 * 64],
3289     &MSVCRT_fdesc[30 * 64], &MSVCRT_fdesc[31 * 64]
3290 } ;
3291
3292 /*********************************************************************
3293  *              __badioinfo (MSVCRT.@)
3294  */
3295 ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };