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