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