Added support for nested exceptions happening inside a catch block.
[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  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <time.h>
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32
33 #include "winternl.h"
34 #include "msvcrt.h"
35 #include "msvcrt/errno.h"
36
37 #include "wine/unicode.h"
38 #include "msvcrt/direct.h"
39 #include "msvcrt/fcntl.h"
40 #include "msvcrt/io.h"
41 #include "msvcrt/sys/locking.h"
42 #include "msvcrt/stdio.h"
43 #include "msvcrt/stdlib.h"
44 #include "msvcrt/string.h"
45 #include "msvcrt/sys/stat.h"
46 #include "msvcrt/sys/utime.h"
47 #include "msvcrt/time.h"
48 #include "msvcrt/share.h"
49
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
53
54 /* for stat mode, permissions apply to all,owner and group */
55 #define MSVCRT_S_IREAD  (_S_IREAD  | (_S_IREAD  >> 3) | (_S_IREAD  >> 6))
56 #define MSVCRT_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
57 #define MSVCRT_S_IEXEC  (_S_IEXEC  | (_S_IEXEC  >> 3) | (_S_IEXEC  >> 6))
58
59 /* _access() bit flags FIXME: incomplete */
60 #define MSVCRT_W_OK      0x02
61
62
63 /* FIXME: Make this dynamic */
64 #define MSVCRT_MAX_FILES 257
65
66 HANDLE MSVCRT_handles[MSVCRT_MAX_FILES];
67 MSVCRT_FILE* MSVCRT_files[MSVCRT_MAX_FILES];
68 int  MSVCRT_flags[MSVCRT_MAX_FILES];
69 char *MSVCRT_tempfiles[MSVCRT_MAX_FILES];
70 MSVCRT_FILE MSVCRT__iob[3];
71 #define MSVCRT_stdin       (MSVCRT__iob+STDIN_FILENO)
72 #define MSVCRT_stdout      (MSVCRT__iob+STDOUT_FILENO)
73 #define MSVCRT_stderr      (MSVCRT__iob+STDERR_FILENO)
74
75 static int MSVCRT_fdstart = 3; /* first unallocated fd */
76 static int MSVCRT_fdend = 3; /* highest allocated fd */
77
78 /* INTERNAL: process umask */
79 static int MSVCRT_umask = 0;
80
81 /* INTERNAL: Static buffer for temp file name */
82 static char MSVCRT_tmpname[MAX_PATH];
83
84 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
85 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
86 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
87 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
88
89 #define TOUL(x) (ULONGLONG)((WCHAR)L##x)
90 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
91 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
92 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
93 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
94
95 extern CRITICAL_SECTION MSVCRT_file_cs;
96 #define LOCK_FILES     EnterCriticalSection(&MSVCRT_file_cs)
97 #define UNLOCK_FILES   LeaveCriticalSection(&MSVCRT_file_cs)
98
99
100 /* INTERNAL: Get the HANDLE for a fd */
101 static HANDLE msvcrt_fdtoh(int fd)
102 {
103   if (fd < 0 || fd >= MSVCRT_fdend ||
104       MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
105   {
106     WARN(":fd (%d) - no handle!\n",fd);
107     *__doserrno() = 0;
108     *MSVCRT__errno() = MSVCRT_EBADF;
109    return INVALID_HANDLE_VALUE;
110   }
111   return MSVCRT_handles[fd];
112 }
113
114 /* INTERNAL: free a file entry fd */
115 static void msvcrt_free_fd(int fd)
116 {
117   MSVCRT_handles[fd] = INVALID_HANDLE_VALUE;
118   MSVCRT_files[fd] = 0;
119   MSVCRT_flags[fd] = 0;
120   TRACE(":fd (%d) freed\n",fd);
121   if (fd < 3)
122     return; /* dont use 0,1,2 for user files */
123   if (fd == MSVCRT_fdend - 1)
124     MSVCRT_fdend--;
125   if (fd < MSVCRT_fdstart)
126     MSVCRT_fdstart = fd;
127 }
128
129 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
130 static int msvcrt_alloc_fd(HANDLE hand, int flag)
131 {
132   int fd = MSVCRT_fdstart;
133
134   TRACE(":handle (%p) allocating fd (%d)\n",hand,fd);
135   if (fd >= MSVCRT_MAX_FILES)
136   {
137     WARN(":files exhausted!\n");
138     return -1;
139   }
140   MSVCRT_handles[fd] = hand;
141   MSVCRT_flags[fd] = flag;
142
143   /* locate next free slot */
144   if (fd == MSVCRT_fdend)
145     MSVCRT_fdstart = ++MSVCRT_fdend;
146   else
147     while(MSVCRT_fdstart < MSVCRT_fdend &&
148           MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE)
149       MSVCRT_fdstart++;
150
151   return fd;
152 }
153
154 /* INTERNAL: Allocate a FILE* for an fd slot
155  * This is done lazily to avoid memory wastage for low level open/write
156  * usage when a FILE* is not requested (but may be later).
157  */
158 static MSVCRT_FILE* msvcrt_alloc_fp(int fd)
159 {
160   TRACE(":fd (%d) allocating FILE*\n",fd);
161   if (fd < 0 || fd >= MSVCRT_fdend ||
162       MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
163   {
164     WARN(":invalid fd %d\n",fd);
165     *__doserrno() = 0;
166     *MSVCRT__errno() = MSVCRT_EBADF;
167     return NULL;
168   }
169   if (!MSVCRT_files[fd])
170   {
171     if ((MSVCRT_files[fd] = MSVCRT_calloc(sizeof(MSVCRT_FILE),1)))
172     {
173       MSVCRT_files[fd]->_file = fd;
174       MSVCRT_files[fd]->_flag = MSVCRT_flags[fd];
175       MSVCRT_files[fd]->_flag &= ~MSVCRT__IOAPPEND; /* mask out, see above */
176     }
177   }
178   TRACE(":got FILE* (%p)\n",MSVCRT_files[fd]);
179   return MSVCRT_files[fd];
180 }
181
182
183 /* INTERNAL: Set up stdin, stderr and stdout */
184 void msvcrt_init_io(void)
185 {
186   int i;
187   memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
188   MSVCRT_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
189   MSVCRT_flags[0] = MSVCRT__iob[0]._flag = MSVCRT__IOREAD;
190   MSVCRT_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
191   MSVCRT_flags[1] = MSVCRT__iob[1]._flag = MSVCRT__IOWRT;
192   MSVCRT_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
193   MSVCRT_flags[2] = MSVCRT__iob[2]._flag = MSVCRT__IOWRT;
194
195   TRACE(":handles (%p)(%p)(%p)\n",MSVCRT_handles[0],
196         MSVCRT_handles[1],MSVCRT_handles[2]);
197
198   for (i = 0; i < 3; i++)
199   {
200     /* FILE structs for stdin/out/err are static and never deleted */
201     MSVCRT_files[i] = &MSVCRT__iob[i];
202     MSVCRT__iob[i]._file = i;
203     MSVCRT_tempfiles[i] = NULL;
204   }
205 }
206
207 /* free everything on process exit */
208 void msvcrt_free_io(void)
209 {
210     _fcloseall();
211     _close(0);
212     _close(1);
213     _close(2);
214 }
215
216 /* INTERNAL: Flush stdio file buffer */
217 static int msvcrt_flush_buffer(MSVCRT_FILE* file)
218 {
219   if(file->_bufsiz) {
220         int cnt=file->_ptr-file->_base;
221         if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
222                 return MSVCRT_EOF;
223         }
224         file->_ptr=file->_base;
225         file->_cnt=file->_bufsiz;
226   }
227   return 0;
228 }
229
230 /* INTERNAL: Allocate stdio file buffer */
231 static void msvcrt_alloc_buffer(MSVCRT_FILE* file)
232 {
233         file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1);
234         if(file->_base) {
235                 file->_bufsiz = MSVCRT_BUFSIZ;
236                 file->_flag |= MSVCRT__IOMYBUF;
237         } else {
238                 file->_base = (unsigned char *)(&file->_charbuf);
239                 /* put here 2 ??? */
240                 file->_bufsiz = sizeof(file->_charbuf);
241         }
242         file->_ptr = file->_base;
243         file->_cnt = 0;
244 }
245
246 /*********************************************************************
247  *              __p__iob(MSVCRT.@)
248  */
249 MSVCRT_FILE *__p__iob(void)
250 {
251  return &MSVCRT__iob[0];
252 }
253
254 /*********************************************************************
255  *              _access (MSVCRT.@)
256  */
257 int _access(const char *filename, int mode)
258 {
259   DWORD attr = GetFileAttributesA(filename);
260
261   TRACE("(%s,%d) %ld\n",filename,mode,attr);
262
263   if (!filename || attr == 0xffffffff)
264   {
265     MSVCRT__set_errno(GetLastError());
266     return -1;
267   }
268   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
269   {
270     MSVCRT__set_errno(ERROR_ACCESS_DENIED);
271     return -1;
272   }
273   return 0;
274 }
275
276 /*********************************************************************
277  *              _waccess (MSVCRT.@)
278  */
279 int _waccess(const WCHAR *filename, int mode)
280 {
281   DWORD attr = GetFileAttributesW(filename);
282
283   TRACE("(%s,%d) %ld\n",debugstr_w(filename),mode,attr);
284
285   if (!filename || attr == 0xffffffff)
286   {
287     MSVCRT__set_errno(GetLastError());
288     return -1;
289   }
290   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
291   {
292     MSVCRT__set_errno(ERROR_ACCESS_DENIED);
293     return -1;
294   }
295   return 0;
296 }
297
298 /*********************************************************************
299  *              _chmod (MSVCRT.@)
300  */
301 int _chmod(const char *path, int flags)
302 {
303   DWORD oldFlags = GetFileAttributesA(path);
304
305   if (oldFlags != 0x0FFFFFFFF)
306   {
307     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
308       oldFlags | FILE_ATTRIBUTE_READONLY;
309
310     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
311       return 0;
312   }
313   MSVCRT__set_errno(GetLastError());
314   return -1;
315 }
316
317 /*********************************************************************
318  *              _wchmod (MSVCRT.@)
319  */
320 int _wchmod(const WCHAR *path, int flags)
321 {
322   DWORD oldFlags = GetFileAttributesW(path);
323
324   if (oldFlags != 0x0FFFFFFFF)
325   {
326     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
327       oldFlags | FILE_ATTRIBUTE_READONLY;
328
329     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
330       return 0;
331   }
332   MSVCRT__set_errno(GetLastError());
333   return -1;
334 }
335
336 /*********************************************************************
337  *              _unlink (MSVCRT.@)
338  */
339 int _unlink(const char *path)
340 {
341   TRACE("(%s)\n",path);
342   if(DeleteFileA(path))
343     return 0;
344   TRACE("failed (%ld)\n",GetLastError());
345   MSVCRT__set_errno(GetLastError());
346   return -1;
347 }
348
349 /*********************************************************************
350  *              _wunlink (MSVCRT.@)
351  */
352 int _wunlink(const WCHAR *path)
353 {
354   TRACE("(%s)\n",debugstr_w(path));
355   if(DeleteFileW(path))
356     return 0;
357   TRACE("failed (%ld)\n",GetLastError());
358   MSVCRT__set_errno(GetLastError());
359   return -1;
360 }
361
362 /*********************************************************************
363  *              _close (MSVCRT.@)
364  */
365 int _close(int fd)
366 {
367   HANDLE hand = msvcrt_fdtoh(fd);
368
369   TRACE(":fd (%d) handle (%p)\n",fd,hand);
370   if (hand == INVALID_HANDLE_VALUE)
371     return -1;
372   /* flush stdio buffers */
373   if(MSVCRT_files[fd]) {
374         if(MSVCRT_files[fd]->_flag & MSVCRT__IOWRT)
375                 MSVCRT_fflush(MSVCRT_files[fd]);
376
377         if(MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF)
378                 MSVCRT_free(MSVCRT_files[fd]->_base);
379   }
380
381   /* Dont free std FILE*'s, they are not dynamic */
382   if (fd > 2 && MSVCRT_files[fd])
383     MSVCRT_free(MSVCRT_files[fd]);
384
385   msvcrt_free_fd(fd);
386
387   if (!CloseHandle(hand))
388   {
389     WARN(":failed-last error (%ld)\n",GetLastError());
390     MSVCRT__set_errno(GetLastError());
391     return -1;
392   }
393   if (MSVCRT_tempfiles[fd])
394   {
395     TRACE("deleting temporary file '%s'\n",MSVCRT_tempfiles[fd]);
396     _unlink(MSVCRT_tempfiles[fd]);
397     MSVCRT_free(MSVCRT_tempfiles[fd]);
398     MSVCRT_tempfiles[fd] = NULL;
399   }
400
401   TRACE(":ok\n");
402   return 0;
403 }
404
405 /*********************************************************************
406  *              _commit (MSVCRT.@)
407  */
408 int _commit(int fd)
409 {
410   HANDLE hand = msvcrt_fdtoh(fd);
411
412   TRACE(":fd (%d) handle (%p)\n",fd,hand);
413   if (hand == INVALID_HANDLE_VALUE)
414     return -1;
415
416   if (!FlushFileBuffers(hand))
417   {
418     if (GetLastError() == ERROR_INVALID_HANDLE)
419     {
420       /* FlushFileBuffers fails for console handles
421        * so we ignore this error.
422        */
423       return 0;
424     }
425     TRACE(":failed-last error (%ld)\n",GetLastError());
426     MSVCRT__set_errno(GetLastError());
427     return -1;
428   }
429   TRACE(":ok\n");
430   return 0;
431 }
432
433 /*********************************************************************
434  *              _eof (MSVCRT.@)
435  */
436 int _eof(int fd)
437 {
438   DWORD curpos,endpos;
439   HANDLE hand = msvcrt_fdtoh(fd);
440
441   TRACE(":fd (%d) handle (%p)\n",fd,hand);
442
443   if (hand == INVALID_HANDLE_VALUE)
444     return -1;
445
446   /* If we have a FILE* for this file, the EOF flag
447    * will be set by the read()/write() functions.
448    */
449   if (MSVCRT_files[fd])
450     return MSVCRT_flags[fd] & MSVCRT__IOEOF;
451
452   /* Otherwise we do it the hard way */
453   curpos = SetFilePointer(hand, 0, NULL, SEEK_CUR);
454   endpos = SetFilePointer(hand, 0, NULL, FILE_END);
455
456   if (curpos == endpos)
457     return TRUE;
458
459   SetFilePointer(hand, curpos, 0, FILE_BEGIN);
460   return FALSE;
461 }
462
463 /*********************************************************************
464  *              _fcloseall (MSVCRT.@)
465  */
466 int _fcloseall(void)
467 {
468   int num_closed = 0, i;
469
470   for (i = 3; i < MSVCRT_fdend; i++)
471     if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
472     {
473       _close(i);
474       num_closed++;
475     }
476
477   TRACE(":closed (%d) handles\n",num_closed);
478   return num_closed;
479 }
480
481 /*********************************************************************
482  *              _lseek (MSVCRT.@)
483  */
484 LONG _lseek(int fd, LONG offset, int whence)
485 {
486   DWORD ret;
487   HANDLE hand = msvcrt_fdtoh(fd);
488
489   TRACE(":fd (%d) handle (%p)\n",fd,hand);
490   if (hand == INVALID_HANDLE_VALUE)
491     return -1;
492
493   if (whence < 0 || whence > 2)
494   {
495     *MSVCRT__errno() = MSVCRT_EINVAL;
496     return -1;
497   }
498
499   TRACE(":fd (%d) to 0x%08lx pos %s\n",
500         fd,offset,(whence==SEEK_SET)?"SEEK_SET":
501         (whence==SEEK_CUR)?"SEEK_CUR":
502         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
503
504   if ((ret = SetFilePointer(hand, offset, NULL, whence)) != 0xffffffff)
505   {
506     if (MSVCRT_files[fd])
507       MSVCRT_files[fd]->_flag &= ~MSVCRT__IOEOF;
508     /* FIXME: What if we seek _to_ EOF - is EOF set? */
509     return ret;
510   }
511   TRACE(":error-last error (%ld)\n",GetLastError());
512   if (MSVCRT_files[fd])
513     switch(GetLastError())
514     {
515     case ERROR_NEGATIVE_SEEK:
516     case ERROR_SEEK_ON_DEVICE:
517       MSVCRT__set_errno(GetLastError());
518       MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
519       break;
520     default:
521       break;
522     }
523   return -1;
524 }
525
526 /*********************************************************************
527  *              _locking (MSVCRT.@)
528  *
529  * This is untested; the underlying LockFile doesn't work yet.
530  */
531 int _locking(int fd, int mode, LONG nbytes)
532 {
533   BOOL ret;
534   DWORD cur_locn;
535   HANDLE hand = msvcrt_fdtoh(fd);
536
537   TRACE(":fd (%d) handle (%p)\n",fd,hand);
538   if (hand == INVALID_HANDLE_VALUE)
539     return -1;
540
541   if (mode < 0 || mode > 4)
542   {
543     *MSVCRT__errno() = MSVCRT_EINVAL;
544     return -1;
545   }
546
547   TRACE(":fd (%d) by 0x%08lx mode %s\n",
548         fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
549         (mode==_LK_LOCK)?"_LK_LOCK":
550         (mode==_LK_NBLCK)?"_LK_NBLCK":
551         (mode==_LK_RLCK)?"_LK_RLCK":
552         (mode==_LK_NBRLCK)?"_LK_NBRLCK":
553                           "UNKNOWN");
554
555   if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == 0xffffffff)
556   {
557     FIXME ("Seek failed\n");
558     *MSVCRT__errno() = MSVCRT_EINVAL; /* FIXME */
559     return -1;
560   }
561   if (mode == _LK_LOCK || mode == _LK_RLCK)
562   {
563     int nretry = 10;
564     ret = 1; /* just to satisfy gcc */
565     while (nretry--)
566     {
567       ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
568       if (ret) break;
569       sleep (1);
570     }
571   }
572   else if (mode == _LK_UNLCK)
573     ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
574   else
575     ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
576   /* FIXME - what about error settings? */
577   return ret ? 0 : -1;
578 }
579
580 /*********************************************************************
581  *              rewind (MSVCRT.@)
582  */
583 void MSVCRT_rewind(MSVCRT_FILE* file)
584 {
585   TRACE(":file (%p) fd (%d)\n",file,file->_file);
586   MSVCRT_fseek(file, 0L, SEEK_SET);
587   MSVCRT_clearerr(file);
588 }
589
590 /*********************************************************************
591  *              _fdopen (MSVCRT.@)
592  */
593 MSVCRT_FILE* _fdopen(int fd, const char *mode)
594 {
595   MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
596
597   TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file);
598   if (file)
599     MSVCRT_rewind(file);
600
601   return file;
602 }
603
604 /*********************************************************************
605  *              _wfdopen (MSVCRT.@)
606  */
607 MSVCRT_FILE* _wfdopen(int fd, const WCHAR *mode)
608 {
609   MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
610
611   TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,debugstr_w(mode),file);
612   if (file)
613     MSVCRT_rewind(file);
614
615   return file;
616 }
617
618 /*********************************************************************
619  *              _filelength (MSVCRT.@)
620  */
621 LONG _filelength(int fd)
622 {
623   LONG curPos = _lseek(fd, 0, SEEK_CUR);
624   if (curPos != -1)
625   {
626     LONG endPos = _lseek(fd, 0, SEEK_END);
627     if (endPos != -1)
628     {
629       if (endPos != curPos)
630         _lseek(fd, curPos, SEEK_SET);
631       return endPos;
632     }
633   }
634   return -1;
635 }
636
637 /*********************************************************************
638  *              _fileno (MSVCRT.@)
639  */
640 int _fileno(MSVCRT_FILE* file)
641 {
642   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
643   return file->_file;
644 }
645
646 /*********************************************************************
647  *              _flushall (MSVCRT.@)
648  */
649 int _flushall(void)
650 {
651   int num_flushed = 0, i = 3;
652
653   while(i < MSVCRT_fdend)
654     if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
655     {
656 #if 0
657       /* FIXME: flush, do not commit */
658       if (_commit(i) == -1)
659         if (MSVCRT_files[i])
660           MSVCRT_files[i]->_flag |= MSVCRT__IOERR;
661 #endif
662       if(MSVCRT_files[i] && MSVCRT_files[i]->_flag & MSVCRT__IOWRT) {
663         MSVCRT_fflush(MSVCRT_files[i]);
664         num_flushed++;
665       }
666     }
667
668   TRACE(":flushed (%d) handles\n",num_flushed);
669   return num_flushed;
670 }
671
672 /*********************************************************************
673  *              _fstat (MSVCRT.@)
674  */
675 int MSVCRT__fstat(int fd, struct _stat* buf)
676 {
677   DWORD dw;
678   BY_HANDLE_FILE_INFORMATION hfi;
679   HANDLE hand = msvcrt_fdtoh(fd);
680
681   TRACE(":fd (%d) stat (%p)\n",fd,buf);
682   if (hand == INVALID_HANDLE_VALUE)
683     return -1;
684
685   if (!buf)
686   {
687     WARN(":failed-NULL buf\n");
688     MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
689     return -1;
690   }
691
692   memset(&hfi, 0, sizeof(hfi));
693   memset(buf, 0, sizeof(struct _stat));
694   if (!GetFileInformationByHandle(hand, &hfi))
695   {
696     WARN(":failed-last error (%ld)\n",GetLastError());
697     MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
698     return -1;
699   }
700   FIXME(":dwFileAttributes = %ld, mode set to 0\n",hfi.dwFileAttributes);
701   buf->st_nlink = hfi.nNumberOfLinks;
702   buf->st_size  = hfi.nFileSizeLow;
703   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
704   buf->st_atime = dw;
705   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
706   buf->st_mtime = buf->st_ctime = dw;
707   return 0;
708 }
709
710 /*********************************************************************
711  *              _futime (MSVCRT.@)
712  */
713 int _futime(int fd, struct _utimbuf *t)
714 {
715   HANDLE hand = msvcrt_fdtoh(fd);
716   FILETIME at, wt;
717
718   if (!t)
719   {
720     MSVCRT_time_t currTime;
721     MSVCRT_time(&currTime);
722     RtlSecondsSince1970ToTime(currTime, (LARGE_INTEGER *)&at);
723     memcpy(&wt, &at, sizeof(wt));
724   }
725   else
726   {
727     RtlSecondsSince1970ToTime(t->actime, (LARGE_INTEGER *)&at);
728     if (t->actime == t->modtime)
729       memcpy(&wt, &at, sizeof(wt));
730     else
731       RtlSecondsSince1970ToTime(t->modtime, (LARGE_INTEGER *)&wt);
732   }
733
734   if (!SetFileTime(hand, NULL, &at, &wt))
735   {
736     MSVCRT__set_errno(GetLastError());
737     return -1 ;
738   }
739   return 0;
740 }
741
742 /*********************************************************************
743  *              _get_osfhandle (MSVCRT.@)
744  */
745 long _get_osfhandle(int fd)
746 {
747   HANDLE hand = msvcrt_fdtoh(fd);
748   HANDLE newhand = hand;
749   TRACE(":fd (%d) handle (%p)\n",fd,hand);
750
751   if (hand != INVALID_HANDLE_VALUE)
752   {
753     /* FIXME: I'm not convinced that I should be copying the
754      * handle here - it may be leaked if the app doesn't
755      * close it (and the API docs dont say that it should)
756      * Not duplicating it means that it can't be inherited
757      * and so lcc's wedit doesn't cope when it passes it to
758      * child processes. I've an idea that it should either
759      * be copied by CreateProcess, or marked as inheritable
760      * when initialised, or maybe both? JG 21-9-00.
761      */
762     DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(),
763                     &newhand,0,TRUE,DUPLICATE_SAME_ACCESS);
764   }
765   return (long)newhand;
766 }
767
768 /*********************************************************************
769  *              _isatty (MSVCRT.@)
770  */
771 int _isatty(int fd)
772 {
773   HANDLE hand = msvcrt_fdtoh(fd);
774
775   TRACE(":fd (%d) handle (%p)\n",fd,hand);
776   if (hand == INVALID_HANDLE_VALUE)
777     return 0;
778
779   return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
780 }
781
782 /*********************************************************************
783  *              _mktemp (MSVCRT.@)
784  */
785 char *_mktemp(char *pattern)
786 {
787   int numX = 0;
788   char *retVal = pattern;
789   int id;
790   char letter = 'a';
791
792   while(*pattern)
793     numX = (*pattern++ == 'X')? numX + 1 : 0;
794   if (numX < 5)
795     return NULL;
796   pattern--;
797   id = GetCurrentProcessId();
798   numX = 6;
799   while(numX--)
800   {
801     int tempNum = id / 10;
802     *pattern-- = id - (tempNum * 10) + '0';
803     id = tempNum;
804   }
805   pattern++;
806   do
807   {
808     if (GetFileAttributesA(retVal) == 0xFFFFFFFF &&
809         GetLastError() == ERROR_FILE_NOT_FOUND)
810       return retVal;
811     *pattern = letter++;
812   } while(letter != '|');
813   return NULL;
814 }
815
816 /*********************************************************************
817  *              _wmktemp (MSVCRT.@)
818  */
819 WCHAR *_wmktemp(WCHAR *pattern)
820 {
821   int numX = 0;
822   WCHAR *retVal = pattern;
823   int id;
824   WCHAR letter = (WCHAR)L'a';
825
826   while(*pattern)
827     numX = (*pattern++ == (WCHAR)L'X')? numX + 1 : 0;
828   if (numX < 5)
829     return NULL;
830   pattern--;
831   id = GetCurrentProcessId();
832   numX = 6;
833   while(numX--)
834   {
835     int tempNum = id / 10;
836     *pattern-- = id - (tempNum * 10) + (WCHAR)L'0';
837     id = tempNum;
838   }
839   pattern++;
840   do
841   {
842     if (GetFileAttributesW(retVal) == 0xFFFFFFFF &&
843         GetLastError() == ERROR_FILE_NOT_FOUND)
844       return retVal;
845     *pattern = letter++;
846   } while(letter != (WCHAR)L'|');
847   return NULL;
848 }
849
850 /*********************************************************************
851  *              _sopen (MSVCRT.@)
852  */
853 int MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
854 {
855   va_list ap;
856   int pmode;
857   DWORD access = 0, creation = 0;
858   DWORD sharing;
859   int ioflag = 0, fd;
860   HANDLE hand;
861   SECURITY_ATTRIBUTES sa;
862
863
864   TRACE(":file (%s) oflags: 0x%04x shflags: 0x%04x\n",
865         path, oflags, shflags);
866
867   switch(oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
868   {
869   case _O_RDONLY:
870     access |= GENERIC_READ;
871     ioflag |= MSVCRT__IOREAD;
872     break;
873   case _O_WRONLY:
874     access |= GENERIC_WRITE;
875     ioflag |= MSVCRT__IOWRT;
876     break;
877   case _O_RDWR:
878     access |= GENERIC_WRITE | GENERIC_READ;
879     ioflag |= MSVCRT__IORW;
880     break;
881   }
882
883   if (oflags & _O_CREAT)
884   {
885     va_start(ap, shflags);
886       pmode = va_arg(ap, int);
887     va_end(ap);
888
889     FIXME(": pmode 0x%04x ignored\n", pmode);
890
891     if (oflags & _O_EXCL)
892       creation = CREATE_NEW;
893     else if (oflags & _O_TRUNC)
894       creation = CREATE_ALWAYS;
895     else
896       creation = OPEN_ALWAYS;
897   }
898   else  /* no _O_CREAT */
899   {
900     if (oflags & _O_TRUNC)
901       creation = TRUNCATE_EXISTING;
902     else
903       creation = OPEN_EXISTING;
904   }
905   if (oflags & _O_APPEND)
906     ioflag |= MSVCRT__IOAPPEND;
907
908
909   oflags |= _O_BINARY; /* FIXME: Default to text */
910
911   if (oflags & _O_TEXT)
912   {
913     /* Dont warn when writing */
914     if (ioflag & GENERIC_READ)
915       FIXME(":TEXT node not implemented\n");
916     oflags &= ~_O_TEXT;
917   }
918
919   switch( shflags )
920   {
921     case _SH_DENYRW:
922       sharing = 0L;
923       break;
924     case _SH_DENYWR:
925       sharing = FILE_SHARE_READ;
926       break;
927     case _SH_DENYRD:
928       sharing = FILE_SHARE_WRITE;
929       break;
930     case _SH_DENYNO:
931       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
932       break;
933     default:
934       ERR( "Unhandled shflags 0x%x\n", shflags );
935       return -1;
936   }
937
938   if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL
939                 |_O_CREAT|_O_RDWR|_O_TEMPORARY|_O_NOINHERIT))
940     TRACE(":unsupported oflags 0x%04x\n",oflags);
941
942   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
943   sa.lpSecurityDescriptor = NULL;
944   sa.bInheritHandle       = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
945
946   hand = CreateFileA(path, access, sharing,
947                       &sa, creation, FILE_ATTRIBUTE_NORMAL, 0);
948
949   if (hand == INVALID_HANDLE_VALUE)  {
950     WARN(":failed-last error (%ld)\n",GetLastError());
951     MSVCRT__set_errno(GetLastError());
952     return -1;
953   }
954
955   fd = msvcrt_alloc_fd(hand, ioflag);
956
957   TRACE(":fd (%d) handle (%p)\n",fd, hand);
958
959   if (fd > 0)
960   {
961     if (oflags & _O_TEMPORARY)
962       MSVCRT_tempfiles[fd] = _strdup(path);
963     if (ioflag & MSVCRT__IOAPPEND)
964       _lseek(fd, 0, FILE_END);
965   }
966
967   return fd;
968 }
969
970 /*********************************************************************
971  *              _wsopen (MSVCRT.@)
972  */
973 int MSVCRT__wsopen( const WCHAR* path, int oflags, int shflags, ... )
974 {
975   const unsigned int len = strlenW(path);
976   char *patha = MSVCRT_calloc(len + 1,1);
977   va_list ap;
978   int pmode;
979
980   va_start(ap, shflags);
981   pmode = va_arg(ap, int);
982   va_end(ap);
983
984   if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
985   {
986     int retval = MSVCRT__sopen(patha,oflags,shflags,pmode);
987     MSVCRT_free(patha);
988     return retval;
989   }
990
991   MSVCRT__set_errno(GetLastError());
992   return -1;
993 }
994
995 /*********************************************************************
996  *              _open (MSVCRT.@)
997  */
998 int _open( const char *path, int flags, ... )
999 {
1000   va_list ap;
1001   int pmode;
1002
1003   va_start(ap, flags);
1004   pmode = va_arg(ap, int);
1005   va_end(ap);
1006
1007   return MSVCRT__sopen( path, flags, _SH_DENYNO, pmode );
1008 }
1009
1010 /*********************************************************************
1011  *              _wopen (MSVCRT.@)
1012  */
1013 int _wopen(const WCHAR *path,int flags,...)
1014 {
1015   const unsigned int len = strlenW(path);
1016   char *patha = MSVCRT_calloc(len + 1,1);
1017   va_list ap;
1018   int pmode;
1019
1020   va_start(ap, flags);
1021   pmode = va_arg(ap, int);
1022   va_end(ap);
1023
1024   if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
1025   {
1026     int retval = _open(patha,flags,pmode);
1027     MSVCRT_free(patha);
1028     return retval;
1029   }
1030
1031   MSVCRT__set_errno(GetLastError());
1032   return -1;
1033 }
1034
1035 /*********************************************************************
1036  *              _creat (MSVCRT.@)
1037  */
1038 int _creat(const char *path, int flags)
1039 {
1040   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
1041   return _open(path, usedFlags);
1042 }
1043
1044 /*********************************************************************
1045  *              _wcreat (MSVCRT.@)
1046  */
1047 int _wcreat(const WCHAR *path, int flags)
1048 {
1049   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
1050   return _wopen(path, usedFlags);
1051 }
1052
1053 /*********************************************************************
1054  *              _open_osfhandle (MSVCRT.@)
1055  */
1056 int _open_osfhandle(long hand, int flags)
1057 {
1058   /* _O_RDONLY (0) always matches, so set the read flag*/
1059   /* FIXME: handle more flags */
1060   int fd= msvcrt_alloc_fd((HANDLE)hand,flags|MSVCRT__IOREAD);
1061   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n",hand,fd, flags |MSVCRT__IOREAD);
1062   return fd;
1063 }
1064
1065 /*********************************************************************
1066  *              _rmtmp (MSVCRT.@)
1067  */
1068 int _rmtmp(void)
1069 {
1070   int num_removed = 0, i;
1071
1072   for (i = 3; i < MSVCRT_fdend; i++)
1073     if (MSVCRT_tempfiles[i])
1074     {
1075       _close(i);
1076       num_removed++;
1077     }
1078
1079   if (num_removed)
1080     TRACE(":removed (%d) temp files\n",num_removed);
1081   return num_removed;
1082 }
1083
1084 /*********************************************************************
1085  *              _read (MSVCRT.@)
1086  */
1087 int _read(int fd, void *buf, unsigned int count)
1088 {
1089   DWORD num_read;
1090   HANDLE hand = msvcrt_fdtoh(fd);
1091
1092   /* Dont trace small reads, it gets *very* annoying */
1093   if (count > 4)
1094     TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
1095   if (hand == INVALID_HANDLE_VALUE)
1096     return -1;
1097
1098   if (ReadFile(hand, buf, count, &num_read, NULL))
1099   {
1100     if (num_read != count && MSVCRT_files[fd])
1101     {
1102       TRACE(":EOF\n");
1103         MSVCRT_flags[fd] |= MSVCRT__IOEOF;
1104 /*
1105       MSVCRT_files[fd]->_flag |= MSVCRT__IOEOF;
1106 */
1107     }
1108     return num_read;
1109   }
1110   TRACE(":failed-last error (%ld)\n",GetLastError());
1111   if (MSVCRT_files[fd])
1112      MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1113   return -1;
1114 }
1115
1116 /*********************************************************************
1117  *              _getw (MSVCRT.@)
1118  */
1119 int _getw(MSVCRT_FILE* file)
1120 {
1121   int i;
1122   if (_read(file->_file, &i, sizeof(int)) != 1)
1123     return MSVCRT_EOF;
1124   return i;
1125 }
1126
1127 /*********************************************************************
1128  *              _setmode (MSVCRT.@)
1129  */
1130 int _setmode(int fd,int mode)
1131 {
1132   if (mode & _O_TEXT)
1133     FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode);
1134   return 0;
1135 }
1136
1137 /*********************************************************************
1138  *              _stat (MSVCRT.@)
1139  */
1140 int MSVCRT__stat(const char* path, struct _stat * buf)
1141 {
1142   DWORD dw;
1143   WIN32_FILE_ATTRIBUTE_DATA hfi;
1144   unsigned short mode = MSVCRT_S_IREAD;
1145   int plen;
1146
1147   TRACE(":file (%s) buf(%p)\n",path,buf);
1148
1149   if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
1150   {
1151       TRACE("failed (%ld)\n",GetLastError());
1152       MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1153       return -1;
1154   }
1155
1156   memset(buf,0,sizeof(struct _stat));
1157
1158   /* FIXME: rdev isnt drive num,despite what the docs say-what is it?
1159      Bon 011120: This FIXME seems incorrect
1160                  Also a letter as first char isn't enough to be classify
1161                  as drive letter
1162   */
1163   if (isalpha(*path)&& (*(path+1)==':'))
1164     buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
1165   else
1166     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1167
1168   plen = strlen(path);
1169
1170   /* Dir, or regular file? */
1171   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1172       (path[plen-1] == '\\'))
1173     mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1174   else
1175   {
1176     mode |= _S_IFREG;
1177     /* executable? */
1178     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
1179     {
1180       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
1181                                  (tolower(path[plen-3]) << 16);
1182       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
1183           mode |= MSVCRT_S_IEXEC;
1184     }
1185   }
1186
1187   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1188     mode |= MSVCRT_S_IWRITE;
1189
1190   buf->st_mode  = mode;
1191   buf->st_nlink = 1;
1192   buf->st_size  = hfi.nFileSizeLow;
1193   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1194   buf->st_atime = dw;
1195   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1196   buf->st_mtime = buf->st_ctime = dw;
1197   TRACE("\n%d %d %d %ld %ld %ld\n", buf->st_mode,buf->st_nlink,buf->st_size,
1198     buf->st_atime,buf->st_mtime, buf->st_ctime);
1199   return 0;
1200 }
1201
1202 /*********************************************************************
1203  *              _wstat (MSVCRT.@)
1204  */
1205 int _wstat(const WCHAR* path, struct _stat * buf)
1206 {
1207   DWORD dw;
1208   WIN32_FILE_ATTRIBUTE_DATA hfi;
1209   unsigned short mode = MSVCRT_S_IREAD;
1210   int plen;
1211
1212   TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
1213
1214   if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
1215   {
1216       TRACE("failed (%ld)\n",GetLastError());
1217       MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1218       return -1;
1219   }
1220
1221   memset(buf,0,sizeof(struct _stat));
1222
1223   /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
1224   if (MSVCRT_iswalpha(*path))
1225     buf->st_dev = buf->st_rdev = toupperW(*path - (WCHAR)L'A'); /* drive num */
1226   else
1227     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1228
1229   plen = strlenW(path);
1230
1231   /* Dir, or regular file? */
1232   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1233       (path[plen-1] == (WCHAR)L'\\'))
1234     mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1235   else
1236   {
1237     mode |= _S_IFREG;
1238     /* executable? */
1239     if (plen > 6 && path[plen-4] == (WCHAR)L'.')  /* shortest exe: "\x.exe" */
1240     {
1241       ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
1242                                ((ULONGLONG)tolowerW(path[plen-3]) << 32);
1243       if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
1244         mode |= MSVCRT_S_IEXEC;
1245     }
1246   }
1247
1248   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1249     mode |= MSVCRT_S_IWRITE;
1250
1251   buf->st_mode  = mode;
1252   buf->st_nlink = 1;
1253   buf->st_size  = hfi.nFileSizeLow;
1254   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1255   buf->st_atime = dw;
1256   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1257   buf->st_mtime = buf->st_ctime = dw;
1258   TRACE("\n%d %d %d %ld %ld %ld\n", buf->st_mode,buf->st_nlink,buf->st_size,
1259         buf->st_atime,buf->st_mtime, buf->st_ctime);
1260   return 0;
1261 }
1262
1263 /*********************************************************************
1264  *              _tell (MSVCRT.@)
1265  */
1266 LONG _tell(int fd)
1267 {
1268   return _lseek(fd, 0, SEEK_CUR);
1269 }
1270
1271 /*********************************************************************
1272  *              _tempnam (MSVCRT.@)
1273  */
1274 char *_tempnam(const char *dir, const char *prefix)
1275 {
1276   char tmpbuf[MAX_PATH];
1277
1278   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
1279   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
1280   {
1281     TRACE("got name (%s)\n",tmpbuf);
1282     return _strdup(tmpbuf);
1283   }
1284   TRACE("failed (%ld)\n",GetLastError());
1285   return NULL;
1286 }
1287
1288 /*********************************************************************
1289  *              _wtempnam (MSVCRT.@)
1290  */
1291 WCHAR *_wtempnam(const WCHAR *dir, const WCHAR *prefix)
1292 {
1293   WCHAR tmpbuf[MAX_PATH];
1294
1295   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
1296   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
1297   {
1298     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
1299     return _wcsdup(tmpbuf);
1300   }
1301   TRACE("failed (%ld)\n",GetLastError());
1302   return NULL;
1303 }
1304
1305 /*********************************************************************
1306  *              _umask (MSVCRT.@)
1307  */
1308 int _umask(int umask)
1309 {
1310   int old_umask = MSVCRT_umask;
1311   TRACE("(%d)\n",umask);
1312   MSVCRT_umask = umask;
1313   return old_umask;
1314 }
1315
1316 /*********************************************************************
1317  *              _utime (MSVCRT.@)
1318  */
1319 int _utime(const char* path, struct _utimbuf *t)
1320 {
1321   int fd = _open(path, _O_WRONLY | _O_BINARY);
1322
1323   if (fd > 0)
1324   {
1325     int retVal = _futime(fd, t);
1326     _close(fd);
1327     return retVal;
1328   }
1329   return -1;
1330 }
1331
1332 /*********************************************************************
1333  *              _wutime (MSVCRT.@)
1334  */
1335 int _wutime(const WCHAR* path, struct _utimbuf *t)
1336 {
1337   int fd = _wopen(path, _O_WRONLY | _O_BINARY);
1338
1339   if (fd > 0)
1340   {
1341     int retVal = _futime(fd, t);
1342     _close(fd);
1343     return retVal;
1344   }
1345   return -1;
1346 }
1347
1348 /*********************************************************************
1349  *              _write (MSVCRT.@)
1350  */
1351 int _write(int fd, const void* buf, unsigned int count)
1352 {
1353   DWORD num_written;
1354   HANDLE hand = msvcrt_fdtoh(fd);
1355
1356   /* Dont trace small writes, it gets *very* annoying */
1357 #if 0
1358   if (count > 32)
1359     TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
1360 #endif
1361   if (hand == INVALID_HANDLE_VALUE)
1362     return -1;
1363
1364   /* If appending, go to EOF */
1365   if (MSVCRT_flags[fd] & MSVCRT__IOAPPEND)
1366     _lseek(fd, 0, FILE_END);
1367
1368   if (WriteFile(hand, buf, count, &num_written, NULL)
1369       &&  (num_written == count))
1370     return num_written;
1371
1372   TRACE(":failed-last error (%ld)\n",GetLastError());
1373   if (MSVCRT_files[fd])
1374      MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1375
1376   return -1;
1377 }
1378
1379 /*********************************************************************
1380  *              _putw (MSVCRT.@)
1381  */
1382 int _putw(int val, MSVCRT_FILE* file)
1383 {
1384   return _write(file->_file, &val, sizeof(val)) == 1? val : MSVCRT_EOF;
1385 }
1386
1387 /*********************************************************************
1388  *              clearerr (MSVCRT.@)
1389  */
1390 void MSVCRT_clearerr(MSVCRT_FILE* file)
1391 {
1392   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1393   file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
1394 }
1395
1396 /*********************************************************************
1397  *              fclose (MSVCRT.@)
1398  */
1399 int MSVCRT_fclose(MSVCRT_FILE* file)
1400 {
1401   int r;
1402   r=_close(file->_file);
1403   return ((r==MSVCRT_EOF) || (file->_flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
1404 }
1405
1406 /*********************************************************************
1407  *              feof (MSVCRT.@)
1408  */
1409 int MSVCRT_feof(MSVCRT_FILE* file)
1410 {
1411   return file->_flag & MSVCRT__IOEOF;
1412 }
1413
1414 /*********************************************************************
1415  *              ferror (MSVCRT.@)
1416  */
1417 int MSVCRT_ferror(MSVCRT_FILE* file)
1418 {
1419   return file->_flag & MSVCRT__IOERR;
1420 }
1421
1422 /*********************************************************************
1423  *              fflush (MSVCRT.@)
1424  */
1425 int MSVCRT_fflush(MSVCRT_FILE* file)
1426 {
1427   if(!file) {
1428         _flushall();
1429         return 0;
1430   } else {
1431         int res=msvcrt_flush_buffer(file);
1432         return res;
1433   }
1434 }
1435
1436 /*********************************************************************
1437  *              fgetc (MSVCRT.@)
1438  */
1439 int MSVCRT_fgetc(MSVCRT_FILE* file)
1440 {
1441   if (file->_cnt>0) {
1442         file->_cnt--;
1443         return *(unsigned char *)file->_ptr++;
1444   } else {
1445         return _filbuf(file);
1446   }
1447 }
1448
1449 /*********************************************************************
1450  *              _fgetchar (MSVCRT.@)
1451  */
1452 int _fgetchar(void)
1453 {
1454   return MSVCRT_fgetc(MSVCRT_stdin);
1455 }
1456
1457 /*********************************************************************
1458  *              _filbuf (MSVCRT.@)
1459  */
1460 int _filbuf(MSVCRT_FILE* file)
1461 {
1462
1463   /* Allocate buffer if needed */
1464   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF) ) {
1465         msvcrt_alloc_buffer(file);
1466   }
1467   if(!(file->_flag & MSVCRT__IOREAD)) {
1468         if(file->_flag & MSVCRT__IORW) {
1469                 file->_flag |= MSVCRT__IOREAD;
1470         } else {
1471                 return MSVCRT_EOF;
1472         }
1473   }
1474   if(file->_flag & MSVCRT__IONBF) {
1475         unsigned char c;
1476         if (_read(file->_file,&c,1) != 1) {
1477                 file->_flag |= MSVCRT__IOEOF;
1478                 return MSVCRT_EOF;
1479         }
1480         return c;
1481   } else {
1482         file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
1483         if(file->_cnt<0) file->_cnt = 0;
1484         if(!file->_cnt) {
1485                 file->_flag |= MSVCRT__IOEOF;
1486                 return MSVCRT_EOF;
1487         }
1488         file->_cnt--;
1489         file->_ptr = file->_base+1;
1490         return *(unsigned char *)file->_base;
1491   }
1492 }
1493
1494 /*********************************************************************
1495  *              fgetpos (MSVCRT.@)
1496  */
1497 int MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
1498 {
1499   *pos = MSVCRT_ftell(file);
1500   return (*pos == -1? -1 : 0);
1501 }
1502
1503 /*********************************************************************
1504  *              fgets (MSVCRT.@)
1505  */
1506 char *MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
1507 {
1508   int    cc;
1509   char * buf_start = s;
1510
1511   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1512         file,file->_file,s,size);
1513
1514   for(cc = MSVCRT_fgetc(file); cc != MSVCRT_EOF && cc != '\n';
1515       cc = MSVCRT_fgetc(file))
1516     if (cc != '\r')
1517     {
1518       if (--size <= 0) break;
1519       *s++ = (char)cc;
1520     }
1521   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
1522   {
1523     TRACE(":nothing read\n");
1524     return 0;
1525   }
1526   if (cc == '\n')
1527     if (--size > 0)
1528       *s++ = '\n';
1529   *s = '\0';
1530   TRACE(":got '%s'\n", buf_start);
1531   return buf_start;
1532 }
1533
1534 /*********************************************************************
1535  *              fgetwc (MSVCRT.@)
1536  */
1537 MSVCRT_wint_t MSVCRT_fgetwc(MSVCRT_FILE* file)
1538 {
1539   WCHAR wc;
1540   if (_read(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1541     return MSVCRT_WEOF;
1542   return wc;
1543 }
1544
1545 /*********************************************************************
1546  *              getwc (MSVCRT.@)
1547  */
1548 MSVCRT_wint_t MSVCRT_getwc(MSVCRT_FILE* file)
1549 {
1550   return MSVCRT_fgetwc(file);
1551 }
1552
1553 /*********************************************************************
1554  *              _fgetwchar (MSVCRT.@)
1555  */
1556 MSVCRT_wint_t _fgetwchar(void)
1557 {
1558   return MSVCRT_fgetwc(MSVCRT_stdin);
1559 }
1560
1561 /*********************************************************************
1562  *              getwchar (MSVCRT.@)
1563  */
1564 MSVCRT_wint_t MSVCRT_getwchar(void)
1565 {
1566   return _fgetwchar();
1567 }
1568
1569 /*********************************************************************
1570  *              fgetws (MSVCRT.@)
1571  */
1572 WCHAR *MSVCRT_fgetws(WCHAR *s, int size, MSVCRT_FILE* file)
1573 {
1574   int    cc;
1575   WCHAR * buf_start = s;
1576
1577   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1578         file,file->_file,s,size);
1579
1580   for(cc = MSVCRT_fgetwc(file); cc != MSVCRT_WEOF && cc != L'\n';
1581       cc = MSVCRT_fgetwc(file))
1582     if (cc != L'\r')
1583     {
1584       if (--size <= 0) break;
1585       *s++ = cc;
1586     }
1587   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
1588   {
1589     TRACE(":nothing read\n");
1590     return 0;
1591   }
1592   if (cc == L'\n')
1593     if (--size > 0)
1594       *s++ = '\n';
1595   *s = '\0';
1596 /*  TRACE(":got '%s'\n", buf_start); */
1597   return buf_start;
1598 }
1599
1600
1601 /*********************************************************************
1602  *              fputwc (MSVCRT.@)
1603  */
1604 MSVCRT_wint_t MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
1605 {
1606   WCHAR mwc=wc;
1607   if (MSVCRT_fwrite( &mwc, sizeof(mwc), 1, file) != 1)
1608     return MSVCRT_WEOF;
1609   return wc;
1610 }
1611
1612 /*********************************************************************
1613  *              _fputwchar (MSVCRT.@)
1614  */
1615 MSVCRT_wint_t _fputwchar(MSVCRT_wint_t wc)
1616 {
1617   return MSVCRT_fputwc(wc, MSVCRT_stdout);
1618 }
1619
1620 /*********************************************************************
1621  *              fopen (MSVCRT.@)
1622  */
1623 MSVCRT_FILE* MSVCRT_fopen(const char *path, const char *mode)
1624 {
1625   MSVCRT_FILE* file;
1626   int flags = 0, plus = 0, fd;
1627   const char* search = mode;
1628
1629   TRACE("(%s,%s)\n",path,mode);
1630
1631   while (*search)
1632     if (*search++ == '+')
1633       plus = 1;
1634
1635   /* map mode string to open() flags. "man fopen" for possibilities. */
1636   switch(*mode++)
1637   {
1638   case 'R': case 'r':
1639     flags = (plus ? _O_RDWR : _O_RDONLY);
1640     break;
1641   case 'W': case 'w':
1642     flags = _O_CREAT | _O_TRUNC | (plus  ? _O_RDWR : _O_WRONLY);
1643     break;
1644   case 'A': case 'a':
1645     flags = _O_CREAT | _O_APPEND | (plus  ? _O_RDWR : _O_WRONLY);
1646     break;
1647   default:
1648     return NULL;
1649   }
1650
1651   while (*mode)
1652     switch (*mode++)
1653     {
1654     case 'B': case 'b':
1655       flags |=  _O_BINARY;
1656       flags &= ~_O_TEXT;
1657       break;
1658     case 'T': case 't':
1659       flags |=  _O_TEXT;
1660       flags &= ~_O_BINARY;
1661       break;
1662     case '+':
1663       break;
1664     default:
1665       FIXME(":unknown flag %c not supported\n",mode[-1]);
1666     }
1667
1668   fd = _open(path, flags);
1669
1670   if (fd < 0)
1671     return NULL;
1672
1673   file = msvcrt_alloc_fp(fd);
1674   TRACE(":got (%p)\n",file);
1675   if (!file)
1676     _close(fd);
1677
1678   return file;
1679 }
1680
1681 /*********************************************************************
1682  *              _wfopen (MSVCRT.@)
1683  */
1684 MSVCRT_FILE *_wfopen(const WCHAR *path, const WCHAR *mode)
1685 {
1686   const unsigned int plen = strlenW(path), mlen = strlenW(mode);
1687   char *patha = MSVCRT_calloc(plen + 1, 1);
1688   char *modea = MSVCRT_calloc(mlen + 1, 1);
1689
1690   TRACE("(%s,%s)\n",debugstr_w(path),debugstr_w(mode));
1691
1692   if (patha && modea &&
1693       WideCharToMultiByte(CP_ACP,0,path,plen,patha,plen,NULL,NULL) &&
1694       WideCharToMultiByte(CP_ACP,0,mode,mlen,modea,mlen,NULL,NULL))
1695   {
1696     MSVCRT_FILE *retval = MSVCRT_fopen(patha,modea);
1697     MSVCRT_free(patha);
1698     MSVCRT_free(modea);
1699     return retval;
1700   }
1701
1702   MSVCRT__set_errno(GetLastError());
1703   return NULL;
1704 }
1705
1706 /*********************************************************************
1707  *              _fsopen (MSVCRT.@)
1708  */
1709 MSVCRT_FILE*  _fsopen(const char *path, const char *mode, int share)
1710 {
1711   FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share);
1712   return MSVCRT_fopen(path,mode);
1713 }
1714
1715 /*********************************************************************
1716  *              _wfsopen (MSVCRT.@)
1717  */
1718 MSVCRT_FILE*  _wfsopen(const WCHAR *path, const WCHAR *mode, int share)
1719 {
1720   FIXME(":(%s,%s,%d),ignoring share mode!\n",
1721         debugstr_w(path),debugstr_w(mode),share);
1722   return _wfopen(path,mode);
1723 }
1724
1725 /*********************************************************************
1726  *              fputc (MSVCRT.@)
1727  */
1728 int MSVCRT_fputc(int c, MSVCRT_FILE* file)
1729 {
1730   if(file->_cnt>0) {
1731         *file->_ptr++=c;
1732         file->_cnt--;
1733         return c;
1734   } else {
1735         return _flsbuf(c, file);
1736   }
1737 }
1738
1739 /*********************************************************************
1740  *              _flsbuf (MSVCRT.@)
1741  */
1742 int _flsbuf(int c, MSVCRT_FILE* file)
1743 {
1744   /* Flush output buffer */
1745   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
1746         msvcrt_alloc_buffer(file);
1747   }
1748   if(!(file->_flag & MSVCRT__IOWRT)) {
1749         if(file->_flag & MSVCRT__IORW) {
1750                 file->_flag |= MSVCRT__IOWRT;
1751         } else {
1752                 return MSVCRT_EOF;
1753         }
1754   }
1755   if(file->_bufsiz) {
1756         int res=msvcrt_flush_buffer(file);
1757         return res?res : MSVCRT_fputc(c, file);
1758   } else {
1759         unsigned char cc=c;
1760         return _write(file->_file, &cc, 1) == 1? c : MSVCRT_EOF;
1761   }
1762 }
1763
1764 /*********************************************************************
1765  *              _fputchar (MSVCRT.@)
1766  */
1767 int _fputchar(int c)
1768 {
1769   return MSVCRT_fputc(c, MSVCRT_stdout);
1770 }
1771
1772 /*********************************************************************
1773  *              fread (MSVCRT.@)
1774  */
1775 MSVCRT_size_t MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
1776 { MSVCRT_size_t rcnt=size * nmemb;
1777   MSVCRT_size_t read=0;
1778   int pread=0;
1779   /* first buffered data */
1780   if(file->_cnt>0) {
1781         int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
1782         memcpy(ptr, file->_ptr, pcnt);
1783         file->_cnt -= pcnt;
1784         file->_ptr += pcnt;
1785         read += pcnt ;
1786         rcnt -= pcnt ;
1787        ptr = (char*)ptr + pcnt;
1788   } else if(!(file->_flag & MSVCRT__IOREAD )) {
1789         if(file->_flag & MSVCRT__IORW) {
1790                 file->_flag |= MSVCRT__IOREAD;
1791         } else
1792                 return 0;
1793   }
1794   if(rcnt) pread = _read(file->_file,ptr, rcnt);
1795   if (MSVCRT_flags[file->_file] & MSVCRT__IOEOF)
1796      /* expose feof condition in the flags
1797         MFC tests file->_flag for feof, and doesn't not call feof())
1798     */
1799     file->_flag |= MSVCRT__IOEOF;
1800   if (pread <= 0)
1801     pread = 0;
1802   read+=pread;
1803   return read / size;
1804 }
1805
1806 /*********************************************************************
1807  *              freopen (MSVCRT.@)
1808  *
1809  */
1810 MSVCRT_FILE* MSVCRT_freopen(const char *path, const char *mode,MSVCRT_FILE* file)
1811 {
1812   MSVCRT_FILE* newfile;
1813   int fd;
1814
1815   TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file);
1816   if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
1817     return NULL;
1818
1819   if (fd > 2)
1820   {
1821 #if 0
1822     FIXME(":reopen on user file not implemented!\n");
1823     MSVCRT__set_errno(ERROR_CALL_NOT_IMPLEMENTED);
1824     return NULL;
1825 #endif
1826     if(MSVCRT_fclose(file))
1827         return NULL;
1828     return MSVCRT_fopen(path, mode);
1829   }
1830
1831   /* first, create the new file */
1832   if ((newfile = MSVCRT_fopen(path,mode)) == NULL)
1833     return NULL;
1834
1835   if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE :
1836      (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE),
1837       MSVCRT_handles[newfile->_file]))
1838   {
1839     /* Redirecting std handle to file , copy over.. */
1840     MSVCRT_handles[fd] = MSVCRT_handles[newfile->_file];
1841     MSVCRT_flags[fd] = MSVCRT_flags[newfile->_file];
1842     memcpy(&MSVCRT__iob[fd], newfile, sizeof (MSVCRT_FILE));
1843     MSVCRT__iob[fd]._file = fd;
1844     /* And free up the resources allocated by fopen, but
1845      * not the HANDLE we copied. */
1846     MSVCRT_free(MSVCRT_files[fd]);
1847     msvcrt_free_fd(newfile->_file);
1848     return &MSVCRT__iob[fd];
1849   }
1850
1851   WARN(":failed-last error (%ld)\n",GetLastError());
1852   MSVCRT_fclose(newfile);
1853   MSVCRT__set_errno(GetLastError());
1854   return NULL;
1855 }
1856
1857 /*********************************************************************
1858  *              fsetpos (MSVCRT.@)
1859  */
1860 int MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
1861 {
1862   return _lseek(file->_file,*pos,SEEK_SET);
1863 }
1864
1865 /*********************************************************************
1866  *              fseek (MSVCRT.@)
1867  */
1868 int MSVCRT_fseek(MSVCRT_FILE* file, long offset, int whence)
1869 {
1870   /* Flush output if needed */
1871   if(file->_flag & MSVCRT__IOWRT)
1872         msvcrt_flush_buffer(file);
1873
1874   if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) {
1875         offset -= file->_cnt;
1876   }
1877   /* Discard buffered input */
1878   file->_cnt = 0;
1879   file->_ptr = file->_base;
1880   /* Reset direction of i/o */
1881   if(file->_flag & MSVCRT__IORW) {
1882         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
1883   }
1884   return (_lseek(file->_file,offset,whence) == -1)?-1:0;
1885 }
1886
1887 /*********************************************************************
1888  *              ftell (MSVCRT.@)
1889  */
1890 LONG MSVCRT_ftell(MSVCRT_FILE* file)
1891 {
1892   int off=0;
1893   long pos;
1894   if(file->_bufsiz)  {
1895         if( file->_flag & MSVCRT__IOWRT ) {
1896                 off = file->_ptr - file->_base;
1897         } else {
1898                 off = -file->_cnt;
1899         }
1900   }
1901   pos = _tell(file->_file);
1902   if(pos == -1) return pos;
1903   return off + pos;
1904 }
1905
1906 /*********************************************************************
1907  *              fwrite (MSVCRT.@)
1908  */
1909 MSVCRT_size_t MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
1910 {
1911   MSVCRT_size_t wrcnt=size * nmemb;
1912   int written = 0;
1913   if (size == 0)
1914       return 0;
1915   if(file->_cnt) {
1916         int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
1917         memcpy(file->_ptr, ptr, pcnt);
1918         file->_cnt -= pcnt;
1919         file->_ptr += pcnt;
1920         written = pcnt;
1921         wrcnt -= pcnt;
1922        ptr = (char*)ptr + pcnt;
1923   } else if(!(file->_flag & MSVCRT__IOWRT)) {
1924         if(file->_flag & MSVCRT__IORW) {
1925                 file->_flag |= MSVCRT__IOWRT;
1926         } else
1927                 return 0;
1928   }
1929   if(wrcnt) {
1930         /* Flush buffer */
1931         int res=msvcrt_flush_buffer(file);
1932         if(!res) {
1933                 int pwritten = _write(file->_file, ptr, wrcnt);
1934                 if (pwritten <= 0) pwritten=0;
1935                 written += pwritten;
1936         }
1937   }
1938   return written / size;
1939 }
1940
1941 /*********************************************************************
1942  *              fputs (MSVCRT.@)
1943  */
1944 int MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
1945 {
1946     size_t len = strlen(s);
1947     return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
1948 }
1949
1950 /*********************************************************************
1951  *              fputws (MSVCRT.@)
1952  */
1953 int MSVCRT_fputws(const WCHAR *s, MSVCRT_FILE* file)
1954 {
1955     size_t len = strlenW(s);
1956     return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
1957 }
1958
1959 /*********************************************************************
1960  *              getchar (MSVCRT.@)
1961  */
1962 int MSVCRT_getchar(void)
1963 {
1964   return MSVCRT_fgetc(MSVCRT_stdin);
1965 }
1966
1967 /*********************************************************************
1968  *              getc (MSVCRT.@)
1969  */
1970 int MSVCRT_getc(MSVCRT_FILE* file)
1971 {
1972   return MSVCRT_fgetc(file);
1973 }
1974
1975 /*********************************************************************
1976  *              gets (MSVCRT.@)
1977  */
1978 char *MSVCRT_gets(char *buf)
1979 {
1980   int    cc;
1981   char * buf_start = buf;
1982
1983   for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
1984       cc = MSVCRT_fgetc(MSVCRT_stdin))
1985   if(cc != '\r') *buf++ = (char)cc;
1986
1987   *buf = '\0';
1988
1989   TRACE("got '%s'\n", buf_start);
1990   return buf_start;
1991 }
1992
1993 /*********************************************************************
1994  *              _getws (MSVCRT.@)
1995  */
1996 WCHAR* MSVCRT__getws(WCHAR* buf)
1997 {
1998     MSVCRT_wint_t cc;
1999     WCHAR* ws = buf;
2000
2001     for (cc = MSVCRT_fgetwc(MSVCRT_stdin); cc != MSVCRT_WEOF && cc != '\n';
2002          cc = MSVCRT_fgetwc(MSVCRT_stdin))
2003     {
2004         if (cc != '\r')
2005             *buf++ = (WCHAR)cc;
2006     }
2007     *buf = '\0';
2008
2009     TRACE("got '%s'\n", debugstr_w(ws));
2010     return ws;
2011 }
2012
2013 /*********************************************************************
2014  *              putc (MSVCRT.@)
2015  */
2016 int MSVCRT_putc(int c, MSVCRT_FILE* file)
2017 {
2018   return MSVCRT_fputc(c, file);
2019 }
2020
2021 /*********************************************************************
2022  *              putchar (MSVCRT.@)
2023  */
2024 int MSVCRT_putchar(int c)
2025 {
2026   return MSVCRT_fputc(c, MSVCRT_stdout);
2027 }
2028
2029 /*********************************************************************
2030  *              puts (MSVCRT.@)
2031  */
2032 int MSVCRT_puts(const char *s)
2033 {
2034     size_t len = strlen(s);
2035     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2036     return MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2037 }
2038
2039 /*********************************************************************
2040  *              _putws (MSVCRT.@)
2041  */
2042 int _putws(const WCHAR *s)
2043 {
2044     static const WCHAR nl = '\n';
2045     size_t len = strlenW(s);
2046     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2047     return MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2048 }
2049
2050 /*********************************************************************
2051  *              remove (MSVCRT.@)
2052  */
2053 int MSVCRT_remove(const char *path)
2054 {
2055   TRACE("(%s)\n",path);
2056   if (DeleteFileA(path))
2057     return 0;
2058   TRACE(":failed (%ld)\n",GetLastError());
2059   MSVCRT__set_errno(GetLastError());
2060   return -1;
2061 }
2062
2063 /*********************************************************************
2064  *              _wremove (MSVCRT.@)
2065  */
2066 int _wremove(const WCHAR *path)
2067 {
2068   TRACE("(%s)\n",debugstr_w(path));
2069   if (DeleteFileW(path))
2070     return 0;
2071   TRACE(":failed (%ld)\n",GetLastError());
2072   MSVCRT__set_errno(GetLastError());
2073   return -1;
2074 }
2075
2076 /*********************************************************************
2077  *              scanf (MSVCRT.@)
2078  */
2079 int MSVCRT_scanf(const char *format, ...)
2080 {
2081   va_list valist;
2082   int res;
2083
2084   va_start(valist, format);
2085   res = MSVCRT_fscanf(MSVCRT_stdin, format, valist);
2086   va_end(valist);
2087   return res;
2088 }
2089
2090 /*********************************************************************
2091  *              wscanf (MSVCRT.@)
2092  */
2093 int MSVCRT_wscanf(const WCHAR *format, ...)
2094 {
2095   va_list valist;
2096   int res;
2097
2098   va_start(valist, format);
2099   res = MSVCRT_fwscanf(MSVCRT_stdin, format, valist);
2100   va_end(valist);
2101   return res;
2102 }
2103
2104 /*********************************************************************
2105  *              rename (MSVCRT.@)
2106  */
2107 int MSVCRT_rename(const char *oldpath,const char *newpath)
2108 {
2109   TRACE(":from %s to %s\n",oldpath,newpath);
2110   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
2111     return 0;
2112   TRACE(":failed (%ld)\n",GetLastError());
2113   MSVCRT__set_errno(GetLastError());
2114   return -1;
2115 }
2116
2117 /*********************************************************************
2118  *              _wrename (MSVCRT.@)
2119  */
2120 int _wrename(const WCHAR *oldpath,const WCHAR *newpath)
2121 {
2122   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
2123   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
2124     return 0;
2125   TRACE(":failed (%ld)\n",GetLastError());
2126   MSVCRT__set_errno(GetLastError());
2127   return -1;
2128 }
2129
2130 /*********************************************************************
2131  *              setvbuf (MSVCRT.@)
2132  */
2133 int MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
2134 {
2135   /* TODO: Check if file busy */
2136   if(file->_bufsiz) {
2137         MSVCRT_free(file->_base);
2138         file->_bufsiz = 0;
2139         file->_cnt = 0;
2140   }
2141   if(mode == MSVCRT__IOFBF) {
2142         file->_flag &= ~MSVCRT__IONBF;
2143         file->_base = file->_ptr = buf;
2144         if(buf) {
2145                 file->_bufsiz = size;
2146         }
2147   } else {
2148         file->_flag |= MSVCRT__IONBF;
2149   }
2150   return 0;
2151 }
2152
2153 /*********************************************************************
2154  *              setbuf (MSVCRT.@)
2155  */
2156 void MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
2157 {
2158   MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ);
2159 }
2160
2161 /*********************************************************************
2162  *              tmpnam (MSVCRT.@)
2163  */
2164 char *MSVCRT_tmpnam(char *s)
2165 {
2166   char tmpbuf[MAX_PATH];
2167   char* prefix = "TMP";
2168   if (!GetTempPathA(MAX_PATH,tmpbuf) ||
2169       !GetTempFileNameA(tmpbuf,prefix,0,MSVCRT_tmpname))
2170   {
2171     TRACE(":failed-last error (%ld)\n",GetLastError());
2172     return NULL;
2173   }
2174   TRACE(":got tmpnam %s\n",MSVCRT_tmpname);
2175   s = MSVCRT_tmpname;
2176   return s;
2177 }
2178
2179 /*********************************************************************
2180  *              tmpfile (MSVCRT.@)
2181  */
2182 MSVCRT_FILE* MSVCRT_tmpfile(void)
2183 {
2184   char *filename = MSVCRT_tmpnam(NULL);
2185   int fd;
2186   fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY);
2187   if (fd != -1)
2188     return msvcrt_alloc_fp(fd);
2189   return NULL;
2190 }
2191
2192 /*********************************************************************
2193  *              vfprintf (MSVCRT.@)
2194  */
2195 int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
2196 {
2197   char buf[2048], *mem = buf;
2198   int written, resize = sizeof(buf), retval;
2199   /* There are two conventions for vsnprintf failing:
2200    * Return -1 if we truncated, or
2201    * Return the number of bytes that would have been written
2202    * The code below handles both cases
2203    */
2204   while ((written = vsnprintf(mem, resize, format, valist)) == -1 ||
2205           written > resize)
2206   {
2207     resize = (written == -1 ? resize * 2 : written + 1);
2208     if (mem != buf)
2209       MSVCRT_free (mem);
2210     if (!(mem = (char *)MSVCRT_malloc(resize)))
2211       return MSVCRT_EOF;
2212   }
2213   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
2214   if (mem != buf)
2215     MSVCRT_free (mem);
2216   return retval;
2217 }
2218
2219 /*********************************************************************
2220  *              vfwprintf (MSVCRT.@)
2221  * FIXME:
2222  * Is final char included in written (then resize is too big) or not
2223  * (then we must test for equality too)?
2224  */
2225 int MSVCRT_vfwprintf(MSVCRT_FILE* file, const WCHAR *format, va_list valist)
2226 {
2227   WCHAR buf[2048], *mem = buf;
2228   int written, resize = sizeof(buf) / sizeof(WCHAR), retval;
2229   /* See vfprintf comments */
2230   while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
2231           written > resize)
2232   {
2233     resize = (written == -1 ? resize * 2 : written + sizeof(WCHAR));
2234     if (mem != buf)
2235       MSVCRT_free (mem);
2236     if (!(mem = (WCHAR *)MSVCRT_malloc(resize*sizeof(*mem))))
2237       return MSVCRT_EOF;
2238   }
2239   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
2240   if (mem != buf)
2241     MSVCRT_free (mem);
2242   return retval;
2243 }
2244
2245 /*********************************************************************
2246  *              vprintf (MSVCRT.@)
2247  */
2248 int MSVCRT_vprintf(const char *format, va_list valist)
2249 {
2250   return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
2251 }
2252
2253 /*********************************************************************
2254  *              vwprintf (MSVCRT.@)
2255  */
2256 int MSVCRT_vwprintf(const WCHAR *format, va_list valist)
2257 {
2258   return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
2259 }
2260
2261 /*********************************************************************
2262  *              fprintf (MSVCRT.@)
2263  */
2264 int MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
2265 {
2266     va_list valist;
2267     int res;
2268     va_start(valist, format);
2269     res = MSVCRT_vfprintf(file, format, valist);
2270     va_end(valist);
2271     return res;
2272 }
2273
2274 /*********************************************************************
2275  *              fwprintf (MSVCRT.@)
2276  */
2277 int MSVCRT_fwprintf(MSVCRT_FILE* file, const WCHAR *format, ...)
2278 {
2279     va_list valist;
2280     int res;
2281     va_start(valist, format);
2282     res = MSVCRT_vfwprintf(file, format, valist);
2283     va_end(valist);
2284     return res;
2285 }
2286
2287 /*********************************************************************
2288  *              printf (MSVCRT.@)
2289  */
2290 int MSVCRT_printf(const char *format, ...)
2291 {
2292     va_list valist;
2293     int res;
2294     va_start(valist, format);
2295     res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
2296     va_end(valist);
2297     return res;
2298 }
2299
2300 /*********************************************************************
2301  *              ungetc (MSVCRT.@)
2302  */
2303 int MSVCRT_ungetc(int c, MSVCRT_FILE * file)
2304 {
2305         if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
2306                 msvcrt_alloc_buffer(file);
2307                 file->_ptr++;
2308         }
2309         if(file->_ptr>file->_base) {
2310                 file->_ptr--;
2311                 *file->_ptr=c;
2312                 file->_cnt++;
2313                 return c;
2314         }
2315         return MSVCRT_EOF;
2316 }
2317
2318 /*********************************************************************
2319  *              ungetwc (MSVCRT.@)
2320  */
2321 MSVCRT_wint_t MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file)
2322 {
2323         WCHAR mwc = wc;
2324         char * pp = (char *)&mwc;
2325         int i;
2326         for(i=sizeof(WCHAR)-1;i>=0;i--) {
2327                 if(pp[i] != MSVCRT_ungetc(pp[i],file))
2328                         return MSVCRT_WEOF;
2329         }
2330         return mwc;
2331 }
2332
2333 /*********************************************************************
2334  *              wprintf (MSVCRT.@)
2335  */
2336 int MSVCRT_wprintf(const WCHAR *format, ...)
2337 {
2338     va_list valist;
2339     int res;
2340     va_start(valist, format);
2341     res = MSVCRT_vwprintf(format, valist);
2342     va_end(valist);
2343     return res;
2344 }