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