mfplat/sample: Refactor sample_CopyToBuffer().
[wine.git] / dlls / msvcrt / file.c
blob58a607e3bbea6879f39d411dd6b9c98755427f9e
1 /*
2 * msvcrt.dll file functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
8 * Copyright 2004 Eric Pouech
9 * Copyright 2004 Juan Lang
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <direct.h>
28 #include <fcntl.h>
29 #include <io.h>
30 #include <share.h>
31 #include <stdarg.h>
32 #include <sys/locking.h>
33 #include <sys/types.h>
34 #include <sys/utime.h>
35 #include <time.h>
36 #include <limits.h>
38 #include "windef.h"
39 #include "winbase.h"
40 #include "wincon.h"
41 #include "winternl.h"
42 #include "winnls.h"
43 #include "msvcrt.h"
44 #include "mtdll.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
50 #undef _fstat
51 #undef _fstati64
52 #undef _stat
53 #undef _stati64
54 #undef _wstat
55 #undef _wstati64
56 #undef _fstat32
57 #undef _fstat32i64
58 #undef _stat32i64
59 #undef _stat32
60 #undef _wstat32
61 #undef _wstat32i64
62 #undef _fstat64i32
63 #undef _fstat64
64 #undef _stat64
65 #undef _stat64i32
66 #undef _wstat64i32
67 #undef _wstat64
69 /* for stat mode, permissions apply to all,owner and group */
70 #define ALL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
71 #define ALL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
72 #define ALL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
74 /* _access() bit flags FIXME: incomplete */
75 #define MSVCRT_W_OK 0x02
76 #define MSVCRT_R_OK 0x04
78 /* values for wxflag in file descriptor */
79 #define WX_OPEN 0x01
80 #define WX_ATEOF 0x02
81 #define WX_READNL 0x04 /* read started with \n */
82 #define WX_PIPE 0x08
83 #define WX_DONTINHERIT 0x10
84 #define WX_APPEND 0x20
85 #define WX_TTY 0x40
86 #define WX_TEXT 0x80
88 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
89 static char utf16_bom[2] = { 0xff, 0xfe };
91 #define MSVCRT_INTERNAL_BUFSIZ 4096
93 enum textmode
95 TEXTMODE_ANSI,
96 TEXTMODE_UTF8,
97 TEXTMODE_UTF16LE,
100 #if _MSVCR_VER >= 140
102 #define MSVCRT_MAX_FILES 8192
103 #define MSVCRT_FD_BLOCK_SIZE 64
105 typedef struct {
106 CRITICAL_SECTION crit;
107 HANDLE handle;
108 __int64 startpos;
109 unsigned char wxflag;
110 char textmode;
111 char lookahead[3];
112 unsigned int unicode : 1;
113 unsigned int utf8translations : 1;
114 unsigned int dbcsBufferUsed : 1;
115 char dbcsBuffer[MB_LEN_MAX];
116 } ioinfo;
118 /*********************************************************************
119 * __badioinfo (MSVCRT.@)
121 ioinfo MSVCRT___badioinfo = { {0}, INVALID_HANDLE_VALUE, 0, WX_TEXT };
122 #else
124 #define MSVCRT_MAX_FILES 2048
125 #define MSVCRT_FD_BLOCK_SIZE 32
127 typedef struct {
128 HANDLE handle;
129 unsigned char wxflag;
130 char lookahead[3];
131 int exflag;
132 CRITICAL_SECTION crit;
133 #if _MSVCR_VER >= 80
134 char textmode : 7;
135 char unicode : 1;
136 char pipech2[2];
137 __int64 startpos;
138 BOOL utf8translations;
139 char dbcsBuffer[1];
140 BOOL dbcsBufferUsed;
141 #endif
142 } ioinfo;
144 /*********************************************************************
145 * __badioinfo (MSVCRT.@)
147 ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
148 #endif
150 /*********************************************************************
151 * __pioinfo (MSVCRT.@)
152 * array of pointers to ioinfo arrays [32]
154 ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
156 #if _MSVCR_VER >= 80
158 #if _MSVCR_VER >= 140
159 static inline BOOL ioinfo_is_crit_init(ioinfo *info)
161 return TRUE;
164 static inline void ioinfo_set_crit_init(ioinfo *info)
167 #else
168 static inline BOOL ioinfo_is_crit_init(ioinfo *info)
170 return info->exflag & 1;
173 static inline void ioinfo_set_crit_init(ioinfo *info)
175 info->exflag |= 1;
177 #endif
179 static inline enum textmode ioinfo_get_textmode(ioinfo *info)
181 return info->textmode;
184 static inline void ioinfo_set_textmode(ioinfo *info, enum textmode mode)
186 info->textmode = mode;
189 static inline void ioinfo_set_unicode(ioinfo *info, BOOL unicode)
191 info->unicode = !!unicode;
193 #else
195 #define EF_UTF8 0x01
196 #define EF_UTF16 0x02
197 #define EF_CRIT_INIT 0x04
198 #define EF_UNK_UNICODE 0x08
200 static inline BOOL ioinfo_is_crit_init(ioinfo *info)
202 return info->exflag & EF_CRIT_INIT;
205 static inline void ioinfo_set_crit_init(ioinfo *info)
207 info->exflag |= EF_CRIT_INIT;
210 static inline enum textmode ioinfo_get_textmode(ioinfo *info)
212 if (info->exflag & EF_UTF8)
213 return TEXTMODE_UTF8;
214 if (info->exflag & EF_UTF16)
215 return TEXTMODE_UTF16LE;
216 return TEXTMODE_ANSI;
219 static inline void ioinfo_set_textmode(ioinfo *info, enum textmode mode)
221 info->exflag &= EF_CRIT_INIT | EF_UNK_UNICODE;
222 switch (mode)
224 case TEXTMODE_ANSI:
225 break;
226 case TEXTMODE_UTF8:
227 info->exflag |= EF_UTF8;
228 break;
229 case TEXTMODE_UTF16LE:
230 info->exflag |= EF_UTF16;
231 break;
235 static inline void ioinfo_set_unicode(ioinfo *info, BOOL unicode)
237 if (unicode)
238 info->exflag |= EF_UNK_UNICODE;
239 else
240 info->exflag &= ~EF_UNK_UNICODE;
242 #endif
244 typedef struct {
245 FILE file;
246 CRITICAL_SECTION crit;
247 } file_crit;
249 FILE MSVCRT__iob[_IOB_ENTRIES] = { { 0 } };
250 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE];
251 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
253 /* INTERNAL: process umask */
254 static int MSVCRT_umask = 0;
256 /* INTERNAL: static data for tmpnam and _wtmpname functions */
257 static LONG tmpnam_unique;
258 static LONG tmpnam_s_unique;
260 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
261 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
262 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
263 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
265 #define TOUL(x) (ULONGLONG)(x)
266 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
267 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
268 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
269 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
271 /* This critical section protects the MSVCRT_fstreams table
272 * and MSVCRT_stream_idx from race conditions. It also
273 * protects fd critical sections creation code.
275 static CRITICAL_SECTION MSVCRT_file_cs;
276 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
278 0, 0, &MSVCRT_file_cs,
279 { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
280 0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
282 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
283 #define LOCK_FILES() do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
284 #define UNLOCK_FILES() do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
286 static void msvcrt_stat64_to_stat(const struct _stat64 *buf64, struct _stat *buf)
288 buf->st_dev = buf64->st_dev;
289 buf->st_ino = buf64->st_ino;
290 buf->st_mode = buf64->st_mode;
291 buf->st_nlink = buf64->st_nlink;
292 buf->st_uid = buf64->st_uid;
293 buf->st_gid = buf64->st_gid;
294 buf->st_rdev = buf64->st_rdev;
295 buf->st_size = buf64->st_size;
296 buf->st_atime = buf64->st_atime;
297 buf->st_mtime = buf64->st_mtime;
298 buf->st_ctime = buf64->st_ctime;
301 static void msvcrt_stat64_to_stati64(const struct _stat64 *buf64, struct _stati64 *buf)
303 buf->st_dev = buf64->st_dev;
304 buf->st_ino = buf64->st_ino;
305 buf->st_mode = buf64->st_mode;
306 buf->st_nlink = buf64->st_nlink;
307 buf->st_uid = buf64->st_uid;
308 buf->st_gid = buf64->st_gid;
309 buf->st_rdev = buf64->st_rdev;
310 buf->st_size = buf64->st_size;
311 buf->st_atime = buf64->st_atime;
312 buf->st_mtime = buf64->st_mtime;
313 buf->st_ctime = buf64->st_ctime;
316 static void msvcrt_stat64_to_stat32(const struct _stat64 *buf64, struct _stat32 *buf)
318 buf->st_dev = buf64->st_dev;
319 buf->st_ino = buf64->st_ino;
320 buf->st_mode = buf64->st_mode;
321 buf->st_nlink = buf64->st_nlink;
322 buf->st_uid = buf64->st_uid;
323 buf->st_gid = buf64->st_gid;
324 buf->st_rdev = buf64->st_rdev;
325 buf->st_size = buf64->st_size;
326 buf->st_atime = buf64->st_atime;
327 buf->st_mtime = buf64->st_mtime;
328 buf->st_ctime = buf64->st_ctime;
331 static void msvcrt_stat64_to_stat64i32(const struct _stat64 *buf64, struct _stat64i32 *buf)
333 buf->st_dev = buf64->st_dev;
334 buf->st_ino = buf64->st_ino;
335 buf->st_mode = buf64->st_mode;
336 buf->st_nlink = buf64->st_nlink;
337 buf->st_uid = buf64->st_uid;
338 buf->st_gid = buf64->st_gid;
339 buf->st_rdev = buf64->st_rdev;
340 buf->st_size = buf64->st_size;
341 buf->st_atime = buf64->st_atime;
342 buf->st_mtime = buf64->st_mtime;
343 buf->st_ctime = buf64->st_ctime;
346 static void msvcrt_stat64_to_stat32i64(const struct _stat64 *buf64, struct _stat32i64 *buf)
348 buf->st_dev = buf64->st_dev;
349 buf->st_ino = buf64->st_ino;
350 buf->st_mode = buf64->st_mode;
351 buf->st_nlink = buf64->st_nlink;
352 buf->st_uid = buf64->st_uid;
353 buf->st_gid = buf64->st_gid;
354 buf->st_rdev = buf64->st_rdev;
355 buf->st_size = buf64->st_size;
356 buf->st_atime = buf64->st_atime;
357 buf->st_mtime = buf64->st_mtime;
358 buf->st_ctime = buf64->st_ctime;
361 static void time_to_filetime( __time64_t time, FILETIME *ft )
363 /* 1601 to 1970 is 369 years plus 89 leap days */
364 static const __int64 secs_1601_to_1970 = ((369 * 365 + 89) * (__int64)86400);
366 __int64 ticks = (time + secs_1601_to_1970) * 10000000;
367 ft->dwHighDateTime = ticks >> 32;
368 ft->dwLowDateTime = ticks;
371 static inline ioinfo* get_ioinfo_nolock(int fd)
373 ioinfo *ret = NULL;
374 if(fd>=0 && fd<MSVCRT_MAX_FILES)
375 ret = MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
376 if(!ret)
377 return &MSVCRT___badioinfo;
379 return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
382 static inline void init_ioinfo_cs(ioinfo *info)
384 if(!ioinfo_is_crit_init(info)) {
385 LOCK_FILES();
386 if(!ioinfo_is_crit_init(info)) {
387 InitializeCriticalSection(&info->crit);
388 ioinfo_set_crit_init(info);
390 UNLOCK_FILES();
394 static inline ioinfo* get_ioinfo(int fd)
396 ioinfo *ret = get_ioinfo_nolock(fd);
397 if(ret == &MSVCRT___badioinfo)
398 return ret;
399 init_ioinfo_cs(ret);
400 EnterCriticalSection(&ret->crit);
401 return ret;
404 static inline BOOL alloc_pioinfo_block(int fd)
406 ioinfo *block;
407 int i;
409 if(fd<0 || fd>=MSVCRT_MAX_FILES)
411 *_errno() = ENFILE;
412 return FALSE;
415 block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
416 if(!block)
418 WARN(":out of memory!\n");
419 *_errno() = ENOMEM;
420 return FALSE;
422 for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
424 block[i].handle = INVALID_HANDLE_VALUE;
425 if (ioinfo_is_crit_init(&block[i]))
427 /* Initialize crit section on block allocation for _MSVC_VER >= 140,
428 * ioinfo_is_crit_init() is always TRUE. */
429 InitializeCriticalSection(&block[i].crit);
432 if(InterlockedCompareExchangePointer((void**)&MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL))
434 if (ioinfo_is_crit_init(&block[0]))
436 for(i = 0; i < MSVCRT_FD_BLOCK_SIZE; ++i)
437 DeleteCriticalSection(&block[i].crit);
439 free(block);
441 return TRUE;
444 static inline ioinfo* get_ioinfo_alloc_fd(int fd)
446 ioinfo *ret;
448 ret = get_ioinfo(fd);
449 if(ret != &MSVCRT___badioinfo)
450 return ret;
452 if(!alloc_pioinfo_block(fd))
453 return &MSVCRT___badioinfo;
455 return get_ioinfo(fd);
458 static inline ioinfo* get_ioinfo_alloc(int *fd)
460 int i;
462 *fd = -1;
463 for(i=0; i<MSVCRT_MAX_FILES; i++)
465 ioinfo *info = get_ioinfo_nolock(i);
467 if(info == &MSVCRT___badioinfo)
469 if(!alloc_pioinfo_block(i))
470 return &MSVCRT___badioinfo;
471 info = get_ioinfo_nolock(i);
474 init_ioinfo_cs(info);
475 if(TryEnterCriticalSection(&info->crit))
477 if(info->handle == INVALID_HANDLE_VALUE)
479 *fd = i;
480 return info;
482 LeaveCriticalSection(&info->crit);
486 WARN(":files exhausted!\n");
487 *_errno() = ENFILE;
488 return &MSVCRT___badioinfo;
491 static inline void release_ioinfo(ioinfo *info)
493 if(info!=&MSVCRT___badioinfo && ioinfo_is_crit_init(info))
494 LeaveCriticalSection(&info->crit);
497 static inline FILE* msvcrt_get_file(int i)
499 file_crit *ret;
501 if(i >= MSVCRT_max_streams)
502 return NULL;
504 if(i < _IOB_ENTRIES)
505 return &MSVCRT__iob[i];
507 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
508 if(!ret) {
509 MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
510 if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
511 ERR("out of memory\n");
512 *_errno() = ENOMEM;
513 return NULL;
516 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
517 } else
518 ret += i%MSVCRT_FD_BLOCK_SIZE;
520 return &ret->file;
523 /* INTERNAL: free a file entry fd */
524 static void msvcrt_free_fd(int fd)
526 ioinfo *fdinfo = get_ioinfo(fd);
528 if(fdinfo != &MSVCRT___badioinfo)
530 fdinfo->handle = INVALID_HANDLE_VALUE;
531 fdinfo->wxflag = 0;
533 TRACE(":fd (%d) freed\n",fd);
535 if (fd < 3)
537 switch (fd)
539 case 0:
540 SetStdHandle(STD_INPUT_HANDLE, 0);
541 break;
542 case 1:
543 SetStdHandle(STD_OUTPUT_HANDLE, 0);
544 break;
545 case 2:
546 SetStdHandle(STD_ERROR_HANDLE, 0);
547 break;
550 release_ioinfo(fdinfo);
553 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag)
555 fdinfo->handle = hand;
556 fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY));
557 fdinfo->lookahead[0] = '\n';
558 fdinfo->lookahead[1] = '\n';
559 fdinfo->lookahead[2] = '\n';
560 ioinfo_set_unicode(fdinfo, FALSE);
561 ioinfo_set_textmode(fdinfo, TEXTMODE_ANSI);
563 if (hand == MSVCRT_NO_CONSOLE) hand = 0;
564 switch (fdinfo-MSVCRT___pioinfo[0])
566 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
567 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
568 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
572 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
573 static int msvcrt_alloc_fd(HANDLE hand, int flag)
575 int fd;
576 ioinfo *info = get_ioinfo_alloc(&fd);
578 TRACE(":handle (%p) allocating fd (%d)\n", hand, fd);
580 if(info == &MSVCRT___badioinfo)
581 return -1;
583 msvcrt_set_fd(info, hand, flag);
584 release_ioinfo(info);
585 return fd;
588 /* INTERNAL: Allocate a FILE* for an fd slot */
589 /* caller must hold the files lock */
590 static FILE* msvcrt_alloc_fp(void)
592 int i;
593 FILE *file;
595 for (i = 3; i < MSVCRT_max_streams; i++)
597 file = msvcrt_get_file(i);
598 if (!file)
599 return NULL;
601 if (file->_flag == 0)
603 if (i == MSVCRT_stream_idx)
605 if (file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
607 InitializeCriticalSection(&((file_crit*)file)->crit);
608 ((file_crit*)file)->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_crit.crit");
610 MSVCRT_stream_idx++;
612 return file;
616 return NULL;
619 /* INTERNAL: initialize a FILE* from an open fd */
620 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags)
622 TRACE(":fd (%d) allocating FILE*\n",fd);
623 if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN))
625 WARN(":invalid fd %d\n",fd);
626 *__doserrno() = 0;
627 *_errno() = EBADF;
628 return -1;
630 file->_ptr = file->_base = NULL;
631 file->_cnt = 0;
632 file->_file = fd;
633 file->_flag = stream_flags;
634 file->_tmpfname = NULL;
636 TRACE(":got FILE* (%p)\n",file);
637 return 0;
640 /* INTERNAL: Create an inheritance data block (for spawned process)
641 * The inheritance block is made of:
642 * 00 int nb of file descriptor (NBFD)
643 * 04 char file flags (wxflag): repeated for each fd
644 * 4+NBFD HANDLE file handle: repeated for each fd
646 BOOL msvcrt_create_io_inherit_block(WORD *size, BYTE **block)
648 int fd, last_fd;
649 char* wxflag_ptr;
650 HANDLE* handle_ptr;
651 ioinfo* fdinfo;
653 for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--)
654 if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE)
655 break;
656 last_fd++;
658 *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd;
659 *block = calloc(1, *size);
660 if (!*block)
662 *size = 0;
663 return FALSE;
665 wxflag_ptr = (char*)*block + sizeof(unsigned);
666 handle_ptr = (HANDLE*)(wxflag_ptr + last_fd);
668 *(unsigned*)*block = last_fd;
669 for (fd = 0; fd < last_fd; fd++)
671 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
672 fdinfo = get_ioinfo_nolock(fd);
673 if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
675 *wxflag_ptr = fdinfo->wxflag;
676 *handle_ptr = fdinfo->handle;
678 else
680 *wxflag_ptr = 0;
681 *handle_ptr = INVALID_HANDLE_VALUE;
683 wxflag_ptr++; handle_ptr++;
685 return TRUE;
688 /* INTERNAL: Set up all file descriptors,
689 * as well as default streams (stdin, stderr and stdout)
691 void msvcrt_init_io(void)
693 STARTUPINFOA si;
694 int i;
695 ioinfo *fdinfo;
697 GetStartupInfoA(&si);
698 if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
700 BYTE* wxflag_ptr;
701 HANDLE* handle_ptr;
702 unsigned int count;
704 count = *(unsigned*)si.lpReserved2;
705 wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
706 handle_ptr = (HANDLE*)(wxflag_ptr + count);
708 count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
709 count = min(count, MSVCRT_MAX_FILES);
710 for (i = 0; i < count; i++)
712 if ((*wxflag_ptr & WX_OPEN) && GetFileType(*handle_ptr) != FILE_TYPE_UNKNOWN)
714 fdinfo = get_ioinfo_alloc_fd(i);
715 if(fdinfo != &MSVCRT___badioinfo)
716 msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr);
717 release_ioinfo(fdinfo);
720 wxflag_ptr++; handle_ptr++;
724 fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO);
725 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
726 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
727 DWORD flags = WX_OPEN | WX_TEXT;
728 DWORD type = GetFileType(h);
730 if (type == FILE_TYPE_UNKNOWN) {
731 h = MSVCRT_NO_CONSOLE;
732 flags |= WX_TTY;
733 } else if ((type & 0xf) == FILE_TYPE_CHAR) {
734 flags |= WX_TTY;
735 } else if ((type & 0xf) == FILE_TYPE_PIPE) {
736 flags |= WX_PIPE;
739 msvcrt_set_fd(fdinfo, h, flags);
741 release_ioinfo(fdinfo);
743 fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO);
744 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
745 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
746 DWORD flags = WX_OPEN | WX_TEXT;
747 DWORD type = GetFileType(h);
749 if (type == FILE_TYPE_UNKNOWN) {
750 h = MSVCRT_NO_CONSOLE;
751 flags |= WX_TTY;
752 } else if ((type & 0xf) == FILE_TYPE_CHAR) {
753 flags |= WX_TTY;
754 } else if ((type & 0xf) == FILE_TYPE_PIPE) {
755 flags |= WX_PIPE;
758 msvcrt_set_fd(fdinfo, h, flags);
760 release_ioinfo(fdinfo);
762 fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO);
763 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
764 HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
765 DWORD flags = WX_OPEN | WX_TEXT;
766 DWORD type = GetFileType(h);
768 if (type == FILE_TYPE_UNKNOWN) {
769 h = MSVCRT_NO_CONSOLE;
770 flags |= WX_TTY;
771 } else if ((type & 0xf) == FILE_TYPE_CHAR) {
772 flags |= WX_TTY;
773 } else if ((type & 0xf) == FILE_TYPE_PIPE) {
774 flags |= WX_PIPE;
777 msvcrt_set_fd(fdinfo, h, flags);
779 release_ioinfo(fdinfo);
781 TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle,
782 get_ioinfo_nolock(STDOUT_FILENO)->handle,
783 get_ioinfo_nolock(STDERR_FILENO)->handle);
785 memset(MSVCRT__iob,0,3*sizeof(FILE));
786 for (i = 0; i < 3; i++)
788 /* FILE structs for stdin/out/err are static and never deleted */
789 MSVCRT__iob[i]._file = get_ioinfo_nolock(i)->handle == MSVCRT_NO_CONSOLE ?
790 MSVCRT_NO_CONSOLE_FD : i;
791 MSVCRT__iob[i]._tmpfname = NULL;
792 MSVCRT__iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
794 MSVCRT_stream_idx = 3;
797 /* INTERNAL: Flush stdio file buffer */
798 static int msvcrt_flush_buffer(FILE* file)
800 int ret = 0;
802 if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT &&
803 file->_flag & (_IOMYBUF|MSVCRT__USERBUF)) {
804 int cnt=file->_ptr-file->_base;
805 if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
806 file->_flag |= _IOERR;
807 ret = EOF;
808 } else if(file->_flag & _IORW) {
809 file->_flag &= ~_IOWRT;
813 file->_ptr=file->_base;
814 file->_cnt=0;
815 return ret;
818 /*********************************************************************
819 * _isatty (MSVCRT.@)
821 int CDECL _isatty(int fd)
823 TRACE(":fd (%d)\n",fd);
825 return get_ioinfo_nolock(fd)->wxflag & WX_TTY;
828 /* INTERNAL: Allocate stdio file buffer */
829 static BOOL msvcrt_alloc_buffer(FILE* file)
831 if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
832 && _isatty(file->_file))
833 return FALSE;
835 file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ);
836 if(file->_base) {
837 file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
838 file->_flag |= _IOMYBUF;
839 } else {
840 file->_base = (char*)(&file->_charbuf);
841 file->_bufsiz = 2;
842 file->_flag |= _IONBF;
844 file->_ptr = file->_base;
845 file->_cnt = 0;
846 return TRUE;
849 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
850 static BOOL add_std_buffer(FILE *file)
852 static char buffers[2][BUFSIZ];
854 if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
855 || (file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF))
856 || !_isatty(file->_file))
857 return FALSE;
859 file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
860 file->_bufsiz = file->_cnt = BUFSIZ;
861 file->_flag |= MSVCRT__USERBUF;
862 return TRUE;
865 /* INTERNAL: Removes temporary buffer from stdout or stderr */
866 /* Only call this function when add_std_buffer returned TRUE */
867 static void remove_std_buffer(FILE *file)
869 msvcrt_flush_buffer(file);
870 file->_ptr = file->_base = NULL;
871 file->_bufsiz = file->_cnt = 0;
872 file->_flag &= ~MSVCRT__USERBUF;
875 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
876 static int msvcrt_int_to_base32(int num, char *str)
878 char *p;
879 int n = num;
880 int digits = 0;
882 while (n != 0)
884 n >>= 5;
885 digits++;
887 p = str + digits;
888 *p = 0;
889 while (--p >= str)
891 *p = (num & 31) + '0';
892 if (*p > '9')
893 *p += ('a' - '0' - 10);
894 num >>= 5;
897 return digits;
900 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
901 static int msvcrt_int_to_base32_w(int num, wchar_t *str)
903 wchar_t *p;
904 int n = num;
905 int digits = 0;
907 while (n != 0)
909 n >>= 5;
910 digits++;
912 p = str + digits;
913 *p = 0;
914 while (--p >= str)
916 *p = (num & 31) + '0';
917 if (*p > '9')
918 *p += ('a' - '0' - 10);
919 num >>= 5;
922 return digits;
925 /*********************************************************************
926 * __iob_func (MSVCRT.@)
928 #undef __iob_func
929 FILE * CDECL __iob_func(void)
931 return &MSVCRT__iob[0];
934 #if _MSVCR_VER >= 140
935 /*********************************************************************
936 * __acrt_iob_func(UCRTBASE.@)
938 FILE * CDECL __acrt_iob_func(unsigned idx)
940 return &MSVCRT__iob[idx];
942 #endif
944 /*********************************************************************
945 * _access (MSVCRT.@)
947 int CDECL _access(const char *filename, int mode)
949 DWORD attr = GetFileAttributesA(filename);
951 TRACE("(%s,%d) %ld\n", filename, mode, attr);
953 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
955 msvcrt_set_errno(GetLastError());
956 return -1;
958 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
960 msvcrt_set_errno(ERROR_ACCESS_DENIED);
961 return -1;
963 return 0;
966 /*********************************************************************
967 * _access_s (MSVCRT.@)
969 int CDECL _access_s(const char *filename, int mode)
971 if (!MSVCRT_CHECK_PMT(filename != NULL)) return *_errno();
972 if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return *_errno();
974 if (_access(filename, mode) == -1)
975 return *_errno();
976 return 0;
979 /*********************************************************************
980 * _waccess (MSVCRT.@)
982 int CDECL _waccess(const wchar_t *filename, int mode)
984 DWORD attr = GetFileAttributesW(filename);
986 TRACE("(%s,%d) %ld\n", debugstr_w(filename), mode, attr);
988 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
990 msvcrt_set_errno(GetLastError());
991 return -1;
993 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
995 msvcrt_set_errno(ERROR_ACCESS_DENIED);
996 return -1;
998 return 0;
1001 /*********************************************************************
1002 * _waccess_s (MSVCRT.@)
1004 int CDECL _waccess_s(const wchar_t *filename, int mode)
1006 if (!MSVCRT_CHECK_PMT(filename != NULL)) return *_errno();
1007 if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return *_errno();
1009 if (_waccess(filename, mode) == -1)
1010 return *_errno();
1011 return 0;
1014 /*********************************************************************
1015 * _chmod (MSVCRT.@)
1017 int CDECL _chmod(const char *path, int flags)
1019 DWORD oldFlags = GetFileAttributesA(path);
1021 if (oldFlags != INVALID_FILE_ATTRIBUTES)
1023 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
1024 oldFlags | FILE_ATTRIBUTE_READONLY;
1026 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
1027 return 0;
1029 msvcrt_set_errno(GetLastError());
1030 return -1;
1033 /*********************************************************************
1034 * _wchmod (MSVCRT.@)
1036 int CDECL _wchmod(const wchar_t *path, int flags)
1038 DWORD oldFlags = GetFileAttributesW(path);
1040 if (oldFlags != INVALID_FILE_ATTRIBUTES)
1042 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
1043 oldFlags | FILE_ATTRIBUTE_READONLY;
1045 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
1046 return 0;
1048 msvcrt_set_errno(GetLastError());
1049 return -1;
1052 /*********************************************************************
1053 * _unlink (MSVCRT.@)
1055 int CDECL _unlink(const char *path)
1057 TRACE("%s\n", debugstr_a(path));
1058 if(DeleteFileA(path))
1059 return 0;
1060 TRACE("failed (%ld)\n", GetLastError());
1061 msvcrt_set_errno(GetLastError());
1062 return -1;
1065 /*********************************************************************
1066 * _wunlink (MSVCRT.@)
1068 int CDECL _wunlink(const wchar_t *path)
1070 TRACE("(%s)\n", debugstr_w(path));
1071 if(DeleteFileW(path))
1072 return 0;
1073 TRACE("failed (%ld)\n", GetLastError());
1074 msvcrt_set_errno(GetLastError());
1075 return -1;
1078 /*********************************************************************
1079 * _commit (MSVCRT.@)
1081 int CDECL _commit(int fd)
1083 ioinfo *info = get_ioinfo(fd);
1084 int ret;
1086 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1088 if (info->handle == INVALID_HANDLE_VALUE)
1089 ret = -1;
1090 else if (!FlushFileBuffers(info->handle))
1092 if (GetLastError() == ERROR_INVALID_HANDLE)
1094 /* FlushFileBuffers fails for console handles
1095 * so we ignore this error.
1097 ret = 0;
1099 else
1101 TRACE(":failed-last error (%ld)\n", GetLastError());
1102 msvcrt_set_errno(GetLastError());
1103 ret = -1;
1106 else
1108 TRACE(":ok\n");
1109 ret = 0;
1112 release_ioinfo(info);
1113 return ret;
1116 /* INTERNAL: Flush all stream buffer */
1117 static int msvcrt_flush_all_buffers(int mask)
1119 int i, num_flushed = 0;
1120 FILE *file;
1122 LOCK_FILES();
1123 for (i = 0; i < MSVCRT_stream_idx; i++) {
1124 file = msvcrt_get_file(i);
1126 if (file->_flag)
1128 if(file->_flag & mask) {
1129 fflush(file);
1130 num_flushed++;
1134 UNLOCK_FILES();
1136 TRACE(":flushed (%d) handles\n",num_flushed);
1137 return num_flushed;
1140 /*********************************************************************
1141 * _flushall (MSVCRT.@)
1143 int CDECL _flushall(void)
1145 return msvcrt_flush_all_buffers(_IOWRT | _IOREAD);
1148 /*********************************************************************
1149 * fflush (MSVCRT.@)
1151 int CDECL fflush(FILE* file)
1153 int ret;
1155 if(!file) {
1156 msvcrt_flush_all_buffers(_IOWRT);
1157 ret = 0;
1158 } else {
1159 _lock_file(file);
1160 ret = _fflush_nolock(file);
1161 _unlock_file(file);
1164 return ret;
1167 /*********************************************************************
1168 * _fflush_nolock (MSVCRT.@)
1170 int CDECL _fflush_nolock(FILE* file)
1172 int res;
1174 if(!file) {
1175 msvcrt_flush_all_buffers(_IOWRT);
1176 return 0;
1179 res = msvcrt_flush_buffer(file);
1180 if(!res && (file->_flag & MSVCRT__IOCOMMIT))
1181 res = _commit(file->_file) ? EOF : 0;
1182 return res;
1185 /*********************************************************************
1186 * _close (MSVCRT.@)
1188 int CDECL _close(int fd)
1190 ioinfo *info = get_ioinfo(fd);
1191 int ret;
1193 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1195 if (fd == MSVCRT_NO_CONSOLE_FD) {
1196 *_errno() = EBADF;
1197 ret = -1;
1198 } else if (!MSVCRT_CHECK_PMT_ERR(info->wxflag & WX_OPEN, EBADF)) {
1199 ret = -1;
1200 } else if (fd == STDOUT_FILENO &&
1201 info->handle == get_ioinfo_nolock(STDERR_FILENO)->handle) {
1202 msvcrt_free_fd(fd);
1203 ret = 0;
1204 } else if (fd == STDERR_FILENO &&
1205 info->handle == get_ioinfo_nolock(STDOUT_FILENO)->handle) {
1206 msvcrt_free_fd(fd);
1207 ret = 0;
1208 } else {
1209 ret = CloseHandle(info->handle) ? 0 : -1;
1210 msvcrt_free_fd(fd);
1211 if (ret) {
1212 WARN(":failed-last error (%ld)\n", GetLastError());
1213 msvcrt_set_errno(GetLastError());
1216 release_ioinfo(info);
1217 return ret;
1220 /*********************************************************************
1221 * _dup2 (MSVCRT.@)
1222 * NOTES
1223 * MSDN isn't clear on this point, but the remarks for _pipe
1224 * indicate file descriptors duplicated with _dup and _dup2 are always
1225 * inheritable.
1227 int CDECL _dup2(int od, int nd)
1229 ioinfo *info_od, *info_nd;
1230 int ret;
1232 TRACE("(od=%d, nd=%d)\n", od, nd);
1234 if (od < nd)
1236 info_od = get_ioinfo(od);
1237 info_nd = get_ioinfo_alloc_fd(nd);
1239 else
1241 info_nd = get_ioinfo_alloc_fd(nd);
1242 info_od = get_ioinfo(od);
1245 if (info_nd == &MSVCRT___badioinfo)
1247 *_errno() = EBADF;
1248 ret = -1;
1250 else if (info_od->wxflag & WX_OPEN)
1252 HANDLE handle;
1254 if (DuplicateHandle(GetCurrentProcess(), info_od->handle,
1255 GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
1257 int wxflag = info_od->wxflag & ~WX_DONTINHERIT;
1259 if (info_nd->wxflag & WX_OPEN)
1260 _close(nd);
1262 msvcrt_set_fd(info_nd, handle, wxflag);
1263 /* _dup2 returns 0, not nd, on success */
1264 ret = 0;
1266 else
1268 ret = -1;
1269 msvcrt_set_errno(GetLastError());
1272 else
1274 *_errno() = EBADF;
1275 ret = -1;
1278 release_ioinfo(info_od);
1279 release_ioinfo(info_nd);
1280 return ret;
1283 /*********************************************************************
1284 * _dup (MSVCRT.@)
1286 int CDECL _dup(int od)
1288 int fd, ret;
1289 ioinfo *info = get_ioinfo_alloc(&fd);
1291 if (_dup2(od, fd) == 0)
1292 ret = fd;
1293 else
1294 ret = -1;
1295 release_ioinfo(info);
1296 return ret;
1299 /*********************************************************************
1300 * _eof (MSVCRT.@)
1302 int CDECL _eof(int fd)
1304 ioinfo *info = get_ioinfo(fd);
1305 DWORD curpos,endpos;
1306 LONG hcurpos,hendpos;
1308 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1310 if (info->handle == INVALID_HANDLE_VALUE)
1312 release_ioinfo(info);
1313 return -1;
1316 if (info->wxflag & WX_ATEOF)
1318 release_ioinfo(info);
1319 return TRUE;
1322 /* Otherwise we do it the hard way */
1323 hcurpos = hendpos = 0;
1324 curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT);
1325 endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END);
1327 if (curpos == endpos && hcurpos == hendpos)
1329 /* FIXME: shouldn't WX_ATEOF be set here? */
1330 release_ioinfo(info);
1331 return TRUE;
1334 SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN);
1335 release_ioinfo(info);
1336 return FALSE;
1339 /*********************************************************************
1340 * _fcloseall (MSVCRT.@)
1342 int CDECL _fcloseall(void)
1344 int num_closed = 0, i;
1345 FILE *file;
1347 LOCK_FILES();
1348 for (i = 3; i < MSVCRT_stream_idx; i++) {
1349 file = msvcrt_get_file(i);
1351 if (file->_flag && !fclose(file))
1352 num_closed++;
1354 UNLOCK_FILES();
1356 TRACE(":closed (%d) handles\n",num_closed);
1357 return num_closed;
1360 /* free everything on process exit */
1361 void msvcrt_free_io(void)
1363 unsigned int i;
1364 int j;
1366 _flushall();
1367 _fcloseall();
1369 for(i=0; i<ARRAY_SIZE(MSVCRT___pioinfo); i++)
1371 if(!MSVCRT___pioinfo[i])
1372 continue;
1374 for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++)
1376 if(ioinfo_is_crit_init(&MSVCRT___pioinfo[i][j]))
1377 DeleteCriticalSection(&MSVCRT___pioinfo[i][j].crit);
1379 free(MSVCRT___pioinfo[i]);
1382 for(j=0; j<MSVCRT_stream_idx; j++)
1384 FILE *file = msvcrt_get_file(j);
1385 if(file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
1387 ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1388 DeleteCriticalSection(&((file_crit*)file)->crit);
1392 for(i=0; i<ARRAY_SIZE(MSVCRT_fstream); i++)
1393 free(MSVCRT_fstream[i]);
1396 /*********************************************************************
1397 * _lseeki64 (MSVCRT.@)
1399 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1401 ioinfo *info = get_ioinfo(fd);
1402 LARGE_INTEGER ofs;
1404 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1406 if (info->handle == INVALID_HANDLE_VALUE)
1408 *_errno() = EBADF;
1409 release_ioinfo(info);
1410 return -1;
1413 if (whence < 0 || whence > 2)
1415 release_ioinfo(info);
1416 *_errno() = EINVAL;
1417 return -1;
1420 TRACE(":fd (%d) to %#I64x pos %s\n",
1421 fd, offset, (whence == SEEK_SET) ? "SEEK_SET" :
1422 (whence == SEEK_CUR) ? "SEEK_CUR" :
1423 (whence == SEEK_END) ? "SEEK_END" : "UNKNOWN");
1425 /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1426 * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1427 ofs.QuadPart = offset;
1428 if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1429 GetLastError() == ERROR_SUCCESS)
1431 info->wxflag &= ~WX_ATEOF;
1432 /* FIXME: What if we seek _to_ EOF - is EOF set? */
1434 release_ioinfo(info);
1435 return ofs.QuadPart;
1437 release_ioinfo(info);
1438 TRACE(":error-last error (%ld)\n", GetLastError());
1439 msvcrt_set_errno(GetLastError());
1440 return -1;
1443 /*********************************************************************
1444 * _lseek (MSVCRT.@)
1446 __msvcrt_long CDECL _lseek(int fd, __msvcrt_long offset, int whence)
1448 return _lseeki64(fd, offset, whence);
1451 /*********************************************************************
1452 * _lock_file (MSVCRT.@)
1454 void CDECL _lock_file(FILE *file)
1456 if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1457 _lock(_STREAM_LOCKS+(file-MSVCRT__iob));
1458 else
1459 EnterCriticalSection(&((file_crit*)file)->crit);
1462 /*********************************************************************
1463 * _unlock_file (MSVCRT.@)
1465 void CDECL _unlock_file(FILE *file)
1467 if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1468 _unlock(_STREAM_LOCKS+(file-MSVCRT__iob));
1469 else
1470 LeaveCriticalSection(&((file_crit*)file)->crit);
1473 /*********************************************************************
1474 * _locking (MSVCRT.@)
1476 * This is untested; the underlying LockFile doesn't work yet.
1478 int CDECL _locking(int fd, int mode, __msvcrt_long nbytes)
1480 ioinfo *info = get_ioinfo(fd);
1481 BOOL ret;
1482 DWORD cur_locn;
1484 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1485 if (info->handle == INVALID_HANDLE_VALUE)
1487 release_ioinfo(info);
1488 return -1;
1491 if (mode < 0 || mode > 4)
1493 release_ioinfo(info);
1494 *_errno() = EINVAL;
1495 return -1;
1498 TRACE(":fd (%d) by %#lx mode %s\n",
1499 fd, nbytes, (mode == _LK_UNLCK) ? "_LK_UNLCK" :
1500 (mode == _LK_LOCK) ? "_LK_LOCK" :
1501 (mode == _LK_NBLCK) ? "_LK_NBLCK" :
1502 (mode == _LK_RLCK) ? "_LK_RLCK" :
1503 (mode == _LK_NBRLCK) ? "_LK_NBRLCK" :
1504 "UNKNOWN");
1506 if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, FILE_CURRENT)) == INVALID_SET_FILE_POINTER)
1508 release_ioinfo(info);
1509 FIXME("Seek failed\n");
1510 *_errno() = EINVAL; /* FIXME */
1511 return -1;
1513 if (mode == _LK_LOCK || mode == _LK_RLCK)
1515 int nretry = 10;
1516 ret = 1; /* just to satisfy gcc */
1517 while (nretry--)
1519 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1520 if (ret) break;
1521 Sleep(1);
1524 else if (mode == _LK_UNLCK)
1525 ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1526 else
1527 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1528 /* FIXME - what about error settings? */
1529 release_ioinfo(info);
1530 return ret ? 0 : -1;
1533 /*********************************************************************
1534 * _fseeki64 (MSVCRT.@)
1536 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1538 int ret;
1540 _lock_file(file);
1541 ret = _fseeki64_nolock(file, offset, whence);
1542 _unlock_file(file);
1544 return ret;
1547 /*********************************************************************
1548 * _fseeki64_nolock (MSVCRT.@)
1550 int CDECL _fseeki64_nolock(FILE* file, __int64 offset, int whence)
1552 int ret;
1554 if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1555 whence = SEEK_SET;
1556 offset += _ftelli64_nolock(file);
1559 /* Flush output if needed */
1560 msvcrt_flush_buffer(file);
1561 /* Reset direction of i/o */
1562 if(file->_flag & _IORW) {
1563 file->_flag &= ~(_IOREAD|_IOWRT);
1565 /* Clear end of file flag */
1566 file->_flag &= ~_IOEOF;
1567 ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1569 return ret;
1572 /*********************************************************************
1573 * fseek (MSVCRT.@)
1575 int CDECL fseek(FILE* file, __msvcrt_long offset, int whence)
1577 return _fseeki64( file, offset, whence );
1580 /*********************************************************************
1581 * _fseek_nolock (MSVCRT.@)
1583 int CDECL _fseek_nolock(FILE* file, __msvcrt_long offset, int whence)
1585 return _fseeki64_nolock( file, offset, whence );
1588 /*********************************************************************
1589 * _chsize_s (MSVCRT.@)
1591 int CDECL _chsize_s(int fd, __int64 size)
1593 ioinfo *info;
1594 __int64 cur, pos;
1595 BOOL ret = FALSE;
1597 TRACE("(fd=%d, size=%#I64x)\n", fd, size);
1599 if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
1602 info = get_ioinfo(fd);
1603 if (info->handle != INVALID_HANDLE_VALUE)
1605 /* save the current file pointer */
1606 cur = _lseeki64(fd, 0, SEEK_CUR);
1607 if (cur >= 0)
1609 pos = _lseeki64(fd, size, SEEK_SET);
1610 if (pos >= 0)
1612 ret = SetEndOfFile(info->handle);
1613 if (!ret) msvcrt_set_errno(GetLastError());
1616 /* restore the file pointer */
1617 _lseeki64(fd, cur, SEEK_SET);
1621 release_ioinfo(info);
1622 return ret ? 0 : *_errno();
1625 /*********************************************************************
1626 * _chsize (MSVCRT.@)
1628 int CDECL _chsize(int fd, __msvcrt_long size)
1630 /* _chsize_s returns errno on failure but _chsize should return -1 */
1631 return _chsize_s( fd, size ) == 0 ? 0 : -1;
1634 /*********************************************************************
1635 * clearerr (MSVCRT.@)
1637 void CDECL clearerr(FILE* file)
1639 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1641 _lock_file(file);
1642 file->_flag &= ~(_IOERR | _IOEOF);
1643 _unlock_file(file);
1646 /*********************************************************************
1647 * clearerr_s (MSVCRT.@)
1649 int CDECL clearerr_s(FILE* file)
1651 TRACE(":file (%p)\n",file);
1653 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
1655 _lock_file(file);
1656 file->_flag &= ~(_IOERR | _IOEOF);
1657 _unlock_file(file);
1658 return 0;
1661 /*********************************************************************
1662 * rewind (MSVCRT.@)
1664 void CDECL rewind(FILE* file)
1666 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1668 _lock_file(file);
1669 _fseek_nolock(file, 0L, SEEK_SET);
1670 clearerr(file);
1671 _unlock_file(file);
1674 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1676 int plus = wcschr(mode, '+') != NULL;
1678 TRACE("%s\n", debugstr_w(mode));
1680 while(*mode == ' ') mode++;
1682 switch(*mode++)
1684 case 'R': case 'r':
1685 *open_flags = plus ? _O_RDWR : _O_RDONLY;
1686 *stream_flags = plus ? _IORW : _IOREAD;
1687 break;
1688 case 'W': case 'w':
1689 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1690 *stream_flags = plus ? _IORW : _IOWRT;
1691 break;
1692 case 'A': case 'a':
1693 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1694 *stream_flags = plus ? _IORW : _IOWRT;
1695 break;
1696 default:
1697 MSVCRT_INVALID_PMT(0, EINVAL);
1698 return -1;
1701 *stream_flags |= MSVCRT__commode;
1703 while (*mode && *mode!=',')
1704 switch (*mode++)
1706 case 'B': case 'b':
1707 *open_flags |= _O_BINARY;
1708 *open_flags &= ~_O_TEXT;
1709 break;
1710 case 't':
1711 *open_flags |= _O_TEXT;
1712 *open_flags &= ~_O_BINARY;
1713 break;
1714 #if _MSVCR_VER>=140
1715 case 'x':
1716 if(!MSVCRT_CHECK_PMT((*open_flags & (_O_CREAT | _O_APPEND)) == _O_CREAT))
1717 return -1;
1718 *open_flags |= _O_EXCL;
1719 break;
1720 #endif
1721 case 'D':
1722 *open_flags |= _O_TEMPORARY;
1723 break;
1724 case 'T':
1725 *open_flags |= _O_SHORT_LIVED;
1726 break;
1727 case 'c':
1728 *stream_flags |= MSVCRT__IOCOMMIT;
1729 break;
1730 case 'n':
1731 *stream_flags &= ~MSVCRT__IOCOMMIT;
1732 break;
1733 case 'N':
1734 *open_flags |= _O_NOINHERIT;
1735 break;
1736 case '+':
1737 case ' ':
1738 case 'a':
1739 case 'w':
1740 break;
1741 case 'S':
1742 if (!(*open_flags & _O_RANDOM))
1743 *open_flags |= _O_SEQUENTIAL;
1744 break;
1745 case 'R':
1746 if (!(*open_flags & _O_SEQUENTIAL))
1747 *open_flags |= _O_RANDOM;
1748 break;
1749 default:
1750 ERR("incorrect mode flag: %c\n", mode[-1]);
1751 break;
1754 if(*mode == ',')
1756 mode++;
1757 while(*mode == ' ') mode++;
1758 if(!MSVCRT_CHECK_PMT(!wcsncmp(L"ccs", mode, 3)))
1759 return -1;
1760 mode += 3;
1761 while(*mode == ' ') mode++;
1762 if(!MSVCRT_CHECK_PMT(*mode == '='))
1763 return -1;
1764 mode++;
1765 while(*mode == ' ') mode++;
1767 if(!_wcsnicmp(L"utf-8", mode, 5))
1769 *open_flags |= _O_U8TEXT;
1770 mode += 5;
1772 else if(!_wcsnicmp(L"utf-16le", mode, 8))
1774 *open_flags |= _O_U16TEXT;
1775 mode += 8;
1777 else if(!_wcsnicmp(L"unicode", mode, 7))
1779 *open_flags |= _O_WTEXT;
1780 mode += 7;
1782 else
1784 MSVCRT_INVALID_PMT(0, EINVAL);
1785 return -1;
1788 while(*mode == ' ') mode++;
1791 if(!MSVCRT_CHECK_PMT(*mode == 0))
1792 return -1;
1793 return 0;
1796 /*********************************************************************
1797 * _fdopen (MSVCRT.@)
1799 FILE* CDECL _fdopen(int fd, const char *mode)
1801 FILE *ret;
1802 wchar_t *modeW = NULL;
1804 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1806 ret = _wfdopen(fd, modeW);
1808 free(modeW);
1809 return ret;
1812 /*********************************************************************
1813 * _wfdopen (MSVCRT.@)
1815 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1817 int open_flags, stream_flags;
1818 FILE* file;
1820 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1822 LOCK_FILES();
1823 if (!(file = msvcrt_alloc_fp()))
1824 file = NULL;
1825 else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1827 file->_flag = 0;
1828 file = NULL;
1830 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1831 UNLOCK_FILES();
1833 return file;
1836 /*********************************************************************
1837 * _filelength (MSVCRT.@)
1839 __msvcrt_long CDECL _filelength(int fd)
1841 LONG curPos = _lseek(fd, 0, SEEK_CUR);
1842 if (curPos != -1)
1844 LONG endPos = _lseek(fd, 0, SEEK_END);
1845 if (endPos != -1)
1847 if (endPos != curPos)
1848 _lseek(fd, curPos, SEEK_SET);
1849 return endPos;
1852 return -1;
1855 /*********************************************************************
1856 * _filelengthi64 (MSVCRT.@)
1858 __int64 CDECL _filelengthi64(int fd)
1860 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1861 if (curPos != -1)
1863 __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1864 if (endPos != -1)
1866 if (endPos != curPos)
1867 _lseeki64(fd, curPos, SEEK_SET);
1868 return endPos;
1871 return -1;
1874 /*********************************************************************
1875 * _fileno (MSVCRT.@)
1877 int CDECL _fileno(FILE* file)
1879 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1880 return file->_file;
1883 /*********************************************************************
1884 * _fstat64 (MSVCRT.@)
1886 int CDECL _fstat64(int fd, struct _stat64* buf)
1888 ioinfo *info = get_ioinfo(fd);
1889 DWORD dw;
1890 DWORD type;
1892 TRACE(":fd (%d) stat (%p)\n", fd, buf);
1893 if (info->handle == INVALID_HANDLE_VALUE)
1895 release_ioinfo(info);
1896 return -1;
1899 if (!buf)
1901 WARN(":failed-NULL buf\n");
1902 msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1903 release_ioinfo(info);
1904 return -1;
1907 memset(buf, 0, sizeof(struct _stat64));
1908 type = GetFileType(info->handle);
1909 if (type == FILE_TYPE_PIPE)
1911 buf->st_dev = buf->st_rdev = fd;
1912 buf->st_mode = _S_IFIFO;
1913 buf->st_nlink = 1;
1915 else if (type == FILE_TYPE_CHAR)
1917 buf->st_dev = buf->st_rdev = fd;
1918 buf->st_mode = _S_IFCHR;
1919 buf->st_nlink = 1;
1921 else /* FILE_TYPE_DISK etc. */
1923 FILE_BASIC_INFORMATION basic_info;
1924 FILE_STANDARD_INFORMATION std_info;
1925 IO_STATUS_BLOCK io;
1926 NTSTATUS status;
1928 if ((status = NtQueryInformationFile( info->handle, &io, &basic_info, sizeof(basic_info), FileBasicInformation )) ||
1929 (status = NtQueryInformationFile( info->handle, &io, &std_info, sizeof(std_info), FileStandardInformation )))
1931 WARN(":failed-error %lx\n", status);
1932 msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1933 release_ioinfo(info);
1934 return -1;
1936 buf->st_mode = _S_IFREG | 0444;
1937 if (!(basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY))
1938 buf->st_mode |= 0222;
1939 buf->st_size = std_info.EndOfFile.QuadPart;
1940 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&basic_info.LastAccessTime, &dw);
1941 buf->st_atime = dw;
1942 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&basic_info.LastWriteTime, &dw);
1943 buf->st_mtime = buf->st_ctime = dw;
1944 buf->st_nlink = std_info.NumberOfLinks;
1945 TRACE(":dwFileAttributes = %#lx, mode set to %#x\n",
1946 basic_info.FileAttributes, buf->st_mode);
1948 release_ioinfo(info);
1949 return 0;
1952 /*********************************************************************
1953 * _fstati64 (MSVCRT.@)
1955 int CDECL _fstati64(int fd, struct _stati64* buf)
1957 int ret;
1958 struct _stat64 buf64;
1960 ret = _fstat64(fd, &buf64);
1961 if (!ret)
1962 msvcrt_stat64_to_stati64(&buf64, buf);
1963 return ret;
1966 /*********************************************************************
1967 * _fstat (MSVCRT.@)
1969 int CDECL _fstat(int fd, struct _stat* buf)
1970 { int ret;
1971 struct _stat64 buf64;
1973 ret = _fstat64(fd, &buf64);
1974 if (!ret)
1975 msvcrt_stat64_to_stat(&buf64, buf);
1976 return ret;
1979 /*********************************************************************
1980 * _fstat32 (MSVCR80.@)
1982 int CDECL _fstat32(int fd, struct _stat32* buf)
1984 int ret;
1985 struct _stat64 buf64;
1987 ret = _fstat64(fd, &buf64);
1988 if (!ret)
1989 msvcrt_stat64_to_stat32(&buf64, buf);
1990 return ret;
1993 /*********************************************************************
1994 * _fstat32i64 (MSVCR80.@)
1996 int CDECL _fstat32i64(int fd, struct _stat32i64* buf)
1998 int ret;
1999 struct _stat64 buf64;
2001 ret = _fstat64(fd, &buf64);
2002 if (!ret)
2003 msvcrt_stat64_to_stat32i64(&buf64, buf);
2004 return ret;
2007 /*********************************************************************
2008 * _fstat64i32 (MSVCR80.@)
2010 int CDECL _fstat64i32(int fd, struct _stat64i32* buf)
2012 int ret;
2013 struct _stat64 buf64;
2015 ret = _fstat64(fd, &buf64);
2016 if (!ret)
2017 msvcrt_stat64_to_stat64i32(&buf64, buf);
2018 return ret;
2021 /*********************************************************************
2022 * _futime64 (MSVCRT.@)
2024 int CDECL _futime64(int fd, struct __utimbuf64 *t)
2026 ioinfo *info = get_ioinfo(fd);
2027 FILETIME at, wt;
2029 if (!t)
2031 time_to_filetime( _time64(NULL), &at );
2032 wt = at;
2034 else
2036 time_to_filetime( t->actime, &at );
2037 time_to_filetime( t->modtime, &wt );
2040 if (!SetFileTime(info->handle, NULL, &at, &wt))
2042 release_ioinfo(info);
2043 msvcrt_set_errno(GetLastError());
2044 return -1 ;
2046 release_ioinfo(info);
2047 return 0;
2050 /*********************************************************************
2051 * _futime32 (MSVCRT.@)
2053 int CDECL _futime32(int fd, struct __utimbuf32 *t)
2055 if (t)
2057 struct __utimbuf64 t64;
2058 t64.actime = t->actime;
2059 t64.modtime = t->modtime;
2060 return _futime64( fd, &t64 );
2062 else
2063 return _futime64( fd, NULL );
2066 /*********************************************************************
2067 * _get_osfhandle (MSVCRT.@)
2069 intptr_t CDECL _get_osfhandle(int fd)
2071 HANDLE hand = get_ioinfo_nolock(fd)->handle;
2072 TRACE(":fd (%d) handle (%p)\n",fd,hand);
2074 if(hand == INVALID_HANDLE_VALUE)
2075 *_errno() = EBADF;
2076 return (intptr_t)hand;
2079 /*********************************************************************
2080 * _mktemp_s (MSVCRT.@)
2082 int CDECL _mktemp_s(char *pattern, size_t size)
2084 DWORD len, xno, id;
2086 if(!MSVCRT_CHECK_PMT(pattern!=NULL))
2087 return EINVAL;
2089 for(len=0; len<size; len++)
2090 if(!pattern[len])
2091 break;
2092 if(!MSVCRT_CHECK_PMT(len!=size && len>=6)) {
2093 if(size)
2094 pattern[0] = 0;
2095 return EINVAL;
2098 for(xno=1; xno<=6; xno++)
2099 if(!MSVCRT_CHECK_PMT(pattern[len-xno] == 'X'))
2100 return EINVAL;
2102 id = GetCurrentProcessId();
2103 for(xno=1; xno<6; xno++) {
2104 pattern[len-xno] = id%10 + '0';
2105 id /= 10;
2108 for(pattern[len-6]='a'; pattern[len-6]<='z'; pattern[len-6]++) {
2109 if(GetFileAttributesA(pattern) == INVALID_FILE_ATTRIBUTES)
2110 return 0;
2113 pattern[0] = 0;
2114 *_errno() = EEXIST;
2115 return EEXIST;
2118 /*********************************************************************
2119 * _mktemp (MSVCRT.@)
2121 char * CDECL _mktemp(char *pattern)
2123 int numX = 0;
2124 char *retVal = pattern;
2125 int id;
2126 char letter = 'a';
2128 if(!pattern)
2129 return NULL;
2131 while(*pattern)
2132 numX = (*pattern++ == 'X')? numX + 1 : 0;
2133 if (numX < 6)
2134 return NULL;
2135 pattern--;
2136 id = GetCurrentProcessId();
2137 numX = 6;
2138 while(numX--)
2140 int tempNum = id / 10;
2141 *pattern-- = id - (tempNum * 10) + '0';
2142 id = tempNum;
2144 pattern++;
2147 *pattern = letter++;
2148 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
2149 return retVal;
2150 } while(letter <= 'z');
2151 return NULL;
2154 /*********************************************************************
2155 * _wmktemp_s (MSVCRT.@)
2157 int CDECL _wmktemp_s(wchar_t *pattern, size_t size)
2159 DWORD len, xno, id;
2161 if(!MSVCRT_CHECK_PMT(pattern!=NULL))
2162 return EINVAL;
2164 for(len=0; len<size; len++)
2165 if(!pattern[len])
2166 break;
2167 if(!MSVCRT_CHECK_PMT(len!=size && len>=6)) {
2168 if(size)
2169 pattern[0] = 0;
2170 return EINVAL;
2173 for(xno=1; xno<=6; xno++)
2174 if(!MSVCRT_CHECK_PMT(pattern[len-xno] == 'X'))
2175 return EINVAL;
2177 id = GetCurrentProcessId();
2178 for(xno=1; xno<6; xno++) {
2179 pattern[len-xno] = id%10 + '0';
2180 id /= 10;
2183 for(pattern[len-6]='a'; pattern[len-6]<='z'; pattern[len-6]++) {
2184 if(GetFileAttributesW(pattern) == INVALID_FILE_ATTRIBUTES)
2185 return 0;
2188 pattern[0] = 0;
2189 *_errno() = EEXIST;
2190 return EEXIST;
2193 /*********************************************************************
2194 * _wmktemp (MSVCRT.@)
2196 wchar_t * CDECL _wmktemp(wchar_t *pattern)
2198 int numX = 0;
2199 wchar_t *retVal = pattern;
2200 int id;
2201 wchar_t letter = 'a';
2203 if(!pattern)
2204 return NULL;
2206 while(*pattern)
2207 numX = (*pattern++ == 'X')? numX + 1 : 0;
2208 if (numX < 6)
2209 return NULL;
2210 pattern--;
2211 id = GetCurrentProcessId();
2212 numX = 6;
2213 while(numX--)
2215 int tempNum = id / 10;
2216 *pattern-- = id - (tempNum * 10) + '0';
2217 id = tempNum;
2219 pattern++;
2222 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES)
2223 return retVal;
2224 *pattern = letter++;
2225 } while(letter != '|');
2226 return NULL;
2229 static unsigned split_oflags(unsigned oflags)
2231 int wxflags = 0;
2232 unsigned unsupp; /* until we support everything */
2234 if (oflags & _O_APPEND) wxflags |= WX_APPEND;
2235 if (oflags & _O_BINARY) {/* Nothing to do */}
2236 else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
2237 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
2238 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
2239 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
2240 else
2242 int fmode;
2243 _get_fmode(&fmode);
2244 if (!(fmode & _O_BINARY)) wxflags |= WX_TEXT; /* default to TEXT*/
2246 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
2248 if ((unsupp = oflags & ~(_O_BINARY | _O_TEXT | _O_APPEND | _O_TRUNC | _O_EXCL | _O_CREAT |
2249 _O_RDWR | _O_WRONLY | _O_TEMPORARY | _O_NOINHERIT | _O_SEQUENTIAL |
2250 _O_RANDOM | _O_SHORT_LIVED | _O_WTEXT | _O_U16TEXT | _O_U8TEXT)))
2251 ERR(":unsupported oflags %#x\n",unsupp);
2253 return wxflags;
2256 /*********************************************************************
2257 * _pipe (MSVCRT.@)
2259 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
2261 int ret = -1;
2262 SECURITY_ATTRIBUTES sa;
2263 HANDLE readHandle, writeHandle;
2265 if (!pfds)
2267 *_errno() = EINVAL;
2268 return -1;
2271 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2272 sa.bInheritHandle = !(textmode & _O_NOINHERIT);
2273 sa.lpSecurityDescriptor = NULL;
2274 if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
2276 unsigned int wxflags = split_oflags(textmode);
2277 int fd;
2279 fd = msvcrt_alloc_fd(readHandle, wxflags|WX_PIPE);
2280 if (fd != -1)
2282 pfds[0] = fd;
2283 fd = msvcrt_alloc_fd(writeHandle, wxflags|WX_PIPE);
2284 if (fd != -1)
2286 pfds[1] = fd;
2287 ret = 0;
2289 else
2291 _close(pfds[0]);
2292 CloseHandle(writeHandle);
2293 *_errno() = EMFILE;
2296 else
2298 CloseHandle(readHandle);
2299 CloseHandle(writeHandle);
2300 *_errno() = EMFILE;
2303 else
2304 msvcrt_set_errno(GetLastError());
2306 return ret;
2309 static int check_bom(HANDLE h, int oflags, BOOL seek)
2311 char bom[sizeof(utf8_bom)];
2312 DWORD r;
2314 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
2315 return oflags;
2317 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
2318 oflags = (oflags & ~(_O_WTEXT | _O_U16TEXT)) | _O_U8TEXT;
2319 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
2320 if (seek && r>2)
2321 SetFilePointer(h, 2, NULL, FILE_BEGIN);
2322 oflags = (oflags & ~(_O_WTEXT | _O_U8TEXT)) | _O_U16TEXT;
2323 }else if (seek) {
2324 SetFilePointer(h, 0, NULL, FILE_BEGIN);
2327 return oflags;
2330 /*********************************************************************
2331 * _wsopen_dispatch (UCRTBASE.@)
2333 int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pmode,
2334 int *fd, int secure )
2336 DWORD access = 0, creation = 0, attrib;
2337 SECURITY_ATTRIBUTES sa;
2338 DWORD sharing, type;
2339 int wxflag;
2340 HANDLE hand;
2342 TRACE("path: (%s) oflags: %#x shflags: %#x pmode: %#x fd*: %p secure: %d\n",
2343 debugstr_w(path), oflags, shflags, pmode, fd, secure);
2345 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
2347 *fd = -1;
2348 wxflag = split_oflags(oflags);
2349 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
2351 case _O_RDONLY: access |= GENERIC_READ; break;
2352 case _O_WRONLY: access |= GENERIC_WRITE; break;
2353 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
2356 if (oflags & _O_CREAT)
2358 if (secure && !MSVCRT_CHECK_PMT(!(pmode & ~(_S_IREAD | _S_IWRITE))))
2359 return EINVAL;
2361 if (oflags & _O_EXCL)
2362 creation = CREATE_NEW;
2363 else if (oflags & _O_TRUNC)
2364 creation = CREATE_ALWAYS;
2365 else
2366 creation = OPEN_ALWAYS;
2368 else /* no _O_CREAT */
2370 if (oflags & _O_TRUNC)
2371 creation = TRUNCATE_EXISTING;
2372 else
2373 creation = OPEN_EXISTING;
2376 switch( shflags )
2378 case _SH_DENYRW:
2379 sharing = 0L;
2380 break;
2381 case _SH_DENYWR:
2382 sharing = FILE_SHARE_READ;
2383 break;
2384 case _SH_DENYRD:
2385 sharing = FILE_SHARE_WRITE;
2386 break;
2387 case _SH_DENYNO:
2388 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
2389 break;
2390 default:
2391 ERR( "Unhandled shflags %#x\n", shflags );
2392 return EINVAL;
2395 if (!(pmode & ~MSVCRT_umask & _S_IWRITE))
2396 attrib = FILE_ATTRIBUTE_READONLY;
2397 else
2398 attrib = FILE_ATTRIBUTE_NORMAL;
2400 if (oflags & _O_TEMPORARY)
2402 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
2403 access |= DELETE;
2404 sharing |= FILE_SHARE_DELETE;
2407 if (oflags & _O_RANDOM)
2408 attrib |= FILE_FLAG_RANDOM_ACCESS;
2409 if (oflags & _O_SEQUENTIAL)
2410 attrib |= FILE_FLAG_SEQUENTIAL_SCAN;
2411 if (oflags & _O_SHORT_LIVED)
2412 attrib |= FILE_ATTRIBUTE_TEMPORARY;
2414 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
2415 sa.lpSecurityDescriptor = NULL;
2416 sa.bInheritHandle = !(oflags & _O_NOINHERIT);
2418 if ((oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
2419 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
2420 && !(access&GENERIC_READ))
2422 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
2423 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2424 if (hand != INVALID_HANDLE_VALUE)
2426 oflags = check_bom(hand, oflags, FALSE);
2427 CloseHandle(hand);
2431 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
2432 if (hand == INVALID_HANDLE_VALUE) {
2433 WARN(":failed-last error (%ld)\n", GetLastError());
2434 msvcrt_set_errno(GetLastError());
2435 return *_errno();
2438 if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
2440 LARGE_INTEGER size = {{0}};
2442 if ((access & GENERIC_WRITE) && (creation==OPEN_EXISTING || creation==OPEN_ALWAYS))
2443 GetFileSizeEx(hand, &size);
2445 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
2446 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
2447 || ((creation==OPEN_EXISTING || creation==OPEN_ALWAYS) && !size.QuadPart)))
2449 if (oflags & _O_U8TEXT)
2451 DWORD written = 0, tmp;
2453 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
2454 sizeof(utf8_bom)-written, &tmp, NULL))
2455 written += tmp;
2456 if (written != sizeof(utf8_bom)) {
2457 WARN("error writing BOM\n");
2458 CloseHandle(hand);
2459 msvcrt_set_errno(GetLastError());
2460 return *_errno();
2463 else
2465 DWORD written = 0, tmp;
2467 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
2468 sizeof(utf16_bom)-written, &tmp, NULL))
2469 written += tmp;
2470 if (written != sizeof(utf16_bom))
2472 WARN("error writing BOM\n");
2473 CloseHandle(hand);
2474 msvcrt_set_errno(GetLastError());
2475 return *_errno();
2477 oflags |= _O_U16TEXT;
2480 else if (access & GENERIC_READ)
2481 oflags = check_bom(hand, oflags, TRUE);
2484 type = GetFileType(hand);
2485 if (type == FILE_TYPE_CHAR)
2486 wxflag |= WX_TTY;
2487 else if (type == FILE_TYPE_PIPE)
2488 wxflag |= WX_PIPE;
2490 *fd = msvcrt_alloc_fd(hand, wxflag);
2491 if (*fd == -1)
2492 return *_errno();
2494 if (oflags & _O_WTEXT)
2495 ioinfo_set_unicode(get_ioinfo_nolock(*fd), TRUE);
2497 if (oflags & _O_U16TEXT)
2498 ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF16LE);
2499 else if (oflags & _O_U8TEXT)
2500 ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF8);
2502 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
2503 return 0;
2507 /*********************************************************************
2508 * _wsopen_s (MSVCRT.@)
2510 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
2512 return _wsopen_dispatch( path, oflags, shflags, pmode, fd, 1 );
2515 /*********************************************************************
2516 * _wsopen (MSVCRT.@)
2518 int WINAPIV _wsopen( const wchar_t *path, int oflags, int shflags, ... )
2520 int pmode;
2521 int fd;
2523 if (oflags & _O_CREAT)
2525 va_list ap;
2527 va_start(ap, shflags);
2528 pmode = va_arg(ap, int);
2529 va_end(ap);
2531 else
2532 pmode = 0;
2534 return _wsopen_dispatch(path, oflags, shflags, pmode, &fd, 0) ? -1 : fd;
2538 /*********************************************************************
2539 * _sopen_dispatch (UCRTBASE.@)
2541 int CDECL _sopen_dispatch( const char *path, int oflags, int shflags,
2542 int pmode, int *fd, int secure)
2544 wchar_t *pathW;
2545 int ret;
2547 if (!MSVCRT_CHECK_PMT(fd != NULL))
2548 return EINVAL;
2549 *fd = -1;
2550 if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
2551 return EINVAL;
2553 ret = _wsopen_dispatch(pathW, oflags, shflags, pmode, fd, secure);
2554 free(pathW);
2555 return ret;
2558 /*********************************************************************
2559 * _sopen_s (MSVCRT.@)
2561 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
2563 return _sopen_dispatch(path, oflags, shflags, pmode, fd, 1);
2566 /*********************************************************************
2567 * _sopen (MSVCRT.@)
2569 int WINAPIV _sopen( const char *path, int oflags, int shflags, ... )
2571 int pmode;
2572 int fd;
2574 if (oflags & _O_CREAT)
2576 va_list ap;
2578 va_start(ap, shflags);
2579 pmode = va_arg(ap, int);
2580 va_end(ap);
2582 else
2583 pmode = 0;
2585 return _sopen_dispatch(path, oflags, shflags, pmode, &fd, 0) ? -1 : fd;
2588 /*********************************************************************
2589 * _open (MSVCRT.@)
2591 int WINAPIV _open( const char *path, int flags, ... )
2593 va_list ap;
2595 if (flags & _O_CREAT)
2597 int pmode;
2598 va_start(ap, flags);
2599 pmode = va_arg(ap, int);
2600 va_end(ap);
2601 return _sopen( path, flags, _SH_DENYNO, pmode );
2603 else
2604 return _sopen( path, flags, _SH_DENYNO);
2607 /*********************************************************************
2608 * _wopen (MSVCRT.@)
2610 int WINAPIV _wopen(const wchar_t *path,int flags,...)
2612 va_list ap;
2614 if (flags & _O_CREAT)
2616 int pmode;
2617 va_start(ap, flags);
2618 pmode = va_arg(ap, int);
2619 va_end(ap);
2620 return _wsopen( path, flags, _SH_DENYNO, pmode );
2622 else
2623 return _wsopen( path, flags, _SH_DENYNO);
2626 /*********************************************************************
2627 * _creat (MSVCRT.@)
2629 int CDECL _creat(const char *path, int pmode)
2631 int flags = _O_CREAT | _O_TRUNC | _O_RDWR;
2632 return _open(path, flags, pmode);
2635 /*********************************************************************
2636 * _wcreat (MSVCRT.@)
2638 int CDECL _wcreat(const wchar_t *path, int pmode)
2640 int flags = _O_CREAT | _O_TRUNC | _O_RDWR;
2641 return _wopen(path, flags, pmode);
2644 /*********************************************************************
2645 * _open_osfhandle (MSVCRT.@)
2647 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2649 DWORD flags;
2650 int fd;
2652 /* _O_RDONLY (0) always matches, so set the read flag
2653 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2654 * file, so set the write flag. It also only sets _O_TEXT if it wants
2655 * text - it never sets _O_BINARY.
2657 /* don't let split_oflags() decide the mode if no mode is passed */
2658 if (!(oflags & (_O_BINARY | _O_TEXT)))
2659 oflags |= _O_BINARY;
2661 flags = GetFileType((HANDLE)handle);
2662 if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2664 msvcrt_set_errno(GetLastError());
2665 return -1;
2668 if (flags == FILE_TYPE_CHAR)
2669 flags = WX_TTY;
2670 else if (flags == FILE_TYPE_PIPE)
2671 flags = WX_PIPE;
2672 else
2673 flags = 0;
2674 flags |= split_oflags(oflags);
2676 fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2677 TRACE(":handle (%Iu) fd (%d) flags %#lx\n", handle, fd, flags);
2678 return fd;
2681 /*********************************************************************
2682 * _rmtmp (MSVCRT.@)
2684 int CDECL _rmtmp(void)
2686 int num_removed = 0, i;
2687 FILE *file;
2689 LOCK_FILES();
2690 for (i = 3; i < MSVCRT_stream_idx; i++) {
2691 file = msvcrt_get_file(i);
2693 if (file->_tmpfname)
2695 fclose(file);
2696 num_removed++;
2699 UNLOCK_FILES();
2701 if (num_removed)
2702 TRACE(":removed (%d) temp files\n",num_removed);
2703 return num_removed;
2706 static inline int get_utf8_char_len(char ch)
2708 if((ch&0xf8) == 0xf0)
2709 return 4;
2710 else if((ch&0xf0) == 0xe0)
2711 return 3;
2712 else if((ch&0xe0) == 0xc0)
2713 return 2;
2714 return 1;
2717 /*********************************************************************
2718 * (internal) read_utf8
2720 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2722 HANDLE hand = fdinfo->handle;
2723 char min_buf[4], *readbuf, lookahead;
2724 DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2726 /* make the buffer big enough to hold at least one character */
2727 /* read bytes have to fit to output and lookahead buffers */
2728 count /= 2;
2729 readbuf_size = count < 4 ? 4 : count;
2730 if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2731 readbuf_size = 4;
2732 readbuf = min_buf;
2735 if(fdinfo->lookahead[0] != '\n') {
2736 readbuf[pos++] = fdinfo->lookahead[0];
2737 fdinfo->lookahead[0] = '\n';
2739 if(fdinfo->lookahead[1] != '\n') {
2740 readbuf[pos++] = fdinfo->lookahead[1];
2741 fdinfo->lookahead[1] = '\n';
2743 if(fdinfo->lookahead[2] != '\n') {
2744 readbuf[pos++] = fdinfo->lookahead[2];
2745 fdinfo->lookahead[2] = '\n';
2750 /* NOTE: this case is broken in native dll, reading
2751 * sometimes fails when small buffer is passed
2753 if(count < 4) {
2754 if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2755 if (GetLastError() == ERROR_BROKEN_PIPE) {
2756 fdinfo->wxflag |= WX_ATEOF;
2757 return 0;
2758 }else {
2759 msvcrt_set_errno(GetLastError());
2760 if (GetLastError() == ERROR_ACCESS_DENIED)
2761 *_errno() = EBADF;
2762 return -1;
2764 }else if(!num_read) {
2765 fdinfo->wxflag |= WX_ATEOF;
2766 return 0;
2767 }else {
2768 pos++;
2771 char_len = get_utf8_char_len(readbuf[0]);
2772 if(char_len>pos) {
2773 if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2774 pos += num_read;
2777 if(readbuf[0] == '\n')
2778 fdinfo->wxflag |= WX_READNL;
2779 else
2780 fdinfo->wxflag &= ~WX_READNL;
2782 if(readbuf[0] == 0x1a) {
2783 fdinfo->wxflag |= WX_ATEOF;
2784 return 0;
2787 if(readbuf[0] == '\r') {
2788 if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2789 buf[0] = '\r';
2790 else if(lookahead == '\n')
2791 buf[0] = '\n';
2792 else {
2793 buf[0] = '\r';
2794 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2795 fdinfo->lookahead[0] = lookahead;
2796 else
2797 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2799 return 2;
2802 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2803 msvcrt_set_errno(GetLastError());
2804 return -1;
2807 return num_read*2;
2810 if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2811 if(pos) {
2812 num_read = 0;
2813 }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2814 fdinfo->wxflag |= WX_ATEOF;
2815 if (readbuf != min_buf) free(readbuf);
2816 return 0;
2817 }else {
2818 msvcrt_set_errno(GetLastError());
2819 if (GetLastError() == ERROR_ACCESS_DENIED)
2820 *_errno() = EBADF;
2821 if (readbuf != min_buf) free(readbuf);
2822 return -1;
2824 }else if(!pos && !num_read) {
2825 fdinfo->wxflag |= WX_ATEOF;
2826 if (readbuf != min_buf) free(readbuf);
2827 return 0;
2830 pos += num_read;
2831 if(readbuf[0] == '\n')
2832 fdinfo->wxflag |= WX_READNL;
2833 else
2834 fdinfo->wxflag &= ~WX_READNL;
2836 /* Find first byte of last character (may be incomplete) */
2837 for(i=pos-1; i>0 && i>pos-4; i--)
2838 if((readbuf[i]&0xc0) != 0x80)
2839 break;
2840 char_len = get_utf8_char_len(readbuf[i]);
2841 if(char_len+i <= pos)
2842 i += char_len;
2844 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2845 if(i < pos)
2846 fdinfo->lookahead[0] = readbuf[i];
2847 if(i+1 < pos)
2848 fdinfo->lookahead[1] = readbuf[i+1];
2849 if(i+2 < pos)
2850 fdinfo->lookahead[2] = readbuf[i+2];
2851 }else if(i < pos) {
2852 SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2854 pos = i;
2856 for(i=0, j=0; i<pos; i++) {
2857 if(readbuf[i] == 0x1a) {
2858 fdinfo->wxflag |= WX_ATEOF;
2859 break;
2862 /* strip '\r' if followed by '\n' */
2863 if(readbuf[i] == '\r' && i+1==pos) {
2864 if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2865 readbuf[j++] = '\r';
2866 }else if(lookahead == '\n' && j==0) {
2867 readbuf[j++] = '\n';
2868 }else {
2869 if(lookahead != '\n')
2870 readbuf[j++] = '\r';
2872 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2873 fdinfo->lookahead[0] = lookahead;
2874 else
2875 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2877 }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2878 readbuf[j++] = readbuf[i];
2881 pos = j;
2883 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2884 msvcrt_set_errno(GetLastError());
2885 if (readbuf != min_buf) free(readbuf);
2886 return -1;
2889 if (readbuf != min_buf) free(readbuf);
2890 return num_read*2;
2893 /*********************************************************************
2894 * (internal) read_i
2896 * When reading \r as last character in text mode, read() positions
2897 * the file pointer on the \r character while getc() goes on to
2898 * the following \n
2900 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2902 DWORD num_read, utf16;
2903 char *bufstart = buf;
2905 if (count == 0)
2906 return 0;
2908 if (fdinfo->wxflag & WX_ATEOF) {
2909 TRACE("already at EOF, returning 0\n");
2910 return 0;
2912 /* Don't trace small reads, it gets *very* annoying */
2913 if (count > 4)
2914 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2915 if (fdinfo->handle == INVALID_HANDLE_VALUE)
2917 *_errno() = EBADF;
2918 return -1;
2921 utf16 = ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF16LE;
2922 if (ioinfo_get_textmode(fdinfo) != TEXTMODE_ANSI && count&1)
2924 *_errno() = EINVAL;
2925 return -1;
2928 if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF8)
2929 return read_utf8(fdinfo, buf, count);
2931 if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2933 if (fdinfo->lookahead[0] != '\n')
2935 bufstart[0] = fdinfo->lookahead[0];
2936 fdinfo->lookahead[0] = '\n';
2938 if (utf16)
2940 bufstart[1] = fdinfo->lookahead[1];
2941 fdinfo->lookahead[1] = '\n';
2944 if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2945 num_read += 1+utf16;
2946 else
2947 num_read = 1+utf16;
2950 if(utf16 && (num_read&1))
2952 /* msvcr90 uses uninitialized value from the buffer in this case */
2953 /* msvcrt ignores additional data */
2954 ERR("got odd number of bytes in UTF16 mode\n");
2955 num_read--;
2958 if (count != 0 && num_read == 0)
2960 fdinfo->wxflag |= WX_ATEOF;
2961 TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2963 else if (fdinfo->wxflag & WX_TEXT)
2965 DWORD i, j;
2967 if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2968 fdinfo->wxflag |= WX_READNL;
2969 else
2970 fdinfo->wxflag &= ~WX_READNL;
2972 for (i=0, j=0; i<num_read; i+=1+utf16)
2974 /* in text mode, a ctrl-z signals EOF */
2975 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2977 fdinfo->wxflag |= WX_ATEOF;
2978 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2979 break;
2982 /* in text mode, strip \r if followed by \n */
2983 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2985 char lookahead[2];
2986 DWORD len;
2988 lookahead[1] = '\n';
2989 if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
2991 if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2993 bufstart[j++] = '\n';
2994 if(utf16) bufstart[j++] = 0;
2996 else
2998 if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
3000 bufstart[j++] = '\r';
3001 if(utf16) bufstart[j++] = 0;
3004 if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
3006 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
3008 bufstart[j++] = '\n';
3009 if (utf16) bufstart[j++] = 0;
3011 else
3013 fdinfo->lookahead[0] = lookahead[0];
3014 fdinfo->lookahead[1] = lookahead[1];
3017 else
3018 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
3021 else
3023 bufstart[j++] = '\r';
3024 if(utf16) bufstart[j++] = 0;
3027 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
3028 || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
3030 bufstart[j++] = bufstart[i];
3031 if(utf16) bufstart[j++] = bufstart[i+1];
3034 num_read = j;
3037 else
3039 if (GetLastError() == ERROR_BROKEN_PIPE)
3041 TRACE(":end-of-pipe\n");
3042 fdinfo->wxflag |= WX_ATEOF;
3043 return 0;
3045 else
3047 TRACE(":failed-last error (%ld)\n", GetLastError());
3048 msvcrt_set_errno(GetLastError());
3049 if (GetLastError() == ERROR_ACCESS_DENIED)
3050 *_errno() = EBADF;
3051 return -1;
3055 if (count > 4)
3056 TRACE("(%lu), %s\n", num_read, debugstr_an(buf, num_read));
3057 return num_read;
3060 /*********************************************************************
3061 * _read (MSVCRT.@)
3063 int CDECL _read(int fd, void *buf, unsigned int count)
3065 ioinfo *info;
3066 int num_read;
3068 if(fd == MSVCRT_NO_CONSOLE_FD) {
3069 *_errno() = EBADF;
3070 return -1;
3073 info = get_ioinfo(fd);
3074 num_read = read_i(fd, info, buf, count);
3075 release_ioinfo(info);
3076 return num_read;
3079 /*********************************************************************
3080 * _setmode (MSVCRT.@)
3082 int CDECL _setmode(int fd,int mode)
3084 ioinfo *info = get_ioinfo(fd);
3085 int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
3087 if(ret==_O_TEXT && ioinfo_get_textmode(info) != TEXTMODE_ANSI)
3088 ret = _O_WTEXT;
3090 if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
3091 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
3092 *_errno() = EINVAL;
3093 release_ioinfo(info);
3094 return -1;
3097 if(info == &MSVCRT___badioinfo) {
3098 *_errno() = EBADF;
3099 return EOF;
3102 if(mode == _O_BINARY) {
3103 info->wxflag &= ~WX_TEXT;
3104 ioinfo_set_textmode(info, TEXTMODE_ANSI);
3105 release_ioinfo(info);
3106 return ret;
3109 info->wxflag |= WX_TEXT;
3110 if(mode == _O_TEXT)
3111 ioinfo_set_textmode(info, TEXTMODE_ANSI);
3112 else if(mode == _O_U8TEXT)
3113 ioinfo_set_textmode(info, TEXTMODE_UTF8);
3114 else
3115 ioinfo_set_textmode(info, TEXTMODE_UTF16LE);
3117 release_ioinfo(info);
3118 return ret;
3121 /*********************************************************************
3122 * _stat64 (MSVCRT.@)
3124 int CDECL _stat64(const char* path, struct _stat64 * buf)
3126 DWORD dw;
3127 WIN32_FILE_ATTRIBUTE_DATA hfi;
3128 unsigned short mode = ALL_S_IREAD;
3129 int plen;
3131 TRACE(":file (%s) buf(%p)\n", path, buf);
3133 plen = strlen(path);
3134 while (plen && path[plen-1]==' ')
3135 plen--;
3137 if (plen==2 && path[1]==':')
3139 *_errno() = ENOENT;
3140 return -1;
3143 #if _MSVCR_VER<140
3144 if (plen>=2 && path[plen-2]!=':' && (path[plen-1]=='\\' || path[plen-1]=='/'))
3146 *_errno() = ENOENT;
3147 return -1;
3149 #endif
3151 if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
3153 TRACE("failed (%ld)\n", GetLastError());
3154 *_errno() = ENOENT;
3155 return -1;
3158 memset(buf,0,sizeof(struct _stat64));
3160 /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
3161 Bon 011120: This FIXME seems incorrect
3162 Also a letter as first char isn't enough to be classified
3163 as a drive letter
3165 if (isalpha(*path)&& (*(path+1)==':'))
3166 buf->st_dev = buf->st_rdev = _toupper_l(*path, NULL) - 'A'; /* drive num */
3167 else
3168 buf->st_dev = buf->st_rdev = _getdrive() - 1;
3170 /* Dir, or regular file? */
3171 if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3172 mode |= (_S_IFDIR | ALL_S_IEXEC);
3173 else
3175 mode |= _S_IFREG;
3176 /* executable? */
3177 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
3179 unsigned int ext = _tolower_l(path[plen-1], NULL) |
3180 (_tolower_l(path[plen-2], NULL) << 8) |
3181 (_tolower_l(path[plen-3], NULL) << 16);
3182 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
3183 mode |= ALL_S_IEXEC;
3187 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
3188 mode |= ALL_S_IWRITE;
3190 buf->st_mode = mode;
3191 buf->st_nlink = 1;
3192 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
3193 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
3194 buf->st_atime = dw;
3195 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
3196 buf->st_mtime = buf->st_ctime = dw;
3197 TRACE("%d %d %#I64x %I64d %I64d %I64d\n", buf->st_mode, buf->st_nlink,
3198 buf->st_size, buf->st_atime, buf->st_mtime, buf->st_ctime);
3199 return 0;
3202 /*********************************************************************
3203 * _stati64 (MSVCRT.@)
3205 int CDECL _stati64(const char* path, struct _stati64 * buf)
3207 int ret;
3208 struct _stat64 buf64;
3210 ret = _stat64(path, &buf64);
3211 if (!ret)
3212 msvcrt_stat64_to_stati64(&buf64, buf);
3213 return ret;
3216 /*********************************************************************
3217 * _stat (MSVCRT.@)
3219 int CDECL _stat(const char* path, struct _stat * buf)
3221 int ret;
3222 struct _stat64 buf64;
3224 ret = _stat64( path, &buf64);
3225 if (!ret)
3226 msvcrt_stat64_to_stat(&buf64, buf);
3227 return ret;
3230 #if _MSVCR_VER >= 80
3232 /*********************************************************************
3233 * _stat32 (MSVCR80.@)
3235 int CDECL _stat32(const char *path, struct _stat32 *buf)
3237 int ret;
3238 struct _stat64 buf64;
3240 ret = _stat64(path, &buf64);
3241 if (!ret)
3242 msvcrt_stat64_to_stat32(&buf64, buf);
3243 return ret;
3246 /*********************************************************************
3247 * _stat32i64 (MSVCR80.@)
3249 int CDECL _stat32i64(const char *path, struct _stat32i64 *buf)
3251 int ret;
3252 struct _stat64 buf64;
3254 ret = _stat64(path, &buf64);
3255 if (!ret)
3256 msvcrt_stat64_to_stat32i64(&buf64, buf);
3257 return ret;
3260 /*********************************************************************
3261 * _stat64i32 (MSVCR80.@)
3263 int CDECL _stat64i32(const char* path, struct _stat64i32 *buf)
3265 int ret;
3266 struct _stat64 buf64;
3268 ret = _stat64(path, &buf64);
3269 if (!ret)
3270 msvcrt_stat64_to_stat64i32(&buf64, buf);
3271 return ret;
3274 #endif /* _MSVCR_VER >= 80 */
3276 /*********************************************************************
3277 * _wstat64 (MSVCRT.@)
3279 int CDECL _wstat64(const wchar_t* path, struct _stat64 * buf)
3281 DWORD dw;
3282 WIN32_FILE_ATTRIBUTE_DATA hfi;
3283 unsigned short mode = ALL_S_IREAD;
3284 int plen;
3286 TRACE(":file (%s) buf(%p)\n", debugstr_w(path), buf);
3288 plen = wcslen(path);
3289 while (plen && path[plen-1]==' ')
3290 plen--;
3292 if (plen==2 && path[1]==':')
3294 *_errno() = ENOENT;
3295 return -1;
3298 #if _MSVCR_VER<140
3299 if (plen>=2 && path[plen-2]!=':' && (path[plen-1]=='\\' || path[plen-1]=='/'))
3301 *_errno() = ENOENT;
3302 return -1;
3304 #endif
3306 if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
3308 TRACE("failed (%ld)\n", GetLastError());
3309 *_errno() = ENOENT;
3310 return -1;
3313 memset(buf,0,sizeof(struct _stat64));
3315 /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
3316 if (iswalpha(*path) && path[1] == ':')
3317 buf->st_dev = buf->st_rdev = towupper(*path) - 'A'; /* drive num */
3318 else
3319 buf->st_dev = buf->st_rdev = _getdrive() - 1;
3321 /* Dir, or regular file? */
3322 if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3323 mode |= (_S_IFDIR | ALL_S_IEXEC);
3324 else
3326 mode |= _S_IFREG;
3327 /* executable? */
3328 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
3330 ULONGLONG ext = towlower(path[plen-1]) | (towlower(path[plen-2]) << 16) |
3331 ((ULONGLONG)towlower(path[plen-3]) << 32);
3332 if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
3333 mode |= ALL_S_IEXEC;
3337 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
3338 mode |= ALL_S_IWRITE;
3340 buf->st_mode = mode;
3341 buf->st_nlink = 1;
3342 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
3343 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
3344 buf->st_atime = dw;
3345 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
3346 buf->st_mtime = buf->st_ctime = dw;
3347 TRACE("%d %d %#I64x %I64d %I64d %I64d\n", buf->st_mode, buf->st_nlink,
3348 buf->st_size, buf->st_atime, buf->st_mtime, buf->st_ctime);
3349 return 0;
3352 /*********************************************************************
3353 * _wstati64 (MSVCRT.@)
3355 int CDECL _wstati64(const wchar_t* path, struct _stati64 * buf)
3357 int ret;
3358 struct _stat64 buf64;
3360 ret = _wstat64(path, &buf64);
3361 if (!ret)
3362 msvcrt_stat64_to_stati64(&buf64, buf);
3363 return ret;
3366 /*********************************************************************
3367 * _wstat (MSVCRT.@)
3369 int CDECL _wstat(const wchar_t* path, struct _stat * buf)
3371 int ret;
3372 struct _stat64 buf64;
3374 ret = _wstat64( path, &buf64 );
3375 if (!ret) msvcrt_stat64_to_stat(&buf64, buf);
3376 return ret;
3379 #if _MSVCR_VER >= 80
3381 /*********************************************************************
3382 * _wstat32 (MSVCR80.@)
3384 int CDECL _wstat32(const wchar_t *path, struct _stat32 *buf)
3386 int ret;
3387 struct _stat64 buf64;
3389 ret = _wstat64(path, &buf64);
3390 if (!ret)
3391 msvcrt_stat64_to_stat32(&buf64, buf);
3392 return ret;
3395 /*********************************************************************
3396 * _wstat32i64 (MSVCR80.@)
3398 int CDECL _wstat32i64(const wchar_t *path, struct _stat32i64 *buf)
3400 int ret;
3401 struct _stat64 buf64;
3403 ret = _wstat64(path, &buf64);
3404 if (!ret)
3405 msvcrt_stat64_to_stat32i64(&buf64, buf);
3406 return ret;
3409 /*********************************************************************
3410 * _wstat64i32 (MSVCR80.@)
3412 int CDECL _wstat64i32(const wchar_t *path, struct _stat64i32 *buf)
3414 int ret;
3415 struct _stat64 buf64;
3417 ret = _wstat64(path, &buf64);
3418 if (!ret)
3419 msvcrt_stat64_to_stat64i32(&buf64, buf);
3420 return ret;
3423 #endif /* _MSVCR_VER >= 80 */
3425 /*********************************************************************
3426 * _tell (MSVCRT.@)
3428 __msvcrt_long CDECL _tell(int fd)
3430 return _lseek(fd, 0, SEEK_CUR);
3433 /*********************************************************************
3434 * _telli64 (MSVCRT.@)
3436 __int64 CDECL _telli64(int fd)
3438 return _lseeki64(fd, 0, SEEK_CUR);
3441 /*********************************************************************
3442 * _tempnam (MSVCRT.@)
3444 char * CDECL _tempnam(const char *dir, const char *prefix)
3446 char tmpbuf[MAX_PATH];
3447 const char *tmp_dir = getenv("TMP");
3449 if (tmp_dir) dir = tmp_dir;
3451 TRACE("dir (%s) prefix (%s)\n", dir, prefix);
3452 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
3454 TRACE("got name (%s)\n", tmpbuf);
3455 DeleteFileA(tmpbuf);
3456 return _strdup(tmpbuf);
3458 TRACE("failed (%ld)\n", GetLastError());
3459 return NULL;
3462 /*********************************************************************
3463 * _wtempnam (MSVCRT.@)
3465 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
3467 wchar_t tmpbuf[MAX_PATH];
3468 const wchar_t *tmp_dir = _wgetenv(L"TMP");
3470 if (tmp_dir) dir = tmp_dir;
3472 TRACE("dir (%s) prefix (%s)\n", debugstr_w(dir), debugstr_w(prefix));
3473 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
3475 TRACE("got name (%s)\n", debugstr_w(tmpbuf));
3476 DeleteFileW(tmpbuf);
3477 return _wcsdup(tmpbuf);
3479 TRACE("failed (%ld)\n", GetLastError());
3480 return NULL;
3483 /*********************************************************************
3484 * _umask (MSVCRT.@)
3486 int CDECL _umask(int umask)
3488 int old_umask = MSVCRT_umask;
3489 TRACE("(%d)\n",umask);
3490 MSVCRT_umask = umask;
3491 return old_umask;
3494 /*********************************************************************
3495 * _utime64 (MSVCRT.@)
3497 int CDECL _utime64(const char* path, struct __utimbuf64 *t)
3499 int fd = _open(path, _O_WRONLY | _O_BINARY);
3501 if (fd > 0)
3503 int retVal = _futime64(fd, t);
3504 _close(fd);
3505 return retVal;
3507 return -1;
3510 /*********************************************************************
3511 * _utime32 (MSVCRT.@)
3513 int CDECL _utime32(const char* path, struct __utimbuf32 *t)
3515 if (t)
3517 struct __utimbuf64 t64;
3518 t64.actime = t->actime;
3519 t64.modtime = t->modtime;
3520 return _utime64( path, &t64 );
3522 else
3523 return _utime64( path, NULL );
3526 /*********************************************************************
3527 * _wutime64 (MSVCRT.@)
3529 int CDECL _wutime64(const wchar_t* path, struct __utimbuf64 *t)
3531 int fd = _wopen(path, _O_WRONLY | _O_BINARY);
3533 if (fd > 0)
3535 int retVal = _futime64(fd, t);
3536 _close(fd);
3537 return retVal;
3539 return -1;
3542 /*********************************************************************
3543 * _wutime32 (MSVCRT.@)
3545 int CDECL _wutime32(const wchar_t* path, struct __utimbuf32 *t)
3547 if (t)
3549 struct __utimbuf64 t64;
3550 t64.actime = t->actime;
3551 t64.modtime = t->modtime;
3552 return _wutime64( path, &t64 );
3554 else
3555 return _wutime64( path, NULL );
3558 /*********************************************************************
3559 * _write (MSVCRT.@)
3561 int CDECL _write(int fd, const void* buf, unsigned int count)
3563 ioinfo *info = get_ioinfo(fd);
3564 HANDLE hand = info->handle;
3565 DWORD num_written, i;
3566 BOOL console = FALSE;
3568 if (hand == INVALID_HANDLE_VALUE || fd == MSVCRT_NO_CONSOLE_FD)
3570 *_errno() = EBADF;
3571 release_ioinfo(info);
3572 return -1;
3575 if (ioinfo_get_textmode(info) != TEXTMODE_ANSI && count&1)
3577 *_errno() = EINVAL;
3578 release_ioinfo(info);
3579 return -1;
3582 /* If appending, go to EOF */
3583 if (info->wxflag & WX_APPEND)
3584 _lseek(fd, 0, FILE_END);
3586 if (!(info->wxflag & WX_TEXT))
3588 if (!WriteFile(hand, buf, count, &num_written, NULL)
3589 || num_written != count)
3591 TRACE("WriteFile (fd %d, hand %p) failed-last error (%ld)\n", fd,
3592 hand, GetLastError());
3593 msvcrt_set_errno(GetLastError());
3594 if (GetLastError() == ERROR_ACCESS_DENIED)
3595 *_errno() = EBADF;
3596 num_written = -1;
3599 release_ioinfo(info);
3600 return num_written;
3603 if (_isatty(fd)) console = VerifyConsoleIoHandle(hand);
3604 for (i = 0; i < count;)
3606 const char *s = buf;
3607 char lfbuf[2048];
3608 DWORD j = 0;
3610 if (ioinfo_get_textmode(info) == TEXTMODE_ANSI && console)
3612 char conv[sizeof(lfbuf)];
3613 size_t len = 0;
3615 #if _MSVCR_VER >= 80
3616 if (info->dbcsBufferUsed)
3618 conv[j++] = info->dbcsBuffer[0];
3619 info->dbcsBufferUsed = FALSE;
3620 conv[j++] = s[i++];
3621 len++;
3623 #endif
3625 for (; i < count && j < sizeof(conv)-1 &&
3626 len < (sizeof(lfbuf) - 1) / sizeof(WCHAR); i++, j++, len++)
3628 if (isleadbyte((unsigned char)s[i]))
3630 conv[j++] = s[i++];
3632 if (i == count)
3634 #if _MSVCR_VER >= 80
3635 info->dbcsBuffer[0] = conv[j-1];
3636 info->dbcsBufferUsed = TRUE;
3637 break;
3638 #else
3639 *_errno() = EINVAL;
3640 release_ioinfo(info);
3641 return -1;
3642 #endif
3645 else if (s[i] == '\n')
3647 conv[j++] = '\r';
3648 len++;
3650 conv[j] = s[i];
3653 len = mbstowcs((WCHAR*)lfbuf, conv, len);
3654 if (len == -1)
3656 msvcrt_set_errno(GetLastError());
3657 release_ioinfo(info);
3658 return -1;
3660 j = len * 2;
3662 else if (ioinfo_get_textmode(info) == TEXTMODE_ANSI)
3664 for (j = 0; i < count && j < sizeof(lfbuf)-1; i++, j++)
3666 if (s[i] == '\n')
3667 lfbuf[j++] = '\r';
3668 lfbuf[j] = s[i];
3671 else if (ioinfo_get_textmode(info) == TEXTMODE_UTF16LE || console)
3673 for (j = 0; i < count && j < sizeof(lfbuf)-3; i++, j++)
3675 if (s[i] == '\n' && !s[i+1])
3677 lfbuf[j++] = '\r';
3678 lfbuf[j++] = 0;
3680 lfbuf[j++] = s[i++];
3681 lfbuf[j] = s[i];
3684 else
3686 char conv[sizeof(lfbuf)/4];
3688 for (j = 0; i < count && j < sizeof(conv)-3; i++, j++)
3690 if (s[i] == '\n' && !s[i+1])
3692 conv[j++] = '\r';
3693 conv[j++] = 0;
3695 conv[j++] = s[i++];
3696 conv[j] = s[i];
3699 j = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)conv, j/2, lfbuf, sizeof(lfbuf), NULL, NULL);
3700 if (!j)
3702 msvcrt_set_errno(GetLastError());
3703 release_ioinfo(info);
3704 return -1;
3708 if (console)
3710 j = j/2;
3711 if (!WriteConsoleW(hand, lfbuf, j, &num_written, NULL))
3712 num_written = -1;
3714 else if (!WriteFile(hand, lfbuf, j, &num_written, NULL))
3716 num_written = -1;
3719 if (num_written != j)
3721 TRACE("WriteFile/WriteConsoleW (fd %d, hand %p) failed-last error (%ld)\n", fd,
3722 hand, GetLastError());
3723 msvcrt_set_errno(GetLastError());
3724 if (GetLastError() == ERROR_ACCESS_DENIED)
3725 *_errno() = EBADF;
3726 release_ioinfo(info);
3727 return -1;
3731 release_ioinfo(info);
3732 return count;
3735 /*********************************************************************
3736 * _putw (MSVCRT.@)
3738 int CDECL _putw(int val, FILE* file)
3740 int len;
3742 _lock_file(file);
3743 len = _write(file->_file, &val, sizeof(val));
3744 if (len == sizeof(val)) {
3745 _unlock_file(file);
3746 return val;
3749 file->_flag |= _IOERR;
3750 _unlock_file(file);
3751 return EOF;
3754 /*********************************************************************
3755 * fclose (MSVCRT.@)
3757 int CDECL fclose(FILE* file)
3759 int ret;
3761 if (!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3763 _lock_file(file);
3764 ret = _fclose_nolock(file);
3765 _unlock_file(file);
3767 return ret;
3770 /*********************************************************************
3771 * _fclose_nolock (MSVCRT.@)
3773 int CDECL _fclose_nolock(FILE* file)
3775 int r, flag;
3777 if (!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3779 if(!(file->_flag & (_IOREAD | _IOWRT | _IORW)))
3781 file->_flag = 0;
3782 return EOF;
3785 flag = file->_flag;
3786 free(file->_tmpfname);
3787 file->_tmpfname = NULL;
3788 /* flush stdio buffers */
3789 if(file->_flag & _IOWRT)
3790 _fflush_nolock(file);
3791 if(file->_flag & _IOMYBUF)
3792 free(file->_base);
3794 r=_close(file->_file);
3795 file->_flag = 0;
3797 return ((r == -1) || (flag & _IOERR) ? EOF : 0);
3800 /*********************************************************************
3801 * feof (MSVCRT.@)
3803 int CDECL feof(FILE* file)
3805 return file->_flag & _IOEOF;
3808 /*********************************************************************
3809 * ferror (MSVCRT.@)
3811 int CDECL ferror(FILE* file)
3813 return file->_flag & _IOERR;
3816 /*********************************************************************
3817 * _filbuf (MSVCRT.@)
3819 int CDECL _filbuf(FILE* file)
3821 unsigned char c;
3823 if(file->_flag & _IOSTRG)
3824 return EOF;
3826 /* Allocate buffer if needed */
3827 if(!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF)))
3828 msvcrt_alloc_buffer(file);
3830 if(!(file->_flag & _IOREAD)) {
3831 if(file->_flag & _IORW)
3832 file->_flag |= _IOREAD;
3833 else
3834 return EOF;
3837 if(!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF))) {
3838 int r;
3839 if ((r = _read(file->_file,&c,1)) != 1) {
3840 file->_flag |= (r == 0) ? _IOEOF : _IOERR;
3841 return EOF;
3844 return c;
3845 } else {
3846 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
3847 if(file->_cnt<=0) {
3848 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
3849 file->_cnt = 0;
3850 return EOF;
3853 file->_cnt--;
3854 file->_ptr = file->_base+1;
3855 c = *(unsigned char *)file->_base;
3856 return c;
3860 /*********************************************************************
3861 * fgetc (MSVCRT.@)
3863 int CDECL fgetc(FILE* file)
3865 int ret;
3867 _lock_file(file);
3868 ret = _fgetc_nolock(file);
3869 _unlock_file(file);
3871 return ret;
3874 /*********************************************************************
3875 * _fgetc_nolock (MSVCRT.@)
3877 int CDECL _fgetc_nolock(FILE* file)
3879 unsigned char *i;
3880 unsigned int j;
3882 if (file->_cnt>0) {
3883 file->_cnt--;
3884 i = (unsigned char *)file->_ptr++;
3885 j = *i;
3886 } else
3887 j = _filbuf(file);
3889 return j;
3892 /*********************************************************************
3893 * _fgetchar (MSVCRT.@)
3895 int CDECL _fgetchar(void)
3897 return fgetc(MSVCRT_stdin);
3900 /*********************************************************************
3901 * fgets (MSVCRT.@)
3903 char * CDECL fgets(char *s, int size, FILE* file)
3905 int cc = EOF;
3906 char * buf_start = s;
3908 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3909 file,file->_file,s,size);
3911 _lock_file(file);
3913 while ((size >1) && (cc = _fgetc_nolock(file)) != EOF && cc != '\n')
3915 *s++ = (char)cc;
3916 size --;
3918 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
3920 TRACE(":nothing read\n");
3921 _unlock_file(file);
3922 return NULL;
3924 if ((cc != EOF) && (size > 1))
3925 *s++ = cc;
3926 *s = '\0';
3927 TRACE(":got %s\n", debugstr_a(buf_start));
3928 _unlock_file(file);
3929 return buf_start;
3932 /*********************************************************************
3933 * fgetwc (MSVCRT.@)
3935 wint_t CDECL fgetwc(FILE* file)
3937 wint_t ret;
3939 _lock_file(file);
3940 ret = _fgetwc_nolock(file);
3941 _unlock_file(file);
3943 return ret;
3946 /*********************************************************************
3947 * _fgetwc_nolock (MSVCRT.@)
3949 wint_t CDECL _fgetwc_nolock(FILE* file)
3951 wint_t ret;
3952 int ch;
3954 if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI
3955 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3956 char *p;
3958 for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
3959 ch = _fgetc_nolock(file);
3960 if(ch == EOF) {
3961 ret = WEOF;
3962 break;
3964 *p = (char)ch;
3966 }else {
3967 char mbs[MB_LEN_MAX];
3968 int len = 0;
3970 ch = _fgetc_nolock(file);
3971 if(ch != EOF) {
3972 mbs[0] = (char)ch;
3973 if(isleadbyte((unsigned char)mbs[0])) {
3974 ch = _fgetc_nolock(file);
3975 if(ch != EOF) {
3976 mbs[1] = (char)ch;
3977 len = 2;
3979 }else {
3980 len = 1;
3984 if(!len || mbtowc(&ret, mbs, len)==-1)
3985 ret = WEOF;
3988 return ret;
3991 /*********************************************************************
3992 * _getw (MSVCRT.@)
3994 int CDECL _getw(FILE* file)
3996 char *ch;
3997 int i, k;
3998 unsigned int j;
3999 ch = (char *)&i;
4001 _lock_file(file);
4002 for (j=0; j<sizeof(int); j++) {
4003 k = _fgetc_nolock(file);
4004 if (k == EOF) {
4005 file->_flag |= _IOEOF;
4006 _unlock_file(file);
4007 return EOF;
4009 ch[j] = k;
4012 _unlock_file(file);
4013 return i;
4016 /*********************************************************************
4017 * getwc (MSVCRT.@)
4019 wint_t CDECL getwc(FILE* file)
4021 return fgetwc(file);
4024 /*********************************************************************
4025 * _fgetwchar (MSVCRT.@)
4027 wint_t CDECL _fgetwchar(void)
4029 return fgetwc(MSVCRT_stdin);
4032 /*********************************************************************
4033 * getwchar (MSVCRT.@)
4035 wint_t CDECL getwchar(void)
4037 return _fgetwchar();
4040 /*********************************************************************
4041 * fgetws (MSVCRT.@)
4043 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
4045 wint_t cc = WEOF;
4046 wchar_t * buf_start = s;
4048 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
4049 file,file->_file,s,size);
4051 _lock_file(file);
4053 while ((size >1) && (cc = _fgetwc_nolock(file)) != WEOF && cc != '\n')
4055 *s++ = cc;
4056 size --;
4058 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
4060 TRACE(":nothing read\n");
4061 _unlock_file(file);
4062 return NULL;
4064 if ((cc != WEOF) && (size > 1))
4065 *s++ = cc;
4066 *s = 0;
4067 TRACE(":got %s\n", debugstr_w(buf_start));
4068 _unlock_file(file);
4069 return buf_start;
4072 /*********************************************************************
4073 * _flsbuf (MSVCRT.@)
4075 int CDECL _flsbuf(int c, FILE* file)
4077 /* Flush output buffer */
4078 if(!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF))) {
4079 msvcrt_alloc_buffer(file);
4082 if(!(file->_flag & _IOWRT)) {
4083 if(!(file->_flag & _IORW)) {
4084 file->_flag |= _IOERR;
4085 *_errno() = EBADF;
4086 return EOF;
4088 file->_flag |= _IOWRT;
4090 if(file->_flag & _IOREAD) {
4091 if(!(file->_flag & _IOEOF)) {
4092 file->_flag |= _IOERR;
4093 return EOF;
4095 file->_cnt = 0;
4096 file->_ptr = file->_base;
4097 file->_flag &= ~(_IOREAD | _IOEOF);
4100 if(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) {
4101 int res = 0;
4103 if(file->_cnt <= 0) {
4104 res = msvcrt_flush_buffer(file);
4105 if(res)
4106 return res;
4107 file->_flag |= _IOWRT;
4108 file->_cnt=file->_bufsiz;
4110 *file->_ptr++ = c;
4111 file->_cnt--;
4112 return c&0xff;
4113 } else {
4114 unsigned char cc=c;
4115 int len;
4116 /* set _cnt to 0 for unbuffered FILEs */
4117 file->_cnt = 0;
4118 len = _write(file->_file, &cc, 1);
4119 if (len == 1)
4120 return c & 0xff;
4121 file->_flag |= _IOERR;
4122 return EOF;
4126 /*********************************************************************
4127 * fwrite (MSVCRT.@)
4129 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
4131 size_t ret;
4133 _lock_file(file);
4134 ret = _fwrite_nolock(ptr, size, nmemb, file);
4135 _unlock_file(file);
4137 return ret;
4140 /*********************************************************************
4141 * _fwrite_nolock (MSVCRT.@)
4143 size_t CDECL _fwrite_nolock(const void *ptr, size_t size, size_t nmemb, FILE* file)
4145 size_t wrcnt=size * nmemb;
4146 int written = 0;
4147 if (size == 0)
4148 return 0;
4150 while(wrcnt) {
4151 if(file->_cnt < 0) {
4152 WARN("negative file->_cnt value in %p\n", file);
4153 file->_flag |= _IOERR;
4154 break;
4155 } else if(file->_cnt) {
4156 int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
4157 memcpy(file->_ptr, ptr, pcnt);
4158 file->_cnt -= pcnt;
4159 file->_ptr += pcnt;
4160 written += pcnt;
4161 wrcnt -= pcnt;
4162 ptr = (const char*)ptr + pcnt;
4163 } else if((file->_flag & _IONBF)
4164 || ((file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) && wrcnt >= file->_bufsiz)
4165 || (!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
4166 size_t pcnt;
4167 int bufsiz;
4169 if(file->_flag & _IONBF)
4170 bufsiz = 1;
4171 else if(!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)))
4172 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
4173 else
4174 bufsiz = file->_bufsiz;
4176 pcnt = (wrcnt / bufsiz) * bufsiz;
4178 if(msvcrt_flush_buffer(file) == EOF)
4179 break;
4181 if(_write(file->_file, ptr, pcnt) <= 0) {
4182 file->_flag |= _IOERR;
4183 break;
4185 written += pcnt;
4186 wrcnt -= pcnt;
4187 ptr = (const char*)ptr + pcnt;
4188 } else {
4189 if(_flsbuf(*(const char*)ptr, file) == EOF)
4190 break;
4191 written++;
4192 wrcnt--;
4193 ptr = (const char*)ptr + 1;
4197 return written / size;
4200 /*********************************************************************
4201 * fputwc (MSVCRT.@)
4203 wint_t CDECL fputwc(wint_t wc, FILE* file)
4205 wint_t ret;
4207 _lock_file(file);
4208 ret = _fputwc_nolock(wc, file);
4209 _unlock_file(file);
4211 return ret;
4214 /*********************************************************************
4215 * _fputwc_nolock (MSVCRT.@)
4217 wint_t CDECL _fputwc_nolock(wint_t wc, FILE* file)
4219 wchar_t mwc=wc;
4220 ioinfo *fdinfo;
4221 wint_t ret;
4223 fdinfo = get_ioinfo_nolock(file->_file);
4225 if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_ANSI) {
4226 char buf[MB_LEN_MAX];
4227 int char_len;
4229 char_len = wctomb(buf, mwc);
4230 if(char_len!=-1 && _fwrite_nolock(buf, char_len, 1, file)==1)
4231 ret = wc;
4232 else
4233 ret = WEOF;
4234 }else if(_fwrite_nolock(&mwc, sizeof(mwc), 1, file) == 1) {
4235 ret = wc;
4236 }else {
4237 ret = WEOF;
4240 return ret;
4243 /*********************************************************************
4244 * _fputwchar (MSVCRT.@)
4246 wint_t CDECL _fputwchar(wint_t wc)
4248 return fputwc(wc, MSVCRT_stdout);
4251 /*********************************************************************
4252 * _wfsopen (MSVCRT.@)
4254 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
4256 FILE* file;
4257 int open_flags, stream_flags, fd;
4259 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
4261 /* map mode string to open() flags. "man fopen" for possibilities. */
4262 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
4263 return NULL;
4265 LOCK_FILES();
4266 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
4267 if (fd < 0)
4268 file = NULL;
4269 else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
4270 != -1)
4271 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
4272 else if (file)
4274 file->_flag = 0;
4275 file = NULL;
4278 TRACE(":got (%p)\n",file);
4279 if (fd >= 0 && !file)
4280 _close(fd);
4281 UNLOCK_FILES();
4282 return file;
4285 /*********************************************************************
4286 * _fsopen (MSVCRT.@)
4288 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
4290 FILE *ret;
4291 wchar_t *pathW = NULL, *modeW = NULL;
4293 if (path && !(pathW = msvcrt_wstrdupa(path))) {
4294 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4295 *_errno() = EINVAL;
4296 return NULL;
4298 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
4300 free(pathW);
4301 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4302 *_errno() = EINVAL;
4303 return NULL;
4306 ret = _wfsopen(pathW, modeW, share);
4308 free(pathW);
4309 free(modeW);
4310 return ret;
4313 /*********************************************************************
4314 * fopen (MSVCRT.@)
4316 FILE * CDECL fopen(const char *path, const char *mode)
4318 return _fsopen( path, mode, _SH_DENYNO );
4321 /*********************************************************************
4322 * fopen_s (MSVCRT.@)
4324 int CDECL fopen_s(FILE** pFile,
4325 const char *filename, const char *mode)
4327 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4328 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
4329 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4331 *pFile = fopen(filename, mode);
4333 if(!*pFile)
4334 return *_errno();
4335 return 0;
4338 /*********************************************************************
4339 * _wfopen (MSVCRT.@)
4341 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
4343 return _wfsopen( path, mode, _SH_DENYNO );
4346 /*********************************************************************
4347 * _wfopen_s (MSVCRT.@)
4349 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
4350 const wchar_t *mode)
4352 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4353 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
4354 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4356 *pFile = _wfopen(filename, mode);
4358 if(!*pFile)
4359 return *_errno();
4360 return 0;
4363 /*********************************************************************
4364 * fputc (MSVCRT.@)
4366 int CDECL fputc(int c, FILE* file)
4368 int ret;
4370 _lock_file(file);
4371 ret = _fputc_nolock(c, file);
4372 _unlock_file(file);
4374 return ret;
4377 /*********************************************************************
4378 * _fputc_nolock (MSVCRT.@)
4380 int CDECL _fputc_nolock(int c, FILE* file)
4382 int res;
4384 if(file->_cnt>0) {
4385 *file->_ptr++=c;
4386 file->_cnt--;
4387 if (c == '\n')
4389 res = msvcrt_flush_buffer(file);
4390 return res ? res : c;
4392 else {
4393 return c & 0xff;
4395 } else {
4396 res = _flsbuf(c, file);
4397 return res;
4401 /*********************************************************************
4402 * _fputchar (MSVCRT.@)
4404 int CDECL _fputchar(int c)
4406 return fputc(c, MSVCRT_stdout);
4409 /*********************************************************************
4410 * fread (MSVCRT.@)
4412 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
4414 size_t ret;
4416 _lock_file(file);
4417 ret = _fread_nolock(ptr, size, nmemb, file);
4418 _unlock_file(file);
4420 return ret;
4423 /*********************************************************************
4424 * _fread_nolock (MSVCRT.@)
4426 size_t CDECL _fread_nolock(void *ptr, size_t size, size_t nmemb, FILE* file)
4428 size_t rcnt=size * nmemb;
4429 size_t read=0;
4430 size_t pread=0;
4432 if(!rcnt)
4433 return 0;
4435 /* first buffered data */
4436 if(file->_cnt>0) {
4437 int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
4438 memcpy(ptr, file->_ptr, pcnt);
4439 file->_cnt -= pcnt;
4440 file->_ptr += pcnt;
4441 read += pcnt ;
4442 rcnt -= pcnt ;
4443 ptr = (char*)ptr + pcnt;
4444 } else if(!(file->_flag & _IOREAD )) {
4445 if(file->_flag & _IORW) {
4446 file->_flag |= _IOREAD;
4447 } else {
4448 return 0;
4452 if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF)))
4453 msvcrt_alloc_buffer(file);
4455 while(rcnt>0)
4457 int i;
4458 if (!file->_cnt && rcnt<file->_bufsiz && (file->_flag & (_IOMYBUF | MSVCRT__USERBUF))) {
4459 i = _read(file->_file, file->_base, file->_bufsiz);
4460 file->_ptr = file->_base;
4461 if (i != -1) {
4462 file->_cnt = i;
4463 if (i > rcnt) i = rcnt;
4465 /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
4466 if (i > 0 && i < file->_cnt) {
4467 get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF;
4468 file->_flag &= ~_IOEOF;
4470 if (i > 0) {
4471 memcpy(ptr, file->_ptr, i);
4472 file->_cnt -= i;
4473 file->_ptr += i;
4475 } else if (rcnt > INT_MAX) {
4476 i = _read(file->_file, ptr, INT_MAX);
4477 } else if (rcnt < (file->_bufsiz ? file->_bufsiz : MSVCRT_INTERNAL_BUFSIZ)) {
4478 i = _read(file->_file, ptr, rcnt);
4479 } else {
4480 i = _read(file->_file, ptr, rcnt - rcnt % (file->_bufsiz ? file->_bufsiz : MSVCRT_INTERNAL_BUFSIZ));
4482 pread += i;
4483 rcnt -= i;
4484 ptr = (char *)ptr+i;
4485 /* expose feof condition in the flags
4486 * MFC tests file->_flag for feof, and doesn't call feof())
4488 if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF)
4489 file->_flag |= _IOEOF;
4490 else if (i == -1)
4492 file->_flag |= _IOERR;
4493 pread = 0;
4494 rcnt = 0;
4496 if (i < 1) break;
4498 read+=pread;
4499 return read / size;
4502 #if _MSVCR_VER >= 80
4504 /*********************************************************************
4505 * fread_s (MSVCR80.@)
4507 size_t CDECL fread_s(void *buf, size_t buf_size, size_t elem_size,
4508 size_t count, FILE *stream)
4510 size_t ret;
4512 if(!MSVCRT_CHECK_PMT(stream != NULL)) {
4513 if(buf && buf_size)
4514 memset(buf, 0, buf_size);
4515 return 0;
4517 if(!elem_size || !count) return 0;
4519 _lock_file(stream);
4520 ret = _fread_nolock_s(buf, buf_size, elem_size, count, stream);
4521 _unlock_file(stream);
4523 return ret;
4526 /*********************************************************************
4527 * _fread_nolock_s (MSVCR80.@)
4529 size_t CDECL _fread_nolock_s(void *buf, size_t buf_size, size_t elem_size,
4530 size_t count, FILE *stream)
4532 size_t bytes_left, buf_pos;
4534 TRACE("(%p %Iu %Iu %Iu %p)\n", buf, buf_size, elem_size, count, stream);
4536 if(!MSVCRT_CHECK_PMT(stream != NULL)) {
4537 if(buf && buf_size)
4538 memset(buf, 0, buf_size);
4539 return 0;
4541 if(!elem_size || !count) return 0;
4542 if(!MSVCRT_CHECK_PMT(buf != NULL)) return 0;
4543 if(!MSVCRT_CHECK_PMT(SIZE_MAX/count >= elem_size)) return 0;
4545 bytes_left = elem_size*count;
4546 buf_pos = 0;
4547 while(bytes_left) {
4548 if(stream->_cnt > 0) {
4549 size_t size = bytes_left<stream->_cnt ? bytes_left : stream->_cnt;
4551 if(!MSVCRT_CHECK_PMT_ERR(size <= buf_size-buf_pos, ERANGE)) {
4552 memset(buf, 0, buf_size);
4553 return 0;
4556 _fread_nolock((char*)buf+buf_pos, 1, size, stream);
4557 buf_pos += size;
4558 bytes_left -= size;
4559 }else {
4560 int c = _filbuf(stream);
4562 if(c == EOF)
4563 break;
4565 if(!MSVCRT_CHECK_PMT_ERR(buf_size != buf_pos, ERANGE)) {
4566 memset(buf, 0, buf_size);
4567 return 0;
4570 ((char*)buf)[buf_pos++] = c;
4571 bytes_left--;
4575 return buf_pos/elem_size;
4578 #endif /* _MSVCR_VER >= 80 */
4580 /*********************************************************************
4581 * _wfreopen (MSVCRT.@)
4584 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
4586 int open_flags, stream_flags, fd;
4588 TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
4590 LOCK_FILES();
4591 if (file)
4593 fclose(file);
4594 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
4595 file = NULL;
4596 else if((fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE)) < 0)
4597 file = NULL;
4598 else if(msvcrt_init_fp(file, fd, stream_flags) == -1)
4600 file->_flag = 0;
4601 file = NULL;
4604 UNLOCK_FILES();
4605 return file;
4608 /*********************************************************************
4609 * _wfreopen_s (MSVCRT.@)
4611 int CDECL _wfreopen_s(FILE** pFile,
4612 const wchar_t *path, const wchar_t *mode, FILE* file)
4614 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4615 if (!MSVCRT_CHECK_PMT(path != NULL)) return EINVAL;
4616 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4617 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
4619 *pFile = _wfreopen(path, mode, file);
4621 if(!*pFile)
4622 return *_errno();
4623 return 0;
4626 /*********************************************************************
4627 * freopen (MSVCRT.@)
4630 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
4632 FILE *ret;
4633 wchar_t *pathW = NULL, *modeW = NULL;
4635 if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
4636 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
4638 free(pathW);
4639 return NULL;
4642 ret = _wfreopen(pathW, modeW, file);
4644 free(pathW);
4645 free(modeW);
4646 return ret;
4649 /*********************************************************************
4650 * freopen_s (MSVCRT.@)
4652 errno_t CDECL freopen_s(FILE** pFile,
4653 const char *path, const char *mode, FILE* file)
4655 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4656 if (!MSVCRT_CHECK_PMT(path != NULL)) return EINVAL;
4657 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4658 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
4660 *pFile = freopen(path, mode, file);
4662 if(!*pFile)
4663 return *_errno();
4664 return 0;
4667 /*********************************************************************
4668 * fsetpos (MSVCRT.@)
4670 int CDECL fsetpos(FILE* file, fpos_t *pos)
4672 int ret;
4674 _lock_file(file);
4675 msvcrt_flush_buffer(file);
4677 /* Reset direction of i/o */
4678 if(file->_flag & _IORW) {
4679 file->_flag &= ~(_IOREAD|_IOWRT);
4682 ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
4683 _unlock_file(file);
4684 return ret;
4687 /*********************************************************************
4688 * _ftelli64 (MSVCRT.@)
4690 __int64 CDECL _ftelli64(FILE* file)
4692 __int64 ret;
4694 _lock_file(file);
4695 ret = _ftelli64_nolock(file);
4696 _unlock_file(file);
4698 return ret;
4701 /*********************************************************************
4702 * _ftelli64_nolock (MSVCRT.@)
4704 __int64 CDECL _ftelli64_nolock(FILE* file)
4706 __int64 pos;
4708 pos = _telli64(file->_file);
4709 if(pos == -1)
4710 return -1;
4711 if(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) {
4712 if(file->_flag & _IOWRT) {
4713 pos += file->_ptr - file->_base;
4715 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4716 char *p;
4718 for(p=file->_base; p<file->_ptr; p++)
4719 if(*p == '\n')
4720 pos++;
4722 } else if(!file->_cnt) { /* nothing to do */
4723 } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
4724 int i;
4726 pos -= file->_cnt;
4727 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4728 for(i=0; i<file->_cnt; i++)
4729 if(file->_ptr[i] == '\n')
4730 pos--;
4732 } else {
4733 char *p;
4735 if(_lseeki64(file->_file, pos, SEEK_SET) != pos)
4736 return -1;
4738 pos -= file->_bufsiz;
4739 pos += file->_ptr - file->_base;
4741 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4742 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL)
4743 pos--;
4745 for(p=file->_base; p<file->_ptr; p++)
4746 if(*p == '\n')
4747 pos++;
4752 return pos;
4755 /*********************************************************************
4756 * ftell (MSVCRT.@)
4758 __msvcrt_long CDECL ftell(FILE* file)
4760 return _ftelli64(file);
4763 #if _MSVCR_VER >= 80
4764 /*********************************************************************
4765 * _ftell_nolock (MSVCR80.@)
4767 __msvcrt_long CDECL _ftell_nolock(FILE* file)
4769 return _ftelli64_nolock(file);
4771 #endif
4773 /*********************************************************************
4774 * fgetpos (MSVCRT.@)
4776 int CDECL fgetpos(FILE* file, fpos_t *pos)
4778 *pos = _ftelli64(file);
4779 if(*pos == -1)
4780 return -1;
4781 return 0;
4784 /*********************************************************************
4785 * fputs (MSVCRT.@)
4787 int CDECL fputs(const char *s, FILE* file)
4789 size_t len = strlen(s);
4790 int ret;
4792 _lock_file(file);
4793 ret = _fwrite_nolock(s, sizeof(*s), len, file) == len ? 0 : EOF;
4794 _unlock_file(file);
4795 return ret;
4798 /*********************************************************************
4799 * fputws (MSVCRT.@)
4801 int CDECL fputws(const wchar_t *s, FILE* file)
4803 size_t i, len = wcslen(s);
4804 BOOL tmp_buf;
4805 int ret;
4807 _lock_file(file);
4808 if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
4809 ret = _fwrite_nolock(s,sizeof(*s),len,file) == len ? 0 : EOF;
4810 _unlock_file(file);
4811 return ret;
4814 tmp_buf = add_std_buffer(file);
4815 for (i=0; i<len; i++) {
4816 if(_fputwc_nolock(s[i], file) == WEOF) {
4817 if(tmp_buf) remove_std_buffer(file);
4818 _unlock_file(file);
4819 return WEOF;
4823 if(tmp_buf) remove_std_buffer(file);
4824 _unlock_file(file);
4825 return 0;
4828 /*********************************************************************
4829 * getchar (MSVCRT.@)
4831 int CDECL getchar(void)
4833 return fgetc(MSVCRT_stdin);
4836 /*********************************************************************
4837 * getc (MSVCRT.@)
4839 int CDECL getc(FILE* file)
4841 return fgetc(file);
4844 /*********************************************************************
4845 * gets_s (MSVCR80.@)
4847 char * CDECL gets_s(char *buf, size_t len)
4849 char *buf_start = buf;
4850 int cc;
4852 if (!MSVCRT_CHECK_PMT(buf != NULL)) return NULL;
4853 if (!MSVCRT_CHECK_PMT(len != 0)) return NULL;
4855 _lock_file(MSVCRT_stdin);
4856 for(cc = _fgetc_nolock(MSVCRT_stdin);
4857 len != 0 && cc != EOF && cc != '\n';
4858 cc = _fgetc_nolock(MSVCRT_stdin))
4860 if (cc != '\r')
4862 *buf++ = (char)cc;
4863 len--;
4866 _unlock_file(MSVCRT_stdin);
4868 if (!len)
4870 *buf_start = 0;
4871 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4872 return NULL;
4875 if ((cc == EOF) && (buf_start == buf))
4877 TRACE(":nothing read\n");
4878 return NULL;
4880 *buf = '\0';
4882 TRACE("got '%s'\n", buf_start);
4883 return buf_start;
4886 /*********************************************************************
4887 * gets (MSVCRT.@)
4889 char * CDECL gets(char *buf)
4891 return gets_s(buf, -1);
4894 /*********************************************************************
4895 * _getws (MSVCRT.@)
4897 wchar_t* CDECL _getws(wchar_t* buf)
4899 wint_t cc;
4900 wchar_t* ws = buf;
4902 _lock_file(MSVCRT_stdin);
4903 for (cc = _fgetwc_nolock(MSVCRT_stdin); cc != WEOF && cc != '\n';
4904 cc = _fgetwc_nolock(MSVCRT_stdin))
4906 if (cc != '\r')
4907 *buf++ = (wchar_t)cc;
4909 _unlock_file(MSVCRT_stdin);
4911 if ((cc == WEOF) && (ws == buf))
4913 TRACE(":nothing read\n");
4914 return NULL;
4916 *buf = '\0';
4918 TRACE("got %s\n", debugstr_w(ws));
4919 return ws;
4922 /*********************************************************************
4923 * putc (MSVCRT.@)
4925 int CDECL putc(int c, FILE* file)
4927 return fputc(c, file);
4930 /*********************************************************************
4931 * putchar (MSVCRT.@)
4933 int CDECL putchar(int c)
4935 return fputc(c, MSVCRT_stdout);
4938 /*********************************************************************
4939 * puts (MSVCRT.@)
4941 int CDECL puts(const char *s)
4943 size_t len = strlen(s);
4944 int ret;
4946 _lock_file(MSVCRT_stdout);
4947 if(_fwrite_nolock(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4948 _unlock_file(MSVCRT_stdout);
4949 return EOF;
4952 ret = _fwrite_nolock("\n",1,1,MSVCRT_stdout) == 1 ? 0 : EOF;
4953 _unlock_file(MSVCRT_stdout);
4954 return ret;
4957 /*********************************************************************
4958 * _putws (MSVCRT.@)
4960 int CDECL _putws(const wchar_t *s)
4962 int ret;
4964 _lock_file(MSVCRT_stdout);
4965 ret = fputws(s, MSVCRT_stdout);
4966 if(ret >= 0)
4967 ret = _fputwc_nolock('\n', MSVCRT_stdout);
4968 _unlock_file(MSVCRT_stdout);
4969 return ret >= 0 ? 0 : WEOF;
4972 /*********************************************************************
4973 * remove (MSVCRT.@)
4975 int CDECL remove(const char *path)
4977 TRACE("(%s)\n", path);
4978 if (DeleteFileA(path))
4979 return 0;
4980 TRACE(":failed (%ld)\n", GetLastError());
4981 msvcrt_set_errno(GetLastError());
4982 return -1;
4985 /*********************************************************************
4986 * _wremove (MSVCRT.@)
4988 int CDECL _wremove(const wchar_t *path)
4990 TRACE("(%s)\n", debugstr_w(path));
4991 if (DeleteFileW(path))
4992 return 0;
4993 TRACE(":failed (%ld)\n", GetLastError());
4994 msvcrt_set_errno(GetLastError());
4995 return -1;
4998 /*********************************************************************
4999 * rename (MSVCRT.@)
5001 int CDECL rename(const char *oldpath,const char *newpath)
5003 TRACE(":from %s to %s\n", oldpath, newpath);
5004 if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
5005 return 0;
5006 TRACE(":failed (%ld)\n", GetLastError());
5007 msvcrt_set_errno(GetLastError());
5008 return -1;
5011 /*********************************************************************
5012 * _wrename (MSVCRT.@)
5014 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
5016 TRACE(":from %s to %s\n", debugstr_w(oldpath), debugstr_w(newpath));
5017 if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
5018 return 0;
5019 TRACE(":failed (%ld)\n", GetLastError());
5020 msvcrt_set_errno(GetLastError());
5021 return -1;
5024 /*********************************************************************
5025 * setvbuf (MSVCRT.@)
5027 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
5029 if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
5030 if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1;
5031 if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1;
5033 _lock_file(file);
5035 _fflush_nolock(file);
5036 if(file->_flag & _IOMYBUF)
5037 free(file->_base);
5038 file->_flag &= ~(_IONBF | _IOMYBUF | MSVCRT__USERBUF);
5039 file->_cnt = 0;
5041 if(mode == _IONBF) {
5042 file->_flag |= _IONBF;
5043 file->_base = file->_ptr = (char*)&file->_charbuf;
5044 file->_bufsiz = 2;
5045 }else if(buf) {
5046 file->_base = file->_ptr = buf;
5047 file->_flag |= MSVCRT__USERBUF;
5048 file->_bufsiz = size;
5049 }else {
5050 file->_base = file->_ptr = malloc(size);
5051 if(!file->_base) {
5052 file->_bufsiz = 0;
5053 _unlock_file(file);
5054 return -1;
5057 file->_flag |= _IOMYBUF;
5058 file->_bufsiz = size;
5060 _unlock_file(file);
5061 return 0;
5064 /*********************************************************************
5065 * setbuf (MSVCRT.@)
5067 void CDECL setbuf(FILE* file, char *buf)
5069 setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
5072 static int tmpnam_helper(char *s, size_t size, LONG *tmpnam_unique, int tmp_max)
5074 char tmpstr[8];
5075 char *p = s;
5076 int digits;
5078 if (!MSVCRT_CHECK_PMT(s != NULL)) return EINVAL;
5080 if (size < 3) {
5081 if (size) *s = 0;
5082 *_errno() = ERANGE;
5083 return ERANGE;
5085 *p++ = '\\';
5086 *p++ = 's';
5087 size -= 2;
5088 digits = msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
5089 if (digits+1 > size) {
5090 *s = 0;
5091 *_errno() = ERANGE;
5092 return ERANGE;
5094 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5095 p += digits;
5096 *p++ = '.';
5097 size -= digits+1;
5099 while(1) {
5100 while ((digits = *tmpnam_unique)+1 < tmp_max) {
5101 if (InterlockedCompareExchange(tmpnam_unique, digits+1, digits) == digits)
5102 break;
5105 digits = msvcrt_int_to_base32(digits, tmpstr);
5106 if (digits+1 > size) {
5107 *s = 0;
5108 *_errno() = ERANGE;
5109 return ERANGE;
5111 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5112 p[digits] = 0;
5114 if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
5115 GetLastError() == ERROR_FILE_NOT_FOUND)
5116 break;
5118 return 0;
5121 int CDECL tmpnam_s(char *s, size_t size)
5123 return tmpnam_helper(s, size, &tmpnam_s_unique, TMP_MAX_S);
5126 /*********************************************************************
5127 * tmpnam (MSVCRT.@)
5129 char * CDECL tmpnam(char *s)
5131 if (!s) {
5132 thread_data_t *data = msvcrt_get_thread_data();
5134 if(!data->tmpnam_buffer)
5135 data->tmpnam_buffer = malloc(MAX_PATH);
5137 s = data->tmpnam_buffer;
5140 return tmpnam_helper(s, -1, &tmpnam_unique, TMP_MAX) ? NULL : s;
5143 static int wtmpnam_helper(wchar_t *s, size_t size, LONG *tmpnam_unique, int tmp_max)
5145 wchar_t tmpstr[8];
5146 wchar_t *p = s;
5147 int digits;
5149 if (!MSVCRT_CHECK_PMT(s != NULL)) return EINVAL;
5151 if (size < 3) {
5152 if (size) *s = 0;
5153 *_errno() = ERANGE;
5154 return ERANGE;
5156 *p++ = '\\';
5157 *p++ = 's';
5158 size -= 2;
5159 digits = msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
5160 if (digits+1 > size) {
5161 *s = 0;
5162 *_errno() = ERANGE;
5163 return ERANGE;
5165 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5166 p += digits;
5167 *p++ = '.';
5168 size -= digits+1;
5170 while(1) {
5171 while ((digits = *tmpnam_unique)+1 < tmp_max) {
5172 if (InterlockedCompareExchange(tmpnam_unique, digits+1, digits) == digits)
5173 break;
5176 digits = msvcrt_int_to_base32_w(digits, tmpstr);
5177 if (digits+1 > size) {
5178 *s = 0;
5179 *_errno() = ERANGE;
5180 return ERANGE;
5182 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5183 p[digits] = 0;
5185 if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
5186 GetLastError() == ERROR_FILE_NOT_FOUND)
5187 break;
5189 return 0;
5192 /*********************************************************************
5193 * _wtmpnam_s (MSVCRT.@)
5195 int CDECL _wtmpnam_s(wchar_t *s, size_t size)
5197 return wtmpnam_helper(s, size, &tmpnam_s_unique, TMP_MAX_S);
5200 /*********************************************************************
5201 * _wtmpnam (MSVCRT.@)
5203 wchar_t * CDECL _wtmpnam(wchar_t *s)
5205 if (!s) {
5206 thread_data_t *data = msvcrt_get_thread_data();
5208 if(!data->wtmpnam_buffer)
5209 data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
5211 s = data->wtmpnam_buffer;
5214 return wtmpnam_helper(s, -1, &tmpnam_unique, TMP_MAX) ? NULL : s;
5217 /*********************************************************************
5218 * tmpfile (MSVCRT.@)
5220 FILE* CDECL tmpfile(void)
5222 char *filename = _tempnam(",", "t");
5223 int fd;
5224 FILE* file = NULL;
5226 LOCK_FILES();
5227 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
5228 _S_IREAD | _S_IWRITE);
5229 if (fd != -1 && (file = msvcrt_alloc_fp()))
5231 if (msvcrt_init_fp(file, fd, _IORW) == -1)
5233 file->_flag = 0;
5234 file = NULL;
5236 else file->_tmpfname = _strdup(filename);
5239 if(fd != -1 && !file)
5240 _close(fd);
5241 free(filename);
5242 UNLOCK_FILES();
5243 return file;
5246 /*********************************************************************
5247 * tmpfile_s (MSVCRT.@)
5249 int CDECL tmpfile_s(FILE** file)
5251 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
5253 *file = tmpfile();
5254 return 0;
5257 static int puts_clbk_file_a(void *file, int len, const char *str)
5259 return fwrite(str, sizeof(char), len, file);
5262 static int puts_clbk_file_w(void *file, int len, const wchar_t *str)
5264 int i, ret;
5266 _lock_file(file);
5268 if(!(get_ioinfo_nolock(((FILE*)file)->_file)->wxflag & WX_TEXT)) {
5269 ret = _fwrite_nolock(str, sizeof(wchar_t), len, file);
5270 _unlock_file(file);
5271 return ret;
5274 for(i=0; i<len; i++) {
5275 if(_fputwc_nolock(str[i], file) == WEOF) {
5276 _unlock_file(file);
5277 return -1;
5281 _unlock_file(file);
5282 return len;
5285 static int vfprintf_helper(DWORD options, FILE* file, const char *format,
5286 _locale_t locale, va_list valist)
5288 printf_arg args_ctx[_ARGMAX+1];
5289 BOOL tmp_buf;
5290 int ret;
5292 if(!MSVCRT_CHECK_PMT( file != NULL )) return -1;
5293 if(!MSVCRT_CHECK_PMT( format != NULL )) return -1;
5295 if(options & MSVCRT_PRINTF_POSITIONAL_PARAMS) {
5296 memset(args_ctx, 0, sizeof(args_ctx));
5297 ret = create_positional_ctx_a(args_ctx, format, valist);
5298 if(ret < 0) {
5299 _invalid_parameter(NULL, NULL, NULL, 0, 0);
5300 *_errno() = EINVAL;
5301 return ret;
5302 } else if(!ret)
5303 options &= ~MSVCRT_PRINTF_POSITIONAL_PARAMS;
5306 _lock_file(file);
5307 tmp_buf = add_std_buffer(file);
5308 ret = pf_printf_a(puts_clbk_file_a, file, format, locale, options,
5309 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? arg_clbk_positional : arg_clbk_valist,
5310 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? args_ctx : NULL, &valist);
5311 if(tmp_buf) remove_std_buffer(file);
5312 _unlock_file(file);
5314 return ret;
5317 static int vfwprintf_helper(DWORD options, FILE* file, const wchar_t *format,
5318 _locale_t locale, va_list valist)
5320 printf_arg args_ctx[_ARGMAX+1];
5321 BOOL tmp_buf;
5322 int ret;
5324 if(!MSVCRT_CHECK_PMT( file != NULL )) return -1;
5325 if(!MSVCRT_CHECK_PMT( format != NULL )) return -1;
5327 if(options & MSVCRT_PRINTF_POSITIONAL_PARAMS) {
5328 memset(args_ctx, 0, sizeof(args_ctx));
5329 ret = create_positional_ctx_w(args_ctx, format, valist);
5330 if(ret < 0) {
5331 _invalid_parameter(NULL, NULL, NULL, 0, 0);
5332 *_errno() = EINVAL;
5333 return ret;
5334 } else if(!ret)
5335 options &= ~MSVCRT_PRINTF_POSITIONAL_PARAMS;
5338 _lock_file(file);
5339 tmp_buf = add_std_buffer(file);
5340 ret = pf_printf_w(puts_clbk_file_w, file, format, locale, options,
5341 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? arg_clbk_positional : arg_clbk_valist,
5342 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? args_ctx : NULL, &valist);
5343 if(tmp_buf) remove_std_buffer(file);
5344 _unlock_file(file);
5346 return ret;
5349 /*********************************************************************
5350 * _vfprintf_s_l (MSVCRT.@)
5352 int CDECL _vfprintf_s_l(FILE* file, const char *format,
5353 _locale_t locale, va_list valist)
5355 return vfprintf_helper(MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5358 /*********************************************************************
5359 * _vfwprintf_s_l (MSVCRT.@)
5361 int CDECL _vfwprintf_s_l(FILE* file, const wchar_t *format,
5362 _locale_t locale, va_list valist)
5364 return vfwprintf_helper(MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5367 /*********************************************************************
5368 * vfprintf (MSVCRT.@)
5370 int CDECL vfprintf(FILE* file, const char *format, va_list valist)
5372 return vfprintf_helper(0, file, format, NULL, valist);
5375 /*********************************************************************
5376 * vfprintf_s (MSVCRT.@)
5378 int CDECL vfprintf_s(FILE* file, const char *format, va_list valist)
5380 return _vfprintf_s_l(file, format, NULL, valist);
5383 /*********************************************************************
5384 * vfwprintf (MSVCRT.@)
5386 int CDECL vfwprintf(FILE* file, const wchar_t *format, va_list valist)
5388 return vfwprintf_helper(0, file, format, NULL, valist);
5391 /*********************************************************************
5392 * vfwprintf_s (MSVCRT.@)
5394 int CDECL vfwprintf_s(FILE* file, const wchar_t *format, va_list valist)
5396 return _vfwprintf_s_l(file, format, NULL, valist);
5399 #if _MSVCR_VER >= 140
5401 /*********************************************************************
5402 * __stdio_common_vfprintf (UCRTBASE.@)
5404 int CDECL _stdio_common_vfprintf(unsigned __int64 options, FILE *file, const char *format,
5405 _locale_t locale, va_list valist)
5407 if (options & ~UCRTBASE_PRINTF_MASK)
5408 FIXME("options %#I64x not handled\n", options);
5410 return vfprintf_helper(options & UCRTBASE_PRINTF_MASK, file, format, locale, valist);
5413 /*********************************************************************
5414 * __stdio_common_vfprintf_p (UCRTBASE.@)
5416 int CDECL __stdio_common_vfprintf_p(unsigned __int64 options, FILE *file, const char *format,
5417 _locale_t locale, va_list valist)
5419 if (options & ~UCRTBASE_PRINTF_MASK)
5420 FIXME("options %#I64x not handled\n", options);
5422 return vfprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_POSITIONAL_PARAMS
5423 | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5427 /*********************************************************************
5428 * __stdio_common_vfprintf_s (UCRTBASE.@)
5430 int CDECL __stdio_common_vfprintf_s(unsigned __int64 options, FILE *file, const char *format,
5431 _locale_t locale, va_list valist)
5433 if (options & ~UCRTBASE_PRINTF_MASK)
5434 FIXME("options %#I64x not handled\n", options);
5436 return vfprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5437 file, format, locale, valist);
5440 /*********************************************************************
5441 * __stdio_common_vfwprintf (UCRTBASE.@)
5443 int CDECL __stdio_common_vfwprintf(unsigned __int64 options, FILE *file, const wchar_t *format,
5444 _locale_t locale, va_list valist)
5446 if (options & ~UCRTBASE_PRINTF_MASK)
5447 FIXME("options %#I64x not handled\n", options);
5449 return vfwprintf_helper(options & UCRTBASE_PRINTF_MASK, file, format, locale, valist);
5452 /*********************************************************************
5453 * __stdio_common_vfwprintf_p (UCRTBASE.@)
5455 int CDECL __stdio_common_vfwprintf_p(unsigned __int64 options, FILE *file, const wchar_t *format,
5456 _locale_t locale, va_list valist)
5458 if (options & ~UCRTBASE_PRINTF_MASK)
5459 FIXME("options %#I64x not handled\n", options);
5461 return vfwprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_POSITIONAL_PARAMS
5462 | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5466 /*********************************************************************
5467 * __stdio_common_vfwprintf_s (UCRTBASE.@)
5469 int CDECL __stdio_common_vfwprintf_s(unsigned __int64 options, FILE *file, const wchar_t *format,
5470 _locale_t locale, va_list valist)
5472 if (options & ~UCRTBASE_PRINTF_MASK)
5473 FIXME("options %#I64x not handled\n", options);
5475 return vfwprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5476 file, format, locale, valist);
5479 #endif /* _MSVCR_VER >= 140 */
5481 /*********************************************************************
5482 * _vfprintf_l (MSVCRT.@)
5484 int CDECL _vfprintf_l(FILE* file, const char *format,
5485 _locale_t locale, va_list valist)
5487 return vfprintf_helper(0, file, format, locale, valist);
5490 /*********************************************************************
5491 * _vfwprintf_l (MSVCRT.@)
5493 int CDECL _vfwprintf_l(FILE* file, const wchar_t *format,
5494 _locale_t locale, va_list valist)
5496 return vfwprintf_helper(0, file, format, locale, valist);
5499 /*********************************************************************
5500 * _vfprintf_p_l (MSVCRT.@)
5502 int CDECL _vfprintf_p_l(FILE* file, const char *format,
5503 _locale_t locale, va_list valist)
5505 return vfprintf_helper(MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5506 file, format, locale, valist);
5509 /*********************************************************************
5510 * _vfprintf_p (MSVCRT.@)
5512 int CDECL _vfprintf_p(FILE* file, const char *format, va_list valist)
5514 return _vfprintf_p_l(file, format, NULL, valist);
5517 /*********************************************************************
5518 * _vfwprintf_p_l (MSVCRT.@)
5520 int CDECL _vfwprintf_p_l(FILE* file, const wchar_t *format,
5521 _locale_t locale, va_list valist)
5523 return vfwprintf_helper(MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5524 file, format, locale, valist);
5527 /*********************************************************************
5528 * _vfwprintf_p (MSVCRT.@)
5530 int CDECL _vfwprintf_p(FILE* file, const wchar_t *format, va_list valist)
5532 return _vfwprintf_p_l(file, format, NULL, valist);
5535 /*********************************************************************
5536 * vprintf (MSVCRT.@)
5538 int CDECL vprintf(const char *format, va_list valist)
5540 return vfprintf(MSVCRT_stdout,format,valist);
5543 /*********************************************************************
5544 * vprintf_s (MSVCRT.@)
5546 int CDECL vprintf_s(const char *format, va_list valist)
5548 return vfprintf_s(MSVCRT_stdout,format,valist);
5551 /*********************************************************************
5552 * vwprintf (MSVCRT.@)
5554 int CDECL vwprintf(const wchar_t *format, va_list valist)
5556 return vfwprintf(MSVCRT_stdout,format,valist);
5559 /*********************************************************************
5560 * vwprintf_s (MSVCRT.@)
5562 int CDECL vwprintf_s(const wchar_t *format, va_list valist)
5564 return vfwprintf_s(MSVCRT_stdout,format,valist);
5567 /*********************************************************************
5568 * fprintf (MSVCRT.@)
5570 int WINAPIV fprintf(FILE* file, const char *format, ...)
5572 va_list valist;
5573 int res;
5574 va_start(valist, format);
5575 res = vfprintf(file, format, valist);
5576 va_end(valist);
5577 return res;
5580 /*********************************************************************
5581 * fprintf_s (MSVCRT.@)
5583 int WINAPIV fprintf_s(FILE* file, const char *format, ...)
5585 va_list valist;
5586 int res;
5587 va_start(valist, format);
5588 res = vfprintf_s(file, format, valist);
5589 va_end(valist);
5590 return res;
5593 /*********************************************************************
5594 * _fprintf_l (MSVCRT.@)
5596 int WINAPIV _fprintf_l(FILE* file, const char *format, _locale_t locale, ...)
5598 va_list valist;
5599 int res;
5600 va_start(valist, locale);
5601 res = _vfprintf_l(file, format, locale, valist);
5602 va_end(valist);
5603 return res;
5607 /*********************************************************************
5608 * _fprintf_p (MSVCRT.@)
5610 int WINAPIV _fprintf_p(FILE* file, const char *format, ...)
5612 va_list valist;
5613 int res;
5614 va_start(valist, format);
5615 res = _vfprintf_p_l(file, format, NULL, valist);
5616 va_end(valist);
5617 return res;
5620 /*********************************************************************
5621 * _fprintf_p_l (MSVCRT.@)
5623 int WINAPIV _fprintf_p_l(FILE* file, const char *format, _locale_t locale, ...)
5625 va_list valist;
5626 int res;
5627 va_start(valist, locale);
5628 res = _vfprintf_p_l(file, format, locale, valist);
5629 va_end(valist);
5630 return res;
5633 /*********************************************************************
5634 * _fprintf_s_l (MSVCRT.@)
5636 int WINAPIV _fprintf_s_l(FILE* file, const char *format, _locale_t locale, ...)
5638 va_list valist;
5639 int res;
5640 va_start(valist, locale);
5641 res = _vfprintf_s_l(file, format, locale, valist);
5642 va_end(valist);
5643 return res;
5646 /*********************************************************************
5647 * fwprintf (MSVCRT.@)
5649 int WINAPIV fwprintf(FILE* file, const wchar_t *format, ...)
5651 va_list valist;
5652 int res;
5653 va_start(valist, format);
5654 res = vfwprintf(file, format, valist);
5655 va_end(valist);
5656 return res;
5659 /*********************************************************************
5660 * fwprintf_s (MSVCRT.@)
5662 int WINAPIV fwprintf_s(FILE* file, const wchar_t *format, ...)
5664 va_list valist;
5665 int res;
5666 va_start(valist, format);
5667 res = vfwprintf_s(file, format, valist);
5668 va_end(valist);
5669 return res;
5672 /*********************************************************************
5673 * _fwprintf_l (MSVCRT.@)
5675 int WINAPIV _fwprintf_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5677 va_list valist;
5678 int res;
5679 va_start(valist, locale);
5680 res = _vfwprintf_l(file, format, locale, valist);
5681 va_end(valist);
5682 return res;
5685 /*********************************************************************
5686 * _fwprintf_p (MSVCRT.@)
5688 int WINAPIV _fwprintf_p(FILE* file, const wchar_t *format, ...)
5690 va_list valist;
5691 int res;
5692 va_start(valist, format);
5693 res = _vfwprintf_p_l(file, format, NULL, valist);
5694 va_end(valist);
5695 return res;
5698 /*********************************************************************
5699 * _fwprintf_p_l (MSVCRT.@)
5701 int WINAPIV _fwprintf_p_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5703 va_list valist;
5704 int res;
5705 va_start(valist, locale);
5706 res = _vfwprintf_p_l(file, format, locale, valist);
5707 va_end(valist);
5708 return res;
5711 /*********************************************************************
5712 * _fwprintf_s_l (MSVCRT.@)
5714 int WINAPIV _fwprintf_s_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5716 va_list valist;
5717 int res;
5718 va_start(valist, locale);
5719 res = _vfwprintf_s_l(file, format, locale, valist);
5720 va_end(valist);
5721 return res;
5724 /*********************************************************************
5725 * printf (MSVCRT.@)
5727 int WINAPIV printf(const char *format, ...)
5729 va_list valist;
5730 int res;
5731 va_start(valist, format);
5732 res = vfprintf(MSVCRT_stdout, format, valist);
5733 va_end(valist);
5734 return res;
5737 /*********************************************************************
5738 * printf_s (MSVCRT.@)
5740 int WINAPIV printf_s(const char *format, ...)
5742 va_list valist;
5743 int res;
5744 va_start(valist, format);
5745 res = vprintf_s(format, valist);
5746 va_end(valist);
5747 return res;
5750 /*********************************************************************
5751 * ungetc (MSVCRT.@)
5753 int CDECL ungetc(int c, FILE * file)
5755 int ret;
5757 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
5759 _lock_file(file);
5760 ret = _ungetc_nolock(c, file);
5761 _unlock_file(file);
5763 return ret;
5766 /*********************************************************************
5767 * _ungetc_nolock (MSVCRT.@)
5769 int CDECL _ungetc_nolock(int c, FILE * file)
5771 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
5773 if (c == EOF || !(file->_flag&_IOREAD ||
5774 (file->_flag&_IORW && !(file->_flag&_IOWRT))))
5775 return EOF;
5777 if((!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF))
5778 && msvcrt_alloc_buffer(file))
5779 || (!file->_cnt && file->_ptr==file->_base))
5780 file->_ptr++;
5782 if(file->_ptr>file->_base) {
5783 file->_ptr--;
5784 if(file->_flag & _IOSTRG) {
5785 if(*file->_ptr != c) {
5786 file->_ptr++;
5787 return EOF;
5789 }else {
5790 *file->_ptr = c;
5792 file->_cnt++;
5793 file->_flag &= ~(_IOERR | _IOEOF);
5794 file->_flag |= _IOREAD;
5795 return c;
5798 return EOF;
5801 /*********************************************************************
5802 * ungetwc (MSVCRT.@)
5804 wint_t CDECL ungetwc(wint_t wc, FILE * file)
5806 wint_t ret;
5808 if(!MSVCRT_CHECK_PMT(file != NULL)) return WEOF;
5810 _lock_file(file);
5811 ret = _ungetwc_nolock(wc, file);
5812 _unlock_file(file);
5814 return ret;
5817 /*********************************************************************
5818 * _ungetwc_nolock (MSVCRT.@)
5820 wint_t CDECL _ungetwc_nolock(wint_t wc, FILE * file)
5822 wchar_t mwc = wc;
5824 if(!MSVCRT_CHECK_PMT(file != NULL)) return WEOF;
5825 if (wc == WEOF)
5826 return WEOF;
5828 if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI
5829 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
5830 unsigned char * pp = (unsigned char *)&mwc;
5831 int i;
5833 for(i=sizeof(wchar_t)-1;i>=0;i--) {
5834 if(pp[i] != _ungetc_nolock(pp[i],file))
5835 return WEOF;
5837 }else {
5838 char mbs[MB_LEN_MAX];
5839 int len;
5841 len = wctomb(mbs, mwc);
5842 if(len == -1)
5843 return WEOF;
5845 for(len--; len>=0; len--) {
5846 if(mbs[len] != _ungetc_nolock(mbs[len], file))
5847 return WEOF;
5851 return mwc;
5854 /*********************************************************************
5855 * wprintf (MSVCRT.@)
5857 int WINAPIV wprintf(const wchar_t *format, ...)
5859 va_list valist;
5860 int res;
5861 va_start(valist, format);
5862 res = vwprintf(format, valist);
5863 va_end(valist);
5864 return res;
5867 /*********************************************************************
5868 * wprintf_s (MSVCRT.@)
5870 int WINAPIV wprintf_s(const wchar_t *format, ...)
5872 va_list valist;
5873 int res;
5874 va_start(valist, format);
5875 res = vwprintf_s(format, valist);
5876 va_end(valist);
5877 return res;
5880 /*********************************************************************
5881 * _getmaxstdio (MSVCRT.@)
5883 int CDECL _getmaxstdio(void)
5885 return MSVCRT_max_streams;
5888 /*********************************************************************
5889 * _setmaxstdio (MSVCRT.@)
5891 int CDECL _setmaxstdio(int newmax)
5893 TRACE("%d\n", newmax);
5895 if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
5896 return -1;
5898 MSVCRT_max_streams = newmax;
5899 return MSVCRT_max_streams;
5902 #if _MSVCR_VER >= 140
5903 /*********************************************************************
5904 * _get_stream_buffer_pointers (UCRTBASE.@)
5906 int CDECL _get_stream_buffer_pointers(FILE *file, char*** base,
5907 char*** ptr, int** count)
5909 if (base)
5910 *base = &file->_base;
5911 if (ptr)
5912 *ptr = &file->_ptr;
5913 if (count)
5914 *count = &file->_cnt;
5915 return 0;
5917 #endif