winewayland.drv: Implement vkGetPhysicalDeviceSurfaceSupportKHR.
[wine.git] / dlls / msvcrt / file.c
blob3c1d9572585033c9a465d37f7a0fe084798db607
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"
45 #include "wine/asm.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 #if defined(__i386__)
1662 /* Stack preserving thunk for rewind
1663 * needed for the UIO mod for Fallout: New Vegas
1665 __ASM_GLOBAL_FUNC(rewind_preserve_stack,
1666 "pushl 4(%esp)\n\t"
1667 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1668 "call "__ASM_NAME("rewind") "\n\t"
1669 "addl $4,%esp\n\t"
1670 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
1671 "ret")
1672 #endif
1674 /*********************************************************************
1675 * rewind (MSVCRT.@)
1677 void CDECL rewind(FILE* file)
1679 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1681 _lock_file(file);
1682 _fseek_nolock(file, 0L, SEEK_SET);
1683 clearerr(file);
1684 _unlock_file(file);
1687 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1689 int plus = wcschr(mode, '+') != NULL;
1691 TRACE("%s\n", debugstr_w(mode));
1693 while(*mode == ' ') mode++;
1695 switch(*mode++)
1697 case 'R': case 'r':
1698 *open_flags = plus ? _O_RDWR : _O_RDONLY;
1699 *stream_flags = plus ? _IORW : _IOREAD;
1700 break;
1701 case 'W': case 'w':
1702 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1703 *stream_flags = plus ? _IORW : _IOWRT;
1704 break;
1705 case 'A': case 'a':
1706 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1707 *stream_flags = plus ? _IORW : _IOWRT;
1708 break;
1709 default:
1710 MSVCRT_INVALID_PMT(0, EINVAL);
1711 return -1;
1714 *stream_flags |= MSVCRT__commode;
1716 while (*mode && *mode!=',')
1717 switch (*mode++)
1719 case 'B': case 'b':
1720 *open_flags |= _O_BINARY;
1721 *open_flags &= ~_O_TEXT;
1722 break;
1723 case 't':
1724 *open_flags |= _O_TEXT;
1725 *open_flags &= ~_O_BINARY;
1726 break;
1727 #if _MSVCR_VER>=140
1728 case 'x':
1729 if(!MSVCRT_CHECK_PMT((*open_flags & (_O_CREAT | _O_APPEND)) == _O_CREAT))
1730 return -1;
1731 *open_flags |= _O_EXCL;
1732 break;
1733 #endif
1734 case 'D':
1735 *open_flags |= _O_TEMPORARY;
1736 break;
1737 case 'T':
1738 *open_flags |= _O_SHORT_LIVED;
1739 break;
1740 case 'c':
1741 *stream_flags |= MSVCRT__IOCOMMIT;
1742 break;
1743 case 'n':
1744 *stream_flags &= ~MSVCRT__IOCOMMIT;
1745 break;
1746 case 'N':
1747 *open_flags |= _O_NOINHERIT;
1748 break;
1749 case '+':
1750 case ' ':
1751 case 'a':
1752 case 'w':
1753 break;
1754 case 'S':
1755 if (!(*open_flags & _O_RANDOM))
1756 *open_flags |= _O_SEQUENTIAL;
1757 break;
1758 case 'R':
1759 if (!(*open_flags & _O_SEQUENTIAL))
1760 *open_flags |= _O_RANDOM;
1761 break;
1762 default:
1763 ERR("incorrect mode flag: %c\n", mode[-1]);
1764 break;
1767 if(*mode == ',')
1769 mode++;
1770 while(*mode == ' ') mode++;
1771 if(!MSVCRT_CHECK_PMT(!wcsncmp(L"ccs", mode, 3)))
1772 return -1;
1773 mode += 3;
1774 while(*mode == ' ') mode++;
1775 if(!MSVCRT_CHECK_PMT(*mode == '='))
1776 return -1;
1777 mode++;
1778 while(*mode == ' ') mode++;
1780 if(!_wcsnicmp(L"utf-8", mode, 5))
1782 *open_flags |= _O_U8TEXT;
1783 mode += 5;
1785 else if(!_wcsnicmp(L"utf-16le", mode, 8))
1787 *open_flags |= _O_U16TEXT;
1788 mode += 8;
1790 else if(!_wcsnicmp(L"unicode", mode, 7))
1792 *open_flags |= _O_WTEXT;
1793 mode += 7;
1795 else
1797 MSVCRT_INVALID_PMT(0, EINVAL);
1798 return -1;
1801 while(*mode == ' ') mode++;
1804 if(!MSVCRT_CHECK_PMT(*mode == 0))
1805 return -1;
1806 return 0;
1809 /*********************************************************************
1810 * _fdopen (MSVCRT.@)
1812 FILE* CDECL _fdopen(int fd, const char *mode)
1814 FILE *ret;
1815 wchar_t *modeW = NULL;
1817 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1819 ret = _wfdopen(fd, modeW);
1821 free(modeW);
1822 return ret;
1825 /*********************************************************************
1826 * _wfdopen (MSVCRT.@)
1828 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1830 int open_flags, stream_flags;
1831 FILE* file;
1833 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1835 LOCK_FILES();
1836 if (!(file = msvcrt_alloc_fp()))
1837 file = NULL;
1838 else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1840 file->_flag = 0;
1841 file = NULL;
1843 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1844 UNLOCK_FILES();
1846 return file;
1849 /*********************************************************************
1850 * _filelength (MSVCRT.@)
1852 __msvcrt_long CDECL _filelength(int fd)
1854 LONG curPos = _lseek(fd, 0, SEEK_CUR);
1855 if (curPos != -1)
1857 LONG endPos = _lseek(fd, 0, SEEK_END);
1858 if (endPos != -1)
1860 if (endPos != curPos)
1861 _lseek(fd, curPos, SEEK_SET);
1862 return endPos;
1865 return -1;
1868 /*********************************************************************
1869 * _filelengthi64 (MSVCRT.@)
1871 __int64 CDECL _filelengthi64(int fd)
1873 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1874 if (curPos != -1)
1876 __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1877 if (endPos != -1)
1879 if (endPos != curPos)
1880 _lseeki64(fd, curPos, SEEK_SET);
1881 return endPos;
1884 return -1;
1887 /*********************************************************************
1888 * _fileno (MSVCRT.@)
1890 int CDECL _fileno(FILE* file)
1892 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1893 return file->_file;
1896 /*********************************************************************
1897 * _fstat64 (MSVCRT.@)
1899 int CDECL _fstat64(int fd, struct _stat64* buf)
1901 ioinfo *info = get_ioinfo(fd);
1902 DWORD dw;
1903 DWORD type;
1905 TRACE(":fd (%d) stat (%p)\n", fd, buf);
1906 if (info->handle == INVALID_HANDLE_VALUE)
1908 release_ioinfo(info);
1909 return -1;
1912 if (!buf)
1914 WARN(":failed-NULL buf\n");
1915 msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1916 release_ioinfo(info);
1917 return -1;
1920 memset(buf, 0, sizeof(struct _stat64));
1921 type = GetFileType(info->handle);
1922 if (type == FILE_TYPE_PIPE)
1924 buf->st_dev = buf->st_rdev = fd;
1925 buf->st_mode = _S_IFIFO;
1926 buf->st_nlink = 1;
1928 else if (type == FILE_TYPE_CHAR)
1930 buf->st_dev = buf->st_rdev = fd;
1931 buf->st_mode = _S_IFCHR;
1932 buf->st_nlink = 1;
1934 else /* FILE_TYPE_DISK etc. */
1936 FILE_BASIC_INFORMATION basic_info;
1937 FILE_STANDARD_INFORMATION std_info;
1938 IO_STATUS_BLOCK io;
1939 NTSTATUS status;
1941 if ((status = NtQueryInformationFile( info->handle, &io, &basic_info, sizeof(basic_info), FileBasicInformation )) ||
1942 (status = NtQueryInformationFile( info->handle, &io, &std_info, sizeof(std_info), FileStandardInformation )))
1944 WARN(":failed-error %lx\n", status);
1945 msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1946 release_ioinfo(info);
1947 return -1;
1949 buf->st_mode = _S_IFREG | 0444;
1950 if (!(basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY))
1951 buf->st_mode |= 0222;
1952 buf->st_size = std_info.EndOfFile.QuadPart;
1953 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&basic_info.LastAccessTime, &dw);
1954 buf->st_atime = dw;
1955 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&basic_info.LastWriteTime, &dw);
1956 buf->st_mtime = buf->st_ctime = dw;
1957 buf->st_nlink = std_info.NumberOfLinks;
1958 TRACE(":dwFileAttributes = %#lx, mode set to %#x\n",
1959 basic_info.FileAttributes, buf->st_mode);
1961 release_ioinfo(info);
1962 return 0;
1965 /*********************************************************************
1966 * _fstati64 (MSVCRT.@)
1968 int CDECL _fstati64(int fd, struct _stati64* buf)
1970 int ret;
1971 struct _stat64 buf64;
1973 ret = _fstat64(fd, &buf64);
1974 if (!ret)
1975 msvcrt_stat64_to_stati64(&buf64, buf);
1976 return ret;
1979 /*********************************************************************
1980 * _fstat (MSVCRT.@)
1982 int CDECL _fstat(int fd, struct _stat* buf)
1983 { int ret;
1984 struct _stat64 buf64;
1986 ret = _fstat64(fd, &buf64);
1987 if (!ret)
1988 msvcrt_stat64_to_stat(&buf64, buf);
1989 return ret;
1992 /*********************************************************************
1993 * _fstat32 (MSVCR80.@)
1995 int CDECL _fstat32(int fd, struct _stat32* buf)
1997 int ret;
1998 struct _stat64 buf64;
2000 ret = _fstat64(fd, &buf64);
2001 if (!ret)
2002 msvcrt_stat64_to_stat32(&buf64, buf);
2003 return ret;
2006 /*********************************************************************
2007 * _fstat32i64 (MSVCR80.@)
2009 int CDECL _fstat32i64(int fd, struct _stat32i64* buf)
2011 int ret;
2012 struct _stat64 buf64;
2014 ret = _fstat64(fd, &buf64);
2015 if (!ret)
2016 msvcrt_stat64_to_stat32i64(&buf64, buf);
2017 return ret;
2020 /*********************************************************************
2021 * _fstat64i32 (MSVCR80.@)
2023 int CDECL _fstat64i32(int fd, struct _stat64i32* buf)
2025 int ret;
2026 struct _stat64 buf64;
2028 ret = _fstat64(fd, &buf64);
2029 if (!ret)
2030 msvcrt_stat64_to_stat64i32(&buf64, buf);
2031 return ret;
2034 /*********************************************************************
2035 * _futime64 (MSVCRT.@)
2037 int CDECL _futime64(int fd, struct __utimbuf64 *t)
2039 ioinfo *info = get_ioinfo(fd);
2040 FILETIME at, wt;
2042 if (!t)
2044 time_to_filetime( _time64(NULL), &at );
2045 wt = at;
2047 else
2049 time_to_filetime( t->actime, &at );
2050 time_to_filetime( t->modtime, &wt );
2053 if (!SetFileTime(info->handle, NULL, &at, &wt))
2055 release_ioinfo(info);
2056 msvcrt_set_errno(GetLastError());
2057 return -1 ;
2059 release_ioinfo(info);
2060 return 0;
2063 /*********************************************************************
2064 * _futime32 (MSVCRT.@)
2066 int CDECL _futime32(int fd, struct __utimbuf32 *t)
2068 if (t)
2070 struct __utimbuf64 t64;
2071 t64.actime = t->actime;
2072 t64.modtime = t->modtime;
2073 return _futime64( fd, &t64 );
2075 else
2076 return _futime64( fd, NULL );
2079 /*********************************************************************
2080 * _get_osfhandle (MSVCRT.@)
2082 intptr_t CDECL _get_osfhandle(int fd)
2084 HANDLE hand = get_ioinfo_nolock(fd)->handle;
2085 TRACE(":fd (%d) handle (%p)\n",fd,hand);
2087 if(hand == INVALID_HANDLE_VALUE)
2088 *_errno() = EBADF;
2089 return (intptr_t)hand;
2092 /*********************************************************************
2093 * _mktemp_s (MSVCRT.@)
2095 int CDECL _mktemp_s(char *pattern, size_t size)
2097 DWORD len, xno, id;
2099 if(!MSVCRT_CHECK_PMT(pattern!=NULL))
2100 return EINVAL;
2102 for(len=0; len<size; len++)
2103 if(!pattern[len])
2104 break;
2105 if(!MSVCRT_CHECK_PMT(len!=size && len>=6)) {
2106 if(size)
2107 pattern[0] = 0;
2108 return EINVAL;
2111 for(xno=1; xno<=6; xno++)
2112 if(!MSVCRT_CHECK_PMT(pattern[len-xno] == 'X'))
2113 return EINVAL;
2115 id = GetCurrentProcessId();
2116 for(xno=1; xno<6; xno++) {
2117 pattern[len-xno] = id%10 + '0';
2118 id /= 10;
2121 for(pattern[len-6]='a'; pattern[len-6]<='z'; pattern[len-6]++) {
2122 if(GetFileAttributesA(pattern) == INVALID_FILE_ATTRIBUTES)
2123 return 0;
2126 pattern[0] = 0;
2127 *_errno() = EEXIST;
2128 return EEXIST;
2131 /*********************************************************************
2132 * _mktemp (MSVCRT.@)
2134 char * CDECL _mktemp(char *pattern)
2136 int numX = 0;
2137 char *retVal = pattern;
2138 int id;
2139 char letter = 'a';
2141 if(!pattern)
2142 return NULL;
2144 while(*pattern)
2145 numX = (*pattern++ == 'X')? numX + 1 : 0;
2146 if (numX < 6)
2147 return NULL;
2148 pattern--;
2149 id = GetCurrentProcessId();
2150 numX = 6;
2151 while(numX--)
2153 int tempNum = id / 10;
2154 *pattern-- = id - (tempNum * 10) + '0';
2155 id = tempNum;
2157 pattern++;
2160 *pattern = letter++;
2161 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
2162 return retVal;
2163 } while(letter <= 'z');
2164 return NULL;
2167 /*********************************************************************
2168 * _wmktemp_s (MSVCRT.@)
2170 int CDECL _wmktemp_s(wchar_t *pattern, size_t size)
2172 DWORD len, xno, id;
2174 if(!MSVCRT_CHECK_PMT(pattern!=NULL))
2175 return EINVAL;
2177 for(len=0; len<size; len++)
2178 if(!pattern[len])
2179 break;
2180 if(!MSVCRT_CHECK_PMT(len!=size && len>=6)) {
2181 if(size)
2182 pattern[0] = 0;
2183 return EINVAL;
2186 for(xno=1; xno<=6; xno++)
2187 if(!MSVCRT_CHECK_PMT(pattern[len-xno] == 'X'))
2188 return EINVAL;
2190 id = GetCurrentProcessId();
2191 for(xno=1; xno<6; xno++) {
2192 pattern[len-xno] = id%10 + '0';
2193 id /= 10;
2196 for(pattern[len-6]='a'; pattern[len-6]<='z'; pattern[len-6]++) {
2197 if(GetFileAttributesW(pattern) == INVALID_FILE_ATTRIBUTES)
2198 return 0;
2201 pattern[0] = 0;
2202 *_errno() = EEXIST;
2203 return EEXIST;
2206 /*********************************************************************
2207 * _wmktemp (MSVCRT.@)
2209 wchar_t * CDECL _wmktemp(wchar_t *pattern)
2211 int numX = 0;
2212 wchar_t *retVal = pattern;
2213 int id;
2214 wchar_t letter = 'a';
2216 if(!pattern)
2217 return NULL;
2219 while(*pattern)
2220 numX = (*pattern++ == 'X')? numX + 1 : 0;
2221 if (numX < 6)
2222 return NULL;
2223 pattern--;
2224 id = GetCurrentProcessId();
2225 numX = 6;
2226 while(numX--)
2228 int tempNum = id / 10;
2229 *pattern-- = id - (tempNum * 10) + '0';
2230 id = tempNum;
2232 pattern++;
2235 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES)
2236 return retVal;
2237 *pattern = letter++;
2238 } while(letter != '|');
2239 return NULL;
2242 static unsigned split_oflags(unsigned oflags)
2244 int wxflags = 0;
2245 unsigned unsupp; /* until we support everything */
2247 if (oflags & _O_APPEND) wxflags |= WX_APPEND;
2248 if (oflags & _O_BINARY) {/* Nothing to do */}
2249 else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
2250 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
2251 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
2252 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
2253 else
2255 int fmode;
2256 _get_fmode(&fmode);
2257 if (!(fmode & _O_BINARY)) wxflags |= WX_TEXT; /* default to TEXT*/
2259 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
2261 if ((unsupp = oflags & ~(_O_BINARY | _O_TEXT | _O_APPEND | _O_TRUNC | _O_EXCL | _O_CREAT |
2262 _O_RDWR | _O_WRONLY | _O_TEMPORARY | _O_NOINHERIT | _O_SEQUENTIAL |
2263 _O_RANDOM | _O_SHORT_LIVED | _O_WTEXT | _O_U16TEXT | _O_U8TEXT)))
2264 ERR(":unsupported oflags %#x\n",unsupp);
2266 return wxflags;
2269 /*********************************************************************
2270 * _pipe (MSVCRT.@)
2272 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
2274 int ret = -1;
2275 SECURITY_ATTRIBUTES sa;
2276 HANDLE readHandle, writeHandle;
2278 if (!pfds)
2280 *_errno() = EINVAL;
2281 return -1;
2284 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2285 sa.bInheritHandle = !(textmode & _O_NOINHERIT);
2286 sa.lpSecurityDescriptor = NULL;
2287 if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
2289 unsigned int wxflags = split_oflags(textmode);
2290 int fd;
2292 fd = msvcrt_alloc_fd(readHandle, wxflags|WX_PIPE);
2293 if (fd != -1)
2295 pfds[0] = fd;
2296 fd = msvcrt_alloc_fd(writeHandle, wxflags|WX_PIPE);
2297 if (fd != -1)
2299 pfds[1] = fd;
2300 ret = 0;
2302 else
2304 _close(pfds[0]);
2305 CloseHandle(writeHandle);
2306 *_errno() = EMFILE;
2309 else
2311 CloseHandle(readHandle);
2312 CloseHandle(writeHandle);
2313 *_errno() = EMFILE;
2316 else
2317 msvcrt_set_errno(GetLastError());
2319 return ret;
2322 static int check_bom(HANDLE h, int oflags, BOOL seek)
2324 char bom[sizeof(utf8_bom)];
2325 DWORD r;
2327 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
2328 return oflags;
2330 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
2331 oflags = (oflags & ~(_O_WTEXT | _O_U16TEXT)) | _O_U8TEXT;
2332 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
2333 if (seek && r>2)
2334 SetFilePointer(h, 2, NULL, FILE_BEGIN);
2335 oflags = (oflags & ~(_O_WTEXT | _O_U8TEXT)) | _O_U16TEXT;
2336 }else if (seek) {
2337 SetFilePointer(h, 0, NULL, FILE_BEGIN);
2340 return oflags;
2343 /*********************************************************************
2344 * _wsopen_dispatch (UCRTBASE.@)
2346 int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pmode,
2347 int *fd, int secure )
2349 DWORD access = 0, creation = 0, attrib;
2350 SECURITY_ATTRIBUTES sa;
2351 DWORD sharing, type;
2352 int wxflag;
2353 HANDLE hand;
2355 TRACE("path: (%s) oflags: %#x shflags: %#x pmode: %#x fd*: %p secure: %d\n",
2356 debugstr_w(path), oflags, shflags, pmode, fd, secure);
2358 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
2360 *fd = -1;
2361 wxflag = split_oflags(oflags);
2362 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
2364 case _O_RDONLY: access |= GENERIC_READ; break;
2365 case _O_WRONLY: access |= GENERIC_WRITE; break;
2366 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
2369 if (oflags & _O_CREAT)
2371 if (secure && !MSVCRT_CHECK_PMT(!(pmode & ~(_S_IREAD | _S_IWRITE))))
2372 return EINVAL;
2374 if (oflags & _O_EXCL)
2375 creation = CREATE_NEW;
2376 else if (oflags & _O_TRUNC)
2377 creation = CREATE_ALWAYS;
2378 else
2379 creation = OPEN_ALWAYS;
2381 else /* no _O_CREAT */
2383 if (oflags & _O_TRUNC)
2384 creation = TRUNCATE_EXISTING;
2385 else
2386 creation = OPEN_EXISTING;
2389 switch( shflags )
2391 case _SH_DENYRW:
2392 sharing = 0L;
2393 break;
2394 case _SH_DENYWR:
2395 sharing = FILE_SHARE_READ;
2396 break;
2397 case _SH_DENYRD:
2398 sharing = FILE_SHARE_WRITE;
2399 break;
2400 case _SH_DENYNO:
2401 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
2402 break;
2403 default:
2404 ERR( "Unhandled shflags %#x\n", shflags );
2405 return EINVAL;
2408 if (!(pmode & ~MSVCRT_umask & _S_IWRITE))
2409 attrib = FILE_ATTRIBUTE_READONLY;
2410 else
2411 attrib = FILE_ATTRIBUTE_NORMAL;
2413 if (oflags & _O_TEMPORARY)
2415 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
2416 access |= DELETE;
2417 sharing |= FILE_SHARE_DELETE;
2420 if (oflags & _O_RANDOM)
2421 attrib |= FILE_FLAG_RANDOM_ACCESS;
2422 if (oflags & _O_SEQUENTIAL)
2423 attrib |= FILE_FLAG_SEQUENTIAL_SCAN;
2424 if (oflags & _O_SHORT_LIVED)
2425 attrib |= FILE_ATTRIBUTE_TEMPORARY;
2427 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
2428 sa.lpSecurityDescriptor = NULL;
2429 sa.bInheritHandle = !(oflags & _O_NOINHERIT);
2431 if ((oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
2432 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
2433 && !(access&GENERIC_READ))
2435 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
2436 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2437 if (hand != INVALID_HANDLE_VALUE)
2439 oflags = check_bom(hand, oflags, FALSE);
2440 CloseHandle(hand);
2444 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
2445 if (hand == INVALID_HANDLE_VALUE) {
2446 WARN(":failed-last error (%ld)\n", GetLastError());
2447 msvcrt_set_errno(GetLastError());
2448 return *_errno();
2451 if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
2453 LARGE_INTEGER size = {{0}};
2455 if ((access & GENERIC_WRITE) && (creation==OPEN_EXISTING || creation==OPEN_ALWAYS))
2456 GetFileSizeEx(hand, &size);
2458 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
2459 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
2460 || ((creation==OPEN_EXISTING || creation==OPEN_ALWAYS) && !size.QuadPart)))
2462 if (oflags & _O_U8TEXT)
2464 DWORD written = 0, tmp;
2466 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
2467 sizeof(utf8_bom)-written, &tmp, NULL))
2468 written += tmp;
2469 if (written != sizeof(utf8_bom)) {
2470 WARN("error writing BOM\n");
2471 CloseHandle(hand);
2472 msvcrt_set_errno(GetLastError());
2473 return *_errno();
2476 else
2478 DWORD written = 0, tmp;
2480 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
2481 sizeof(utf16_bom)-written, &tmp, NULL))
2482 written += tmp;
2483 if (written != sizeof(utf16_bom))
2485 WARN("error writing BOM\n");
2486 CloseHandle(hand);
2487 msvcrt_set_errno(GetLastError());
2488 return *_errno();
2490 oflags |= _O_U16TEXT;
2493 else if (access & GENERIC_READ)
2494 oflags = check_bom(hand, oflags, TRUE);
2497 type = GetFileType(hand);
2498 if (type == FILE_TYPE_CHAR)
2499 wxflag |= WX_TTY;
2500 else if (type == FILE_TYPE_PIPE)
2501 wxflag |= WX_PIPE;
2503 *fd = msvcrt_alloc_fd(hand, wxflag);
2504 if (*fd == -1)
2505 return *_errno();
2507 if (oflags & _O_WTEXT)
2508 ioinfo_set_unicode(get_ioinfo_nolock(*fd), TRUE);
2510 if (oflags & _O_U16TEXT)
2511 ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF16LE);
2512 else if (oflags & _O_U8TEXT)
2513 ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF8);
2515 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
2516 return 0;
2520 /*********************************************************************
2521 * _wsopen_s (MSVCRT.@)
2523 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
2525 return _wsopen_dispatch( path, oflags, shflags, pmode, fd, 1 );
2528 /*********************************************************************
2529 * _wsopen (MSVCRT.@)
2531 int WINAPIV _wsopen( const wchar_t *path, int oflags, int shflags, ... )
2533 int pmode;
2534 int fd;
2536 if (oflags & _O_CREAT)
2538 va_list ap;
2540 va_start(ap, shflags);
2541 pmode = va_arg(ap, int);
2542 va_end(ap);
2544 else
2545 pmode = 0;
2547 return _wsopen_dispatch(path, oflags, shflags, pmode, &fd, 0) ? -1 : fd;
2551 /*********************************************************************
2552 * _sopen_dispatch (UCRTBASE.@)
2554 int CDECL _sopen_dispatch( const char *path, int oflags, int shflags,
2555 int pmode, int *fd, int secure)
2557 wchar_t *pathW;
2558 int ret;
2560 if (!MSVCRT_CHECK_PMT(fd != NULL))
2561 return EINVAL;
2562 *fd = -1;
2563 if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
2564 return EINVAL;
2566 ret = _wsopen_dispatch(pathW, oflags, shflags, pmode, fd, secure);
2567 free(pathW);
2568 return ret;
2571 /*********************************************************************
2572 * _sopen_s (MSVCRT.@)
2574 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
2576 return _sopen_dispatch(path, oflags, shflags, pmode, fd, 1);
2579 /*********************************************************************
2580 * _sopen (MSVCRT.@)
2582 int WINAPIV _sopen( const char *path, int oflags, int shflags, ... )
2584 int pmode;
2585 int fd;
2587 if (oflags & _O_CREAT)
2589 va_list ap;
2591 va_start(ap, shflags);
2592 pmode = va_arg(ap, int);
2593 va_end(ap);
2595 else
2596 pmode = 0;
2598 return _sopen_dispatch(path, oflags, shflags, pmode, &fd, 0) ? -1 : fd;
2601 /*********************************************************************
2602 * _open (MSVCRT.@)
2604 int WINAPIV _open( const char *path, int flags, ... )
2606 va_list ap;
2608 if (flags & _O_CREAT)
2610 int pmode;
2611 va_start(ap, flags);
2612 pmode = va_arg(ap, int);
2613 va_end(ap);
2614 return _sopen( path, flags, _SH_DENYNO, pmode );
2616 else
2617 return _sopen( path, flags, _SH_DENYNO);
2620 /*********************************************************************
2621 * _wopen (MSVCRT.@)
2623 int WINAPIV _wopen(const wchar_t *path,int flags,...)
2625 va_list ap;
2627 if (flags & _O_CREAT)
2629 int pmode;
2630 va_start(ap, flags);
2631 pmode = va_arg(ap, int);
2632 va_end(ap);
2633 return _wsopen( path, flags, _SH_DENYNO, pmode );
2635 else
2636 return _wsopen( path, flags, _SH_DENYNO);
2639 /*********************************************************************
2640 * _creat (MSVCRT.@)
2642 int CDECL _creat(const char *path, int pmode)
2644 int flags = _O_CREAT | _O_TRUNC | _O_RDWR;
2645 return _open(path, flags, pmode);
2648 /*********************************************************************
2649 * _wcreat (MSVCRT.@)
2651 int CDECL _wcreat(const wchar_t *path, int pmode)
2653 int flags = _O_CREAT | _O_TRUNC | _O_RDWR;
2654 return _wopen(path, flags, pmode);
2657 /*********************************************************************
2658 * _open_osfhandle (MSVCRT.@)
2660 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2662 DWORD flags;
2663 int fd;
2665 /* _O_RDONLY (0) always matches, so set the read flag
2666 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2667 * file, so set the write flag. It also only sets _O_TEXT if it wants
2668 * text - it never sets _O_BINARY.
2670 /* don't let split_oflags() decide the mode if no mode is passed */
2671 if (!(oflags & (_O_BINARY | _O_TEXT)))
2672 oflags |= _O_BINARY;
2674 flags = GetFileType((HANDLE)handle);
2675 if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2677 msvcrt_set_errno(GetLastError());
2678 return -1;
2681 if (flags == FILE_TYPE_CHAR)
2682 flags = WX_TTY;
2683 else if (flags == FILE_TYPE_PIPE)
2684 flags = WX_PIPE;
2685 else
2686 flags = 0;
2687 flags |= split_oflags(oflags);
2689 fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2690 TRACE(":handle (%Iu) fd (%d) flags %#lx\n", handle, fd, flags);
2691 return fd;
2694 /*********************************************************************
2695 * _rmtmp (MSVCRT.@)
2697 int CDECL _rmtmp(void)
2699 int num_removed = 0, i;
2700 FILE *file;
2702 LOCK_FILES();
2703 for (i = 3; i < MSVCRT_stream_idx; i++) {
2704 file = msvcrt_get_file(i);
2706 if (file->_tmpfname)
2708 fclose(file);
2709 num_removed++;
2712 UNLOCK_FILES();
2714 if (num_removed)
2715 TRACE(":removed (%d) temp files\n",num_removed);
2716 return num_removed;
2719 static inline int get_utf8_char_len(char ch)
2721 if((ch&0xf8) == 0xf0)
2722 return 4;
2723 else if((ch&0xf0) == 0xe0)
2724 return 3;
2725 else if((ch&0xe0) == 0xc0)
2726 return 2;
2727 return 1;
2730 /*********************************************************************
2731 * (internal) read_utf8
2733 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2735 HANDLE hand = fdinfo->handle;
2736 char min_buf[4], *readbuf, lookahead;
2737 DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2739 /* make the buffer big enough to hold at least one character */
2740 /* read bytes have to fit to output and lookahead buffers */
2741 count /= 2;
2742 readbuf_size = count < 4 ? 4 : count;
2743 if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2744 readbuf_size = 4;
2745 readbuf = min_buf;
2748 if(fdinfo->lookahead[0] != '\n') {
2749 readbuf[pos++] = fdinfo->lookahead[0];
2750 fdinfo->lookahead[0] = '\n';
2752 if(fdinfo->lookahead[1] != '\n') {
2753 readbuf[pos++] = fdinfo->lookahead[1];
2754 fdinfo->lookahead[1] = '\n';
2756 if(fdinfo->lookahead[2] != '\n') {
2757 readbuf[pos++] = fdinfo->lookahead[2];
2758 fdinfo->lookahead[2] = '\n';
2763 /* NOTE: this case is broken in native dll, reading
2764 * sometimes fails when small buffer is passed
2766 if(count < 4) {
2767 if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2768 if (GetLastError() == ERROR_BROKEN_PIPE) {
2769 fdinfo->wxflag |= WX_ATEOF;
2770 return 0;
2771 }else {
2772 msvcrt_set_errno(GetLastError());
2773 if (GetLastError() == ERROR_ACCESS_DENIED)
2774 *_errno() = EBADF;
2775 return -1;
2777 }else if(!num_read) {
2778 fdinfo->wxflag |= WX_ATEOF;
2779 return 0;
2780 }else {
2781 pos++;
2784 char_len = get_utf8_char_len(readbuf[0]);
2785 if(char_len>pos) {
2786 if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2787 pos += num_read;
2790 if(readbuf[0] == '\n')
2791 fdinfo->wxflag |= WX_READNL;
2792 else
2793 fdinfo->wxflag &= ~WX_READNL;
2795 if(readbuf[0] == 0x1a) {
2796 fdinfo->wxflag |= WX_ATEOF;
2797 return 0;
2800 if(readbuf[0] == '\r') {
2801 if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2802 buf[0] = '\r';
2803 else if(lookahead == '\n')
2804 buf[0] = '\n';
2805 else {
2806 buf[0] = '\r';
2807 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2808 fdinfo->lookahead[0] = lookahead;
2809 else
2810 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2812 return 2;
2815 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2816 msvcrt_set_errno(GetLastError());
2817 return -1;
2820 return num_read*2;
2823 if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2824 if(pos) {
2825 num_read = 0;
2826 }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2827 fdinfo->wxflag |= WX_ATEOF;
2828 if (readbuf != min_buf) free(readbuf);
2829 return 0;
2830 }else {
2831 msvcrt_set_errno(GetLastError());
2832 if (GetLastError() == ERROR_ACCESS_DENIED)
2833 *_errno() = EBADF;
2834 if (readbuf != min_buf) free(readbuf);
2835 return -1;
2837 }else if(!pos && !num_read) {
2838 fdinfo->wxflag |= WX_ATEOF;
2839 if (readbuf != min_buf) free(readbuf);
2840 return 0;
2843 pos += num_read;
2844 if(readbuf[0] == '\n')
2845 fdinfo->wxflag |= WX_READNL;
2846 else
2847 fdinfo->wxflag &= ~WX_READNL;
2849 /* Find first byte of last character (may be incomplete) */
2850 for(i=pos-1; i>0 && i>pos-4; i--)
2851 if((readbuf[i]&0xc0) != 0x80)
2852 break;
2853 char_len = get_utf8_char_len(readbuf[i]);
2854 if(char_len+i <= pos)
2855 i += char_len;
2857 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2858 if(i < pos)
2859 fdinfo->lookahead[0] = readbuf[i];
2860 if(i+1 < pos)
2861 fdinfo->lookahead[1] = readbuf[i+1];
2862 if(i+2 < pos)
2863 fdinfo->lookahead[2] = readbuf[i+2];
2864 }else if(i < pos) {
2865 SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2867 pos = i;
2869 for(i=0, j=0; i<pos; i++) {
2870 if(readbuf[i] == 0x1a) {
2871 fdinfo->wxflag |= WX_ATEOF;
2872 break;
2875 /* strip '\r' if followed by '\n' */
2876 if(readbuf[i] == '\r' && i+1==pos) {
2877 if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2878 readbuf[j++] = '\r';
2879 }else if(lookahead == '\n' && j==0) {
2880 readbuf[j++] = '\n';
2881 }else {
2882 if(lookahead != '\n')
2883 readbuf[j++] = '\r';
2885 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2886 fdinfo->lookahead[0] = lookahead;
2887 else
2888 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2890 }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2891 readbuf[j++] = readbuf[i];
2894 pos = j;
2896 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2897 msvcrt_set_errno(GetLastError());
2898 if (readbuf != min_buf) free(readbuf);
2899 return -1;
2902 if (readbuf != min_buf) free(readbuf);
2903 return num_read*2;
2906 /*********************************************************************
2907 * (internal) read_i
2909 * When reading \r as last character in text mode, read() positions
2910 * the file pointer on the \r character while getc() goes on to
2911 * the following \n
2913 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2915 DWORD num_read, utf16;
2916 char *bufstart = buf;
2918 if (count == 0)
2919 return 0;
2921 if (fdinfo->wxflag & WX_ATEOF) {
2922 TRACE("already at EOF, returning 0\n");
2923 return 0;
2925 /* Don't trace small reads, it gets *very* annoying */
2926 if (count > 4)
2927 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2928 if (fdinfo->handle == INVALID_HANDLE_VALUE)
2930 *_errno() = EBADF;
2931 return -1;
2934 utf16 = ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF16LE;
2935 if (ioinfo_get_textmode(fdinfo) != TEXTMODE_ANSI && count&1)
2937 *_errno() = EINVAL;
2938 return -1;
2941 if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_UTF8)
2942 return read_utf8(fdinfo, buf, count);
2944 if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2946 if (fdinfo->lookahead[0] != '\n')
2948 bufstart[0] = fdinfo->lookahead[0];
2949 fdinfo->lookahead[0] = '\n';
2951 if (utf16)
2953 bufstart[1] = fdinfo->lookahead[1];
2954 fdinfo->lookahead[1] = '\n';
2957 if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2958 num_read += 1+utf16;
2959 else
2960 num_read = 1+utf16;
2963 if(utf16 && (num_read&1))
2965 /* msvcr90 uses uninitialized value from the buffer in this case */
2966 /* msvcrt ignores additional data */
2967 ERR("got odd number of bytes in UTF16 mode\n");
2968 num_read--;
2971 if (count != 0 && num_read == 0)
2973 fdinfo->wxflag |= WX_ATEOF;
2974 TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2976 else if (fdinfo->wxflag & WX_TEXT)
2978 DWORD i, j;
2980 if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2981 fdinfo->wxflag |= WX_READNL;
2982 else
2983 fdinfo->wxflag &= ~WX_READNL;
2985 for (i=0, j=0; i<num_read; i+=1+utf16)
2987 /* in text mode, a ctrl-z signals EOF */
2988 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2990 fdinfo->wxflag |= WX_ATEOF;
2991 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2992 break;
2995 /* in text mode, strip \r if followed by \n */
2996 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2998 char lookahead[2];
2999 DWORD len;
3001 lookahead[1] = '\n';
3002 if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
3004 if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
3006 bufstart[j++] = '\n';
3007 if(utf16) bufstart[j++] = 0;
3009 else
3011 if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
3013 bufstart[j++] = '\r';
3014 if(utf16) bufstart[j++] = 0;
3017 if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
3019 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
3021 bufstart[j++] = '\n';
3022 if (utf16) bufstart[j++] = 0;
3024 else
3026 fdinfo->lookahead[0] = lookahead[0];
3027 fdinfo->lookahead[1] = lookahead[1];
3030 else
3031 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
3034 else
3036 bufstart[j++] = '\r';
3037 if(utf16) bufstart[j++] = 0;
3040 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
3041 || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
3043 bufstart[j++] = bufstart[i];
3044 if(utf16) bufstart[j++] = bufstart[i+1];
3047 num_read = j;
3050 else
3052 if (GetLastError() == ERROR_BROKEN_PIPE)
3054 TRACE(":end-of-pipe\n");
3055 fdinfo->wxflag |= WX_ATEOF;
3056 return 0;
3058 else
3060 TRACE(":failed-last error (%ld)\n", GetLastError());
3061 msvcrt_set_errno(GetLastError());
3062 if (GetLastError() == ERROR_ACCESS_DENIED)
3063 *_errno() = EBADF;
3064 return -1;
3068 if (count > 4)
3069 TRACE("(%lu), %s\n", num_read, debugstr_an(buf, num_read));
3070 return num_read;
3073 /*********************************************************************
3074 * _read (MSVCRT.@)
3076 int CDECL _read(int fd, void *buf, unsigned int count)
3078 ioinfo *info;
3079 int num_read;
3081 if(fd == MSVCRT_NO_CONSOLE_FD) {
3082 *_errno() = EBADF;
3083 return -1;
3086 info = get_ioinfo(fd);
3087 num_read = read_i(fd, info, buf, count);
3088 release_ioinfo(info);
3089 return num_read;
3092 /*********************************************************************
3093 * _setmode (MSVCRT.@)
3095 int CDECL _setmode(int fd,int mode)
3097 ioinfo *info = get_ioinfo(fd);
3098 int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
3100 if(ret==_O_TEXT && ioinfo_get_textmode(info) != TEXTMODE_ANSI)
3101 ret = _O_WTEXT;
3103 if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
3104 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
3105 *_errno() = EINVAL;
3106 release_ioinfo(info);
3107 return -1;
3110 if(info == &MSVCRT___badioinfo) {
3111 *_errno() = EBADF;
3112 return EOF;
3115 if(mode == _O_BINARY) {
3116 info->wxflag &= ~WX_TEXT;
3117 ioinfo_set_textmode(info, TEXTMODE_ANSI);
3118 release_ioinfo(info);
3119 return ret;
3122 info->wxflag |= WX_TEXT;
3123 if(mode == _O_TEXT)
3124 ioinfo_set_textmode(info, TEXTMODE_ANSI);
3125 else if(mode == _O_U8TEXT)
3126 ioinfo_set_textmode(info, TEXTMODE_UTF8);
3127 else
3128 ioinfo_set_textmode(info, TEXTMODE_UTF16LE);
3130 release_ioinfo(info);
3131 return ret;
3134 /*********************************************************************
3135 * _stat64 (MSVCRT.@)
3137 int CDECL _stat64(const char* path, struct _stat64 * buf)
3139 DWORD dw;
3140 WIN32_FILE_ATTRIBUTE_DATA hfi;
3141 unsigned short mode = ALL_S_IREAD;
3142 int plen;
3144 TRACE(":file (%s) buf(%p)\n", path, buf);
3146 plen = strlen(path);
3147 while (plen && path[plen-1]==' ')
3148 plen--;
3150 if (plen==2 && path[1]==':')
3152 *_errno() = ENOENT;
3153 return -1;
3156 #if _MSVCR_VER<140
3157 if (plen>=2 && path[plen-2]!=':' && (path[plen-1]=='\\' || path[plen-1]=='/'))
3159 *_errno() = ENOENT;
3160 return -1;
3162 #endif
3164 if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
3166 TRACE("failed (%ld)\n", GetLastError());
3167 *_errno() = ENOENT;
3168 return -1;
3171 memset(buf,0,sizeof(struct _stat64));
3173 /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
3174 Bon 011120: This FIXME seems incorrect
3175 Also a letter as first char isn't enough to be classified
3176 as a drive letter
3178 if (isalpha(*path)&& (*(path+1)==':'))
3179 buf->st_dev = buf->st_rdev = _toupper_l(*path, NULL) - 'A'; /* drive num */
3180 else
3181 buf->st_dev = buf->st_rdev = _getdrive() - 1;
3183 /* Dir, or regular file? */
3184 if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3185 mode |= (_S_IFDIR | ALL_S_IEXEC);
3186 else
3188 mode |= _S_IFREG;
3189 /* executable? */
3190 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
3192 unsigned int ext = _tolower_l(path[plen-1], NULL) |
3193 (_tolower_l(path[plen-2], NULL) << 8) |
3194 (_tolower_l(path[plen-3], NULL) << 16);
3195 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
3196 mode |= ALL_S_IEXEC;
3200 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
3201 mode |= ALL_S_IWRITE;
3203 buf->st_mode = mode;
3204 buf->st_nlink = 1;
3205 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
3206 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
3207 buf->st_atime = dw;
3208 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
3209 buf->st_mtime = buf->st_ctime = dw;
3210 TRACE("%d %d %#I64x %I64d %I64d %I64d\n", buf->st_mode, buf->st_nlink,
3211 buf->st_size, buf->st_atime, buf->st_mtime, buf->st_ctime);
3212 return 0;
3215 /*********************************************************************
3216 * _stati64 (MSVCRT.@)
3218 int CDECL _stati64(const char* path, struct _stati64 * buf)
3220 int ret;
3221 struct _stat64 buf64;
3223 ret = _stat64(path, &buf64);
3224 if (!ret)
3225 msvcrt_stat64_to_stati64(&buf64, buf);
3226 return ret;
3229 /*********************************************************************
3230 * _stat (MSVCRT.@)
3232 int CDECL _stat(const char* path, struct _stat * buf)
3234 int ret;
3235 struct _stat64 buf64;
3237 ret = _stat64( path, &buf64);
3238 if (!ret)
3239 msvcrt_stat64_to_stat(&buf64, buf);
3240 return ret;
3243 #if _MSVCR_VER >= 80
3245 /*********************************************************************
3246 * _stat32 (MSVCR80.@)
3248 int CDECL _stat32(const char *path, struct _stat32 *buf)
3250 int ret;
3251 struct _stat64 buf64;
3253 ret = _stat64(path, &buf64);
3254 if (!ret)
3255 msvcrt_stat64_to_stat32(&buf64, buf);
3256 return ret;
3259 /*********************************************************************
3260 * _stat32i64 (MSVCR80.@)
3262 int CDECL _stat32i64(const char *path, struct _stat32i64 *buf)
3264 int ret;
3265 struct _stat64 buf64;
3267 ret = _stat64(path, &buf64);
3268 if (!ret)
3269 msvcrt_stat64_to_stat32i64(&buf64, buf);
3270 return ret;
3273 /*********************************************************************
3274 * _stat64i32 (MSVCR80.@)
3276 int CDECL _stat64i32(const char* path, struct _stat64i32 *buf)
3278 int ret;
3279 struct _stat64 buf64;
3281 ret = _stat64(path, &buf64);
3282 if (!ret)
3283 msvcrt_stat64_to_stat64i32(&buf64, buf);
3284 return ret;
3287 #endif /* _MSVCR_VER >= 80 */
3289 /*********************************************************************
3290 * _wstat64 (MSVCRT.@)
3292 int CDECL _wstat64(const wchar_t* path, struct _stat64 * buf)
3294 DWORD dw;
3295 WIN32_FILE_ATTRIBUTE_DATA hfi;
3296 unsigned short mode = ALL_S_IREAD;
3297 int plen;
3299 TRACE(":file (%s) buf(%p)\n", debugstr_w(path), buf);
3301 plen = wcslen(path);
3302 while (plen && path[plen-1]==' ')
3303 plen--;
3305 if (plen==2 && path[1]==':')
3307 *_errno() = ENOENT;
3308 return -1;
3311 #if _MSVCR_VER<140
3312 if (plen>=2 && path[plen-2]!=':' && (path[plen-1]=='\\' || path[plen-1]=='/'))
3314 *_errno() = ENOENT;
3315 return -1;
3317 #endif
3319 if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
3321 TRACE("failed (%ld)\n", GetLastError());
3322 *_errno() = ENOENT;
3323 return -1;
3326 memset(buf,0,sizeof(struct _stat64));
3328 /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
3329 if (iswalpha(*path) && path[1] == ':')
3330 buf->st_dev = buf->st_rdev = towupper(*path) - 'A'; /* drive num */
3331 else
3332 buf->st_dev = buf->st_rdev = _getdrive() - 1;
3334 /* Dir, or regular file? */
3335 if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3336 mode |= (_S_IFDIR | ALL_S_IEXEC);
3337 else
3339 mode |= _S_IFREG;
3340 /* executable? */
3341 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
3343 ULONGLONG ext = towlower(path[plen-1]) | (towlower(path[plen-2]) << 16) |
3344 ((ULONGLONG)towlower(path[plen-3]) << 32);
3345 if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
3346 mode |= ALL_S_IEXEC;
3350 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
3351 mode |= ALL_S_IWRITE;
3353 buf->st_mode = mode;
3354 buf->st_nlink = 1;
3355 buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
3356 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
3357 buf->st_atime = dw;
3358 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
3359 buf->st_mtime = buf->st_ctime = dw;
3360 TRACE("%d %d %#I64x %I64d %I64d %I64d\n", buf->st_mode, buf->st_nlink,
3361 buf->st_size, buf->st_atime, buf->st_mtime, buf->st_ctime);
3362 return 0;
3365 /*********************************************************************
3366 * _wstati64 (MSVCRT.@)
3368 int CDECL _wstati64(const wchar_t* path, struct _stati64 * buf)
3370 int ret;
3371 struct _stat64 buf64;
3373 ret = _wstat64(path, &buf64);
3374 if (!ret)
3375 msvcrt_stat64_to_stati64(&buf64, buf);
3376 return ret;
3379 /*********************************************************************
3380 * _wstat (MSVCRT.@)
3382 int CDECL _wstat(const wchar_t* path, struct _stat * buf)
3384 int ret;
3385 struct _stat64 buf64;
3387 ret = _wstat64( path, &buf64 );
3388 if (!ret) msvcrt_stat64_to_stat(&buf64, buf);
3389 return ret;
3392 #if _MSVCR_VER >= 80
3394 /*********************************************************************
3395 * _wstat32 (MSVCR80.@)
3397 int CDECL _wstat32(const wchar_t *path, struct _stat32 *buf)
3399 int ret;
3400 struct _stat64 buf64;
3402 ret = _wstat64(path, &buf64);
3403 if (!ret)
3404 msvcrt_stat64_to_stat32(&buf64, buf);
3405 return ret;
3408 /*********************************************************************
3409 * _wstat32i64 (MSVCR80.@)
3411 int CDECL _wstat32i64(const wchar_t *path, struct _stat32i64 *buf)
3413 int ret;
3414 struct _stat64 buf64;
3416 ret = _wstat64(path, &buf64);
3417 if (!ret)
3418 msvcrt_stat64_to_stat32i64(&buf64, buf);
3419 return ret;
3422 /*********************************************************************
3423 * _wstat64i32 (MSVCR80.@)
3425 int CDECL _wstat64i32(const wchar_t *path, struct _stat64i32 *buf)
3427 int ret;
3428 struct _stat64 buf64;
3430 ret = _wstat64(path, &buf64);
3431 if (!ret)
3432 msvcrt_stat64_to_stat64i32(&buf64, buf);
3433 return ret;
3436 #endif /* _MSVCR_VER >= 80 */
3438 /*********************************************************************
3439 * _tell (MSVCRT.@)
3441 __msvcrt_long CDECL _tell(int fd)
3443 return _lseek(fd, 0, SEEK_CUR);
3446 /*********************************************************************
3447 * _telli64 (MSVCRT.@)
3449 __int64 CDECL _telli64(int fd)
3451 return _lseeki64(fd, 0, SEEK_CUR);
3454 /*********************************************************************
3455 * _tempnam (MSVCRT.@)
3457 char * CDECL _tempnam(const char *dir, const char *prefix)
3459 char tmpbuf[MAX_PATH];
3460 const char *tmp_dir = getenv("TMP");
3462 if (tmp_dir) dir = tmp_dir;
3464 TRACE("dir (%s) prefix (%s)\n", dir, prefix);
3465 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
3467 TRACE("got name (%s)\n", tmpbuf);
3468 DeleteFileA(tmpbuf);
3469 return _strdup(tmpbuf);
3471 TRACE("failed (%ld)\n", GetLastError());
3472 return NULL;
3475 /*********************************************************************
3476 * _wtempnam (MSVCRT.@)
3478 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
3480 wchar_t tmpbuf[MAX_PATH];
3481 const wchar_t *tmp_dir = _wgetenv(L"TMP");
3483 if (tmp_dir) dir = tmp_dir;
3485 TRACE("dir (%s) prefix (%s)\n", debugstr_w(dir), debugstr_w(prefix));
3486 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
3488 TRACE("got name (%s)\n", debugstr_w(tmpbuf));
3489 DeleteFileW(tmpbuf);
3490 return _wcsdup(tmpbuf);
3492 TRACE("failed (%ld)\n", GetLastError());
3493 return NULL;
3496 /*********************************************************************
3497 * _umask (MSVCRT.@)
3499 int CDECL _umask(int umask)
3501 int old_umask = MSVCRT_umask;
3502 TRACE("(%d)\n",umask);
3503 MSVCRT_umask = umask;
3504 return old_umask;
3507 /*********************************************************************
3508 * _utime64 (MSVCRT.@)
3510 int CDECL _utime64(const char* path, struct __utimbuf64 *t)
3512 int fd = _open(path, _O_WRONLY | _O_BINARY);
3514 if (fd > 0)
3516 int retVal = _futime64(fd, t);
3517 _close(fd);
3518 return retVal;
3520 return -1;
3523 /*********************************************************************
3524 * _utime32 (MSVCRT.@)
3526 int CDECL _utime32(const char* path, struct __utimbuf32 *t)
3528 if (t)
3530 struct __utimbuf64 t64;
3531 t64.actime = t->actime;
3532 t64.modtime = t->modtime;
3533 return _utime64( path, &t64 );
3535 else
3536 return _utime64( path, NULL );
3539 /*********************************************************************
3540 * _wutime64 (MSVCRT.@)
3542 int CDECL _wutime64(const wchar_t* path, struct __utimbuf64 *t)
3544 int fd = _wopen(path, _O_WRONLY | _O_BINARY);
3546 if (fd > 0)
3548 int retVal = _futime64(fd, t);
3549 _close(fd);
3550 return retVal;
3552 return -1;
3555 /*********************************************************************
3556 * _wutime32 (MSVCRT.@)
3558 int CDECL _wutime32(const wchar_t* path, struct __utimbuf32 *t)
3560 if (t)
3562 struct __utimbuf64 t64;
3563 t64.actime = t->actime;
3564 t64.modtime = t->modtime;
3565 return _wutime64( path, &t64 );
3567 else
3568 return _wutime64( path, NULL );
3571 /*********************************************************************
3572 * _write (MSVCRT.@)
3574 int CDECL _write(int fd, const void* buf, unsigned int count)
3576 ioinfo *info = get_ioinfo(fd);
3577 HANDLE hand = info->handle;
3578 DWORD num_written, i;
3579 BOOL console = FALSE;
3581 if (hand == INVALID_HANDLE_VALUE || fd == MSVCRT_NO_CONSOLE_FD)
3583 *_errno() = EBADF;
3584 release_ioinfo(info);
3585 return -1;
3588 if (ioinfo_get_textmode(info) != TEXTMODE_ANSI && count&1)
3590 *_errno() = EINVAL;
3591 release_ioinfo(info);
3592 return -1;
3595 /* If appending, go to EOF */
3596 if (info->wxflag & WX_APPEND)
3597 _lseek(fd, 0, FILE_END);
3599 if (!(info->wxflag & WX_TEXT))
3601 if (!WriteFile(hand, buf, count, &num_written, NULL)
3602 || num_written != count)
3604 TRACE("WriteFile (fd %d, hand %p) failed-last error (%ld)\n", fd,
3605 hand, GetLastError());
3606 msvcrt_set_errno(GetLastError());
3607 if (GetLastError() == ERROR_ACCESS_DENIED)
3608 *_errno() = EBADF;
3609 num_written = -1;
3612 release_ioinfo(info);
3613 return num_written;
3616 if (_isatty(fd)) console = VerifyConsoleIoHandle(hand);
3617 for (i = 0; i < count;)
3619 const char *s = buf;
3620 char lfbuf[2048];
3621 DWORD j = 0;
3623 if (ioinfo_get_textmode(info) == TEXTMODE_ANSI && console)
3625 char conv[sizeof(lfbuf)];
3626 size_t len = 0;
3628 #if _MSVCR_VER >= 80
3629 if (info->dbcsBufferUsed)
3631 conv[j++] = info->dbcsBuffer[0];
3632 info->dbcsBufferUsed = FALSE;
3633 conv[j++] = s[i++];
3634 len++;
3636 #endif
3638 for (; i < count && j < sizeof(conv)-1 &&
3639 len < (sizeof(lfbuf) - 1) / sizeof(WCHAR); i++, j++, len++)
3641 if (isleadbyte((unsigned char)s[i]))
3643 conv[j++] = s[i++];
3645 if (i == count)
3647 #if _MSVCR_VER >= 80
3648 info->dbcsBuffer[0] = conv[j-1];
3649 info->dbcsBufferUsed = TRUE;
3650 break;
3651 #else
3652 *_errno() = EINVAL;
3653 release_ioinfo(info);
3654 return -1;
3655 #endif
3658 else if (s[i] == '\n')
3660 conv[j++] = '\r';
3661 len++;
3663 conv[j] = s[i];
3666 len = mbstowcs((WCHAR*)lfbuf, conv, len);
3667 if (len == -1)
3669 msvcrt_set_errno(GetLastError());
3670 release_ioinfo(info);
3671 return -1;
3673 j = len * 2;
3675 else if (ioinfo_get_textmode(info) == TEXTMODE_ANSI)
3677 for (j = 0; i < count && j < sizeof(lfbuf)-1; i++, j++)
3679 if (s[i] == '\n')
3680 lfbuf[j++] = '\r';
3681 lfbuf[j] = s[i];
3684 else if (ioinfo_get_textmode(info) == TEXTMODE_UTF16LE || console)
3686 for (j = 0; i < count && j < sizeof(lfbuf)-3; i++, j++)
3688 if (s[i] == '\n' && !s[i+1])
3690 lfbuf[j++] = '\r';
3691 lfbuf[j++] = 0;
3693 lfbuf[j++] = s[i++];
3694 lfbuf[j] = s[i];
3697 else
3699 char conv[sizeof(lfbuf)/4];
3701 for (j = 0; i < count && j < sizeof(conv)-3; i++, j++)
3703 if (s[i] == '\n' && !s[i+1])
3705 conv[j++] = '\r';
3706 conv[j++] = 0;
3708 conv[j++] = s[i++];
3709 conv[j] = s[i];
3712 j = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)conv, j/2, lfbuf, sizeof(lfbuf), NULL, NULL);
3713 if (!j)
3715 msvcrt_set_errno(GetLastError());
3716 release_ioinfo(info);
3717 return -1;
3721 if (console)
3723 j = j/2;
3724 if (!WriteConsoleW(hand, lfbuf, j, &num_written, NULL))
3725 num_written = -1;
3727 else if (!WriteFile(hand, lfbuf, j, &num_written, NULL))
3729 num_written = -1;
3732 if (num_written != j)
3734 TRACE("WriteFile/WriteConsoleW (fd %d, hand %p) failed-last error (%ld)\n", fd,
3735 hand, GetLastError());
3736 msvcrt_set_errno(GetLastError());
3737 if (GetLastError() == ERROR_ACCESS_DENIED)
3738 *_errno() = EBADF;
3739 release_ioinfo(info);
3740 return -1;
3744 release_ioinfo(info);
3745 return count;
3748 /*********************************************************************
3749 * _putw (MSVCRT.@)
3751 int CDECL _putw(int val, FILE* file)
3753 int len;
3755 _lock_file(file);
3756 len = _write(file->_file, &val, sizeof(val));
3757 if (len == sizeof(val)) {
3758 _unlock_file(file);
3759 return val;
3762 file->_flag |= _IOERR;
3763 _unlock_file(file);
3764 return EOF;
3767 /*********************************************************************
3768 * fclose (MSVCRT.@)
3770 int CDECL fclose(FILE* file)
3772 int ret;
3774 if (!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3776 _lock_file(file);
3777 ret = _fclose_nolock(file);
3778 _unlock_file(file);
3780 return ret;
3783 /*********************************************************************
3784 * _fclose_nolock (MSVCRT.@)
3786 int CDECL _fclose_nolock(FILE* file)
3788 int r, flag;
3790 if (!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3792 if(!(file->_flag & (_IOREAD | _IOWRT | _IORW)))
3794 file->_flag = 0;
3795 return EOF;
3798 flag = file->_flag;
3799 free(file->_tmpfname);
3800 file->_tmpfname = NULL;
3801 /* flush stdio buffers */
3802 if(file->_flag & _IOWRT)
3803 _fflush_nolock(file);
3804 if(file->_flag & _IOMYBUF)
3805 free(file->_base);
3807 r=_close(file->_file);
3808 file->_flag = 0;
3810 return ((r == -1) || (flag & _IOERR) ? EOF : 0);
3813 /*********************************************************************
3814 * feof (MSVCRT.@)
3816 int CDECL feof(FILE* file)
3818 return file->_flag & _IOEOF;
3821 /*********************************************************************
3822 * ferror (MSVCRT.@)
3824 int CDECL ferror(FILE* file)
3826 return file->_flag & _IOERR;
3829 /*********************************************************************
3830 * _filbuf (MSVCRT.@)
3832 int CDECL _filbuf(FILE* file)
3834 unsigned char c;
3836 if(file->_flag & _IOSTRG)
3837 return EOF;
3839 /* Allocate buffer if needed */
3840 if(!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF)))
3841 msvcrt_alloc_buffer(file);
3843 if(!(file->_flag & _IOREAD)) {
3844 if(file->_flag & _IORW)
3845 file->_flag |= _IOREAD;
3846 else
3847 return EOF;
3850 if(!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF))) {
3851 int r;
3852 if ((r = _read(file->_file,&c,1)) != 1) {
3853 file->_flag |= (r == 0) ? _IOEOF : _IOERR;
3854 return EOF;
3857 return c;
3858 } else {
3859 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
3860 if(file->_cnt<=0) {
3861 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
3862 file->_cnt = 0;
3863 return EOF;
3866 file->_cnt--;
3867 file->_ptr = file->_base+1;
3868 c = *(unsigned char *)file->_base;
3869 return c;
3873 /*********************************************************************
3874 * fgetc (MSVCRT.@)
3876 int CDECL fgetc(FILE* file)
3878 int ret;
3880 _lock_file(file);
3881 ret = _fgetc_nolock(file);
3882 _unlock_file(file);
3884 return ret;
3887 /*********************************************************************
3888 * _fgetc_nolock (MSVCRT.@)
3890 int CDECL _fgetc_nolock(FILE* file)
3892 unsigned char *i;
3893 unsigned int j;
3895 if (file->_cnt>0) {
3896 file->_cnt--;
3897 i = (unsigned char *)file->_ptr++;
3898 j = *i;
3899 } else
3900 j = _filbuf(file);
3902 return j;
3905 /*********************************************************************
3906 * _fgetchar (MSVCRT.@)
3908 int CDECL _fgetchar(void)
3910 return fgetc(MSVCRT_stdin);
3913 /*********************************************************************
3914 * fgets (MSVCRT.@)
3916 char * CDECL fgets(char *s, int size, FILE* file)
3918 int cc = EOF;
3919 char * buf_start = s;
3921 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3922 file,file->_file,s,size);
3924 _lock_file(file);
3926 while ((size >1) && (cc = _fgetc_nolock(file)) != EOF && cc != '\n')
3928 *s++ = (char)cc;
3929 size --;
3931 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
3933 TRACE(":nothing read\n");
3934 _unlock_file(file);
3935 return NULL;
3937 if ((cc != EOF) && (size > 1))
3938 *s++ = cc;
3939 *s = '\0';
3940 TRACE(":got %s\n", debugstr_a(buf_start));
3941 _unlock_file(file);
3942 return buf_start;
3945 /*********************************************************************
3946 * fgetwc (MSVCRT.@)
3948 wint_t CDECL fgetwc(FILE* file)
3950 wint_t ret;
3952 _lock_file(file);
3953 ret = _fgetwc_nolock(file);
3954 _unlock_file(file);
3956 return ret;
3959 /*********************************************************************
3960 * _fgetwc_nolock (MSVCRT.@)
3962 wint_t CDECL _fgetwc_nolock(FILE* file)
3964 wint_t ret;
3965 int ch;
3967 if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI
3968 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3969 char *p;
3971 for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
3972 ch = _fgetc_nolock(file);
3973 if(ch == EOF) {
3974 ret = WEOF;
3975 break;
3977 *p = (char)ch;
3979 }else {
3980 char mbs[MB_LEN_MAX];
3981 int len = 0;
3983 ch = _fgetc_nolock(file);
3984 if(ch != EOF) {
3985 mbs[0] = (char)ch;
3986 if(isleadbyte((unsigned char)mbs[0])) {
3987 ch = _fgetc_nolock(file);
3988 if(ch != EOF) {
3989 mbs[1] = (char)ch;
3990 len = 2;
3992 }else {
3993 len = 1;
3997 if(!len || mbtowc(&ret, mbs, len)==-1)
3998 ret = WEOF;
4001 return ret;
4004 /*********************************************************************
4005 * _getw (MSVCRT.@)
4007 int CDECL _getw(FILE* file)
4009 char *ch;
4010 int i, k;
4011 unsigned int j;
4012 ch = (char *)&i;
4014 _lock_file(file);
4015 for (j=0; j<sizeof(int); j++) {
4016 k = _fgetc_nolock(file);
4017 if (k == EOF) {
4018 file->_flag |= _IOEOF;
4019 _unlock_file(file);
4020 return EOF;
4022 ch[j] = k;
4025 _unlock_file(file);
4026 return i;
4029 /*********************************************************************
4030 * getwc (MSVCRT.@)
4032 wint_t CDECL getwc(FILE* file)
4034 return fgetwc(file);
4037 /*********************************************************************
4038 * _fgetwchar (MSVCRT.@)
4040 wint_t CDECL _fgetwchar(void)
4042 return fgetwc(MSVCRT_stdin);
4045 /*********************************************************************
4046 * getwchar (MSVCRT.@)
4048 wint_t CDECL getwchar(void)
4050 return _fgetwchar();
4053 /*********************************************************************
4054 * fgetws (MSVCRT.@)
4056 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
4058 wint_t cc = WEOF;
4059 wchar_t * buf_start = s;
4061 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
4062 file,file->_file,s,size);
4064 _lock_file(file);
4066 while ((size >1) && (cc = _fgetwc_nolock(file)) != WEOF && cc != '\n')
4068 *s++ = cc;
4069 size --;
4071 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
4073 TRACE(":nothing read\n");
4074 _unlock_file(file);
4075 return NULL;
4077 if ((cc != WEOF) && (size > 1))
4078 *s++ = cc;
4079 *s = 0;
4080 TRACE(":got %s\n", debugstr_w(buf_start));
4081 _unlock_file(file);
4082 return buf_start;
4085 /*********************************************************************
4086 * _flsbuf (MSVCRT.@)
4088 int CDECL _flsbuf(int c, FILE* file)
4090 /* Flush output buffer */
4091 if(!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF))) {
4092 msvcrt_alloc_buffer(file);
4095 if(!(file->_flag & _IOWRT)) {
4096 if(!(file->_flag & _IORW)) {
4097 file->_flag |= _IOERR;
4098 *_errno() = EBADF;
4099 return EOF;
4101 file->_flag |= _IOWRT;
4103 if(file->_flag & _IOREAD) {
4104 if(!(file->_flag & _IOEOF)) {
4105 file->_flag |= _IOERR;
4106 return EOF;
4108 file->_cnt = 0;
4109 file->_ptr = file->_base;
4110 file->_flag &= ~(_IOREAD | _IOEOF);
4113 if(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) {
4114 int res = 0;
4116 if(file->_cnt <= 0) {
4117 res = msvcrt_flush_buffer(file);
4118 if(res)
4119 return res;
4120 file->_flag |= _IOWRT;
4121 file->_cnt=file->_bufsiz;
4123 *file->_ptr++ = c;
4124 file->_cnt--;
4125 return c&0xff;
4126 } else {
4127 unsigned char cc=c;
4128 int len;
4129 /* set _cnt to 0 for unbuffered FILEs */
4130 file->_cnt = 0;
4131 len = _write(file->_file, &cc, 1);
4132 if (len == 1)
4133 return c & 0xff;
4134 file->_flag |= _IOERR;
4135 return EOF;
4139 /*********************************************************************
4140 * fwrite (MSVCRT.@)
4142 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
4144 size_t ret;
4146 _lock_file(file);
4147 ret = _fwrite_nolock(ptr, size, nmemb, file);
4148 _unlock_file(file);
4150 return ret;
4153 /*********************************************************************
4154 * _fwrite_nolock (MSVCRT.@)
4156 size_t CDECL _fwrite_nolock(const void *ptr, size_t size, size_t nmemb, FILE* file)
4158 size_t wrcnt=size * nmemb;
4159 int written = 0;
4160 if (size == 0)
4161 return 0;
4163 while(wrcnt) {
4164 if(file->_cnt < 0) {
4165 WARN("negative file->_cnt value in %p\n", file);
4166 file->_flag |= _IOERR;
4167 break;
4168 } else if(file->_cnt) {
4169 int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
4170 memcpy(file->_ptr, ptr, pcnt);
4171 file->_cnt -= pcnt;
4172 file->_ptr += pcnt;
4173 written += pcnt;
4174 wrcnt -= pcnt;
4175 ptr = (const char*)ptr + pcnt;
4176 } else if((file->_flag & _IONBF)
4177 || ((file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) && wrcnt >= file->_bufsiz)
4178 || (!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
4179 size_t pcnt;
4180 int bufsiz;
4182 if(file->_flag & _IONBF)
4183 bufsiz = 1;
4184 else if(!(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)))
4185 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
4186 else
4187 bufsiz = file->_bufsiz;
4189 pcnt = (wrcnt / bufsiz) * bufsiz;
4191 if(msvcrt_flush_buffer(file) == EOF)
4192 break;
4194 if(_write(file->_file, ptr, pcnt) <= 0) {
4195 file->_flag |= _IOERR;
4196 break;
4198 written += pcnt;
4199 wrcnt -= pcnt;
4200 ptr = (const char*)ptr + pcnt;
4201 } else {
4202 if(_flsbuf(*(const char*)ptr, file) == EOF)
4203 break;
4204 written++;
4205 wrcnt--;
4206 ptr = (const char*)ptr + 1;
4210 return written / size;
4213 /*********************************************************************
4214 * fputwc (MSVCRT.@)
4216 wint_t CDECL fputwc(wint_t wc, FILE* file)
4218 wint_t ret;
4220 _lock_file(file);
4221 ret = _fputwc_nolock(wc, file);
4222 _unlock_file(file);
4224 return ret;
4227 /*********************************************************************
4228 * _fputwc_nolock (MSVCRT.@)
4230 wint_t CDECL _fputwc_nolock(wint_t wc, FILE* file)
4232 wchar_t mwc=wc;
4233 ioinfo *fdinfo;
4234 wint_t ret;
4236 fdinfo = get_ioinfo_nolock(file->_file);
4238 if((fdinfo->wxflag&WX_TEXT) && ioinfo_get_textmode(fdinfo) == TEXTMODE_ANSI) {
4239 char buf[MB_LEN_MAX];
4240 int char_len;
4242 char_len = wctomb(buf, mwc);
4243 if(char_len!=-1 && _fwrite_nolock(buf, char_len, 1, file)==1)
4244 ret = wc;
4245 else
4246 ret = WEOF;
4247 }else if(_fwrite_nolock(&mwc, sizeof(mwc), 1, file) == 1) {
4248 ret = wc;
4249 }else {
4250 ret = WEOF;
4253 return ret;
4256 /*********************************************************************
4257 * _fputwchar (MSVCRT.@)
4259 wint_t CDECL _fputwchar(wint_t wc)
4261 return fputwc(wc, MSVCRT_stdout);
4264 /*********************************************************************
4265 * _wfsopen (MSVCRT.@)
4267 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
4269 FILE* file;
4270 int open_flags, stream_flags, fd;
4272 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
4274 /* map mode string to open() flags. "man fopen" for possibilities. */
4275 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
4276 return NULL;
4278 LOCK_FILES();
4279 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
4280 if (fd < 0)
4281 file = NULL;
4282 else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
4283 != -1)
4284 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
4285 else if (file)
4287 file->_flag = 0;
4288 file = NULL;
4291 TRACE(":got (%p)\n",file);
4292 if (fd >= 0 && !file)
4293 _close(fd);
4294 UNLOCK_FILES();
4295 return file;
4298 /*********************************************************************
4299 * _fsopen (MSVCRT.@)
4301 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
4303 FILE *ret;
4304 wchar_t *pathW = NULL, *modeW = NULL;
4306 if (path && !(pathW = msvcrt_wstrdupa(path))) {
4307 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4308 *_errno() = EINVAL;
4309 return NULL;
4311 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
4313 free(pathW);
4314 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4315 *_errno() = EINVAL;
4316 return NULL;
4319 ret = _wfsopen(pathW, modeW, share);
4321 free(pathW);
4322 free(modeW);
4323 return ret;
4326 /*********************************************************************
4327 * fopen (MSVCRT.@)
4329 FILE * CDECL fopen(const char *path, const char *mode)
4331 return _fsopen( path, mode, _SH_DENYNO );
4334 /*********************************************************************
4335 * fopen_s (MSVCRT.@)
4337 int CDECL fopen_s(FILE** pFile,
4338 const char *filename, const char *mode)
4340 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4341 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
4342 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4344 *pFile = fopen(filename, mode);
4346 if(!*pFile)
4347 return *_errno();
4348 return 0;
4351 /*********************************************************************
4352 * _wfopen (MSVCRT.@)
4354 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
4356 return _wfsopen( path, mode, _SH_DENYNO );
4359 /*********************************************************************
4360 * _wfopen_s (MSVCRT.@)
4362 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
4363 const wchar_t *mode)
4365 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4366 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
4367 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4369 *pFile = _wfopen(filename, mode);
4371 if(!*pFile)
4372 return *_errno();
4373 return 0;
4376 /*********************************************************************
4377 * fputc (MSVCRT.@)
4379 int CDECL fputc(int c, FILE* file)
4381 int ret;
4383 _lock_file(file);
4384 ret = _fputc_nolock(c, file);
4385 _unlock_file(file);
4387 return ret;
4390 /*********************************************************************
4391 * _fputc_nolock (MSVCRT.@)
4393 int CDECL _fputc_nolock(int c, FILE* file)
4395 int res;
4397 if(file->_cnt>0) {
4398 *file->_ptr++=c;
4399 file->_cnt--;
4400 if (c == '\n')
4402 res = msvcrt_flush_buffer(file);
4403 return res ? res : c;
4405 else {
4406 return c & 0xff;
4408 } else {
4409 res = _flsbuf(c, file);
4410 return res;
4414 /*********************************************************************
4415 * _fputchar (MSVCRT.@)
4417 int CDECL _fputchar(int c)
4419 return fputc(c, MSVCRT_stdout);
4422 /*********************************************************************
4423 * fread (MSVCRT.@)
4425 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
4427 size_t ret;
4429 _lock_file(file);
4430 ret = _fread_nolock(ptr, size, nmemb, file);
4431 _unlock_file(file);
4433 return ret;
4436 /*********************************************************************
4437 * _fread_nolock (MSVCRT.@)
4439 size_t CDECL _fread_nolock(void *ptr, size_t size, size_t nmemb, FILE* file)
4441 size_t rcnt=size * nmemb;
4442 size_t read=0;
4443 size_t pread=0;
4445 if(!rcnt)
4446 return 0;
4448 /* first buffered data */
4449 if(file->_cnt>0) {
4450 int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
4451 memcpy(ptr, file->_ptr, pcnt);
4452 file->_cnt -= pcnt;
4453 file->_ptr += pcnt;
4454 read += pcnt ;
4455 rcnt -= pcnt ;
4456 ptr = (char*)ptr + pcnt;
4457 } else if(!(file->_flag & _IOREAD )) {
4458 if(file->_flag & _IORW) {
4459 file->_flag |= _IOREAD;
4460 } else {
4461 return 0;
4465 if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF)))
4466 msvcrt_alloc_buffer(file);
4468 while(rcnt>0)
4470 int i;
4471 if (!file->_cnt && rcnt<file->_bufsiz && (file->_flag & (_IOMYBUF | MSVCRT__USERBUF))) {
4472 i = _read(file->_file, file->_base, file->_bufsiz);
4473 file->_ptr = file->_base;
4474 if (i != -1) {
4475 file->_cnt = i;
4476 if (i > rcnt) i = rcnt;
4478 /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
4479 if (i > 0 && i < file->_cnt) {
4480 get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF;
4481 file->_flag &= ~_IOEOF;
4483 if (i > 0) {
4484 memcpy(ptr, file->_ptr, i);
4485 file->_cnt -= i;
4486 file->_ptr += i;
4488 } else if (rcnt > INT_MAX) {
4489 i = _read(file->_file, ptr, INT_MAX);
4490 } else if (rcnt < (file->_bufsiz ? file->_bufsiz : MSVCRT_INTERNAL_BUFSIZ)) {
4491 i = _read(file->_file, ptr, rcnt);
4492 } else {
4493 i = _read(file->_file, ptr, rcnt - rcnt % (file->_bufsiz ? file->_bufsiz : MSVCRT_INTERNAL_BUFSIZ));
4495 pread += i;
4496 rcnt -= i;
4497 ptr = (char *)ptr+i;
4498 /* expose feof condition in the flags
4499 * MFC tests file->_flag for feof, and doesn't call feof())
4501 if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF)
4502 file->_flag |= _IOEOF;
4503 else if (i == -1)
4505 file->_flag |= _IOERR;
4506 pread = 0;
4507 rcnt = 0;
4509 if (i < 1) break;
4511 read+=pread;
4512 return read / size;
4515 #if _MSVCR_VER >= 80
4517 /*********************************************************************
4518 * fread_s (MSVCR80.@)
4520 size_t CDECL fread_s(void *buf, size_t buf_size, size_t elem_size,
4521 size_t count, FILE *stream)
4523 size_t ret;
4525 if(!MSVCRT_CHECK_PMT(stream != NULL)) {
4526 if(buf && buf_size)
4527 memset(buf, 0, buf_size);
4528 return 0;
4530 if(!elem_size || !count) return 0;
4532 _lock_file(stream);
4533 ret = _fread_nolock_s(buf, buf_size, elem_size, count, stream);
4534 _unlock_file(stream);
4536 return ret;
4539 /*********************************************************************
4540 * _fread_nolock_s (MSVCR80.@)
4542 size_t CDECL _fread_nolock_s(void *buf, size_t buf_size, size_t elem_size,
4543 size_t count, FILE *stream)
4545 size_t bytes_left, buf_pos;
4547 TRACE("(%p %Iu %Iu %Iu %p)\n", buf, buf_size, elem_size, count, stream);
4549 if(!MSVCRT_CHECK_PMT(stream != NULL)) {
4550 if(buf && buf_size)
4551 memset(buf, 0, buf_size);
4552 return 0;
4554 if(!elem_size || !count) return 0;
4555 if(!MSVCRT_CHECK_PMT(buf != NULL)) return 0;
4556 if(!MSVCRT_CHECK_PMT(SIZE_MAX/count >= elem_size)) return 0;
4558 bytes_left = elem_size*count;
4559 buf_pos = 0;
4560 while(bytes_left) {
4561 if(stream->_cnt > 0) {
4562 size_t size = bytes_left<stream->_cnt ? bytes_left : stream->_cnt;
4564 if(!MSVCRT_CHECK_PMT_ERR(size <= buf_size-buf_pos, ERANGE)) {
4565 memset(buf, 0, buf_size);
4566 return 0;
4569 _fread_nolock((char*)buf+buf_pos, 1, size, stream);
4570 buf_pos += size;
4571 bytes_left -= size;
4572 }else {
4573 int c = _filbuf(stream);
4575 if(c == EOF)
4576 break;
4578 if(!MSVCRT_CHECK_PMT_ERR(buf_size != buf_pos, ERANGE)) {
4579 memset(buf, 0, buf_size);
4580 return 0;
4583 ((char*)buf)[buf_pos++] = c;
4584 bytes_left--;
4588 return buf_pos/elem_size;
4591 #endif /* _MSVCR_VER >= 80 */
4593 /*********************************************************************
4594 * _wfreopen (MSVCRT.@)
4597 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
4599 int open_flags, stream_flags, fd;
4601 TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
4603 LOCK_FILES();
4604 if (file)
4606 fclose(file);
4607 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
4608 file = NULL;
4609 else if((fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE)) < 0)
4610 file = NULL;
4611 else if(msvcrt_init_fp(file, fd, stream_flags) == -1)
4613 file->_flag = 0;
4614 file = NULL;
4617 UNLOCK_FILES();
4618 return file;
4621 /*********************************************************************
4622 * _wfreopen_s (MSVCRT.@)
4624 int CDECL _wfreopen_s(FILE** pFile,
4625 const wchar_t *path, const wchar_t *mode, FILE* file)
4627 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4628 if (!MSVCRT_CHECK_PMT(path != NULL)) return EINVAL;
4629 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4630 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
4632 *pFile = _wfreopen(path, mode, file);
4634 if(!*pFile)
4635 return *_errno();
4636 return 0;
4639 /*********************************************************************
4640 * freopen (MSVCRT.@)
4643 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
4645 FILE *ret;
4646 wchar_t *pathW = NULL, *modeW = NULL;
4648 if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
4649 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
4651 free(pathW);
4652 return NULL;
4655 ret = _wfreopen(pathW, modeW, file);
4657 free(pathW);
4658 free(modeW);
4659 return ret;
4662 /*********************************************************************
4663 * freopen_s (MSVCRT.@)
4665 errno_t CDECL freopen_s(FILE** pFile,
4666 const char *path, const char *mode, FILE* file)
4668 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
4669 if (!MSVCRT_CHECK_PMT(path != NULL)) return EINVAL;
4670 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
4671 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
4673 *pFile = freopen(path, mode, file);
4675 if(!*pFile)
4676 return *_errno();
4677 return 0;
4680 /*********************************************************************
4681 * fsetpos (MSVCRT.@)
4683 int CDECL fsetpos(FILE* file, fpos_t *pos)
4685 return _fseeki64(file,*pos,SEEK_SET);
4688 /*********************************************************************
4689 * _ftelli64 (MSVCRT.@)
4691 __int64 CDECL _ftelli64(FILE* file)
4693 __int64 ret;
4695 _lock_file(file);
4696 ret = _ftelli64_nolock(file);
4697 _unlock_file(file);
4699 return ret;
4702 /*********************************************************************
4703 * _ftelli64_nolock (MSVCRT.@)
4705 __int64 CDECL _ftelli64_nolock(FILE* file)
4707 __int64 pos;
4709 pos = _telli64(file->_file);
4710 if(pos == -1)
4711 return -1;
4712 if(file->_flag & (_IOMYBUF | MSVCRT__USERBUF)) {
4713 if(file->_flag & _IOWRT) {
4714 pos += file->_ptr - file->_base;
4716 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4717 char *p;
4719 for(p=file->_base; p<file->_ptr; p++)
4720 if(*p == '\n')
4721 pos++;
4723 } else if(!file->_cnt) { /* nothing to do */
4724 } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
4725 int i;
4727 pos -= file->_cnt;
4728 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4729 for(i=0; i<file->_cnt; i++)
4730 if(file->_ptr[i] == '\n')
4731 pos--;
4733 } else {
4734 char *p;
4736 if(_lseeki64(file->_file, pos, SEEK_SET) != pos)
4737 return -1;
4739 pos -= file->_bufsiz;
4740 pos += file->_ptr - file->_base;
4742 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
4743 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL)
4744 pos--;
4746 for(p=file->_base; p<file->_ptr; p++)
4747 if(*p == '\n')
4748 pos++;
4753 return pos;
4756 /*********************************************************************
4757 * ftell (MSVCRT.@)
4759 __msvcrt_long CDECL ftell(FILE* file)
4761 return _ftelli64(file);
4764 #if _MSVCR_VER >= 80
4765 /*********************************************************************
4766 * _ftell_nolock (MSVCR80.@)
4768 __msvcrt_long CDECL _ftell_nolock(FILE* file)
4770 return _ftelli64_nolock(file);
4772 #endif
4774 /*********************************************************************
4775 * fgetpos (MSVCRT.@)
4777 int CDECL fgetpos(FILE* file, fpos_t *pos)
4779 *pos = _ftelli64(file);
4780 if(*pos == -1)
4781 return -1;
4782 return 0;
4785 /*********************************************************************
4786 * fputs (MSVCRT.@)
4788 int CDECL fputs(const char *s, FILE* file)
4790 size_t len = strlen(s);
4791 int ret;
4793 _lock_file(file);
4794 ret = _fwrite_nolock(s, sizeof(*s), len, file) == len ? 0 : EOF;
4795 _unlock_file(file);
4796 return ret;
4799 /*********************************************************************
4800 * fputws (MSVCRT.@)
4802 int CDECL fputws(const wchar_t *s, FILE* file)
4804 size_t i, len = wcslen(s);
4805 BOOL tmp_buf;
4806 int ret;
4808 _lock_file(file);
4809 if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
4810 ret = _fwrite_nolock(s,sizeof(*s),len,file) == len ? 0 : EOF;
4811 _unlock_file(file);
4812 return ret;
4815 tmp_buf = add_std_buffer(file);
4816 for (i=0; i<len; i++) {
4817 if(_fputwc_nolock(s[i], file) == WEOF) {
4818 if(tmp_buf) remove_std_buffer(file);
4819 _unlock_file(file);
4820 return WEOF;
4824 if(tmp_buf) remove_std_buffer(file);
4825 _unlock_file(file);
4826 return 0;
4829 /*********************************************************************
4830 * getchar (MSVCRT.@)
4832 int CDECL getchar(void)
4834 return fgetc(MSVCRT_stdin);
4837 /*********************************************************************
4838 * getc (MSVCRT.@)
4840 int CDECL getc(FILE* file)
4842 return fgetc(file);
4845 /*********************************************************************
4846 * gets_s (MSVCR80.@)
4848 char * CDECL gets_s(char *buf, size_t len)
4850 char *buf_start = buf;
4851 int cc;
4853 if (!MSVCRT_CHECK_PMT(buf != NULL)) return NULL;
4854 if (!MSVCRT_CHECK_PMT(len != 0)) return NULL;
4856 _lock_file(MSVCRT_stdin);
4857 for(cc = _fgetc_nolock(MSVCRT_stdin);
4858 len != 0 && cc != EOF && cc != '\n';
4859 cc = _fgetc_nolock(MSVCRT_stdin))
4861 if (cc != '\r')
4863 *buf++ = (char)cc;
4864 len--;
4867 _unlock_file(MSVCRT_stdin);
4869 if (!len)
4871 *buf_start = 0;
4872 _invalid_parameter(NULL, NULL, NULL, 0, 0);
4873 return NULL;
4876 if ((cc == EOF) && (buf_start == buf))
4878 TRACE(":nothing read\n");
4879 return NULL;
4881 *buf = '\0';
4883 TRACE("got '%s'\n", buf_start);
4884 return buf_start;
4887 /*********************************************************************
4888 * gets (MSVCRT.@)
4890 char * CDECL gets(char *buf)
4892 return gets_s(buf, -1);
4895 /*********************************************************************
4896 * _getws (MSVCRT.@)
4898 wchar_t* CDECL _getws(wchar_t* buf)
4900 wint_t cc;
4901 wchar_t* ws = buf;
4903 _lock_file(MSVCRT_stdin);
4904 for (cc = _fgetwc_nolock(MSVCRT_stdin); cc != WEOF && cc != '\n';
4905 cc = _fgetwc_nolock(MSVCRT_stdin))
4907 if (cc != '\r')
4908 *buf++ = (wchar_t)cc;
4910 _unlock_file(MSVCRT_stdin);
4912 if ((cc == WEOF) && (ws == buf))
4914 TRACE(":nothing read\n");
4915 return NULL;
4917 *buf = '\0';
4919 TRACE("got %s\n", debugstr_w(ws));
4920 return ws;
4923 /*********************************************************************
4924 * putc (MSVCRT.@)
4926 int CDECL putc(int c, FILE* file)
4928 return fputc(c, file);
4931 /*********************************************************************
4932 * putchar (MSVCRT.@)
4934 int CDECL putchar(int c)
4936 return fputc(c, MSVCRT_stdout);
4939 /*********************************************************************
4940 * puts (MSVCRT.@)
4942 int CDECL puts(const char *s)
4944 size_t len = strlen(s);
4945 int ret;
4947 _lock_file(MSVCRT_stdout);
4948 if(_fwrite_nolock(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4949 _unlock_file(MSVCRT_stdout);
4950 return EOF;
4953 ret = _fwrite_nolock("\n",1,1,MSVCRT_stdout) == 1 ? 0 : EOF;
4954 _unlock_file(MSVCRT_stdout);
4955 return ret;
4958 /*********************************************************************
4959 * _putws (MSVCRT.@)
4961 int CDECL _putws(const wchar_t *s)
4963 int ret;
4965 _lock_file(MSVCRT_stdout);
4966 ret = fputws(s, MSVCRT_stdout);
4967 if(ret >= 0)
4968 ret = _fputwc_nolock('\n', MSVCRT_stdout);
4969 _unlock_file(MSVCRT_stdout);
4970 return ret >= 0 ? 0 : WEOF;
4973 /*********************************************************************
4974 * remove (MSVCRT.@)
4976 int CDECL remove(const char *path)
4978 TRACE("(%s)\n", path);
4979 if (DeleteFileA(path))
4980 return 0;
4981 TRACE(":failed (%ld)\n", GetLastError());
4982 msvcrt_set_errno(GetLastError());
4983 return -1;
4986 /*********************************************************************
4987 * _wremove (MSVCRT.@)
4989 int CDECL _wremove(const wchar_t *path)
4991 TRACE("(%s)\n", debugstr_w(path));
4992 if (DeleteFileW(path))
4993 return 0;
4994 TRACE(":failed (%ld)\n", GetLastError());
4995 msvcrt_set_errno(GetLastError());
4996 return -1;
4999 /*********************************************************************
5000 * rename (MSVCRT.@)
5002 int CDECL rename(const char *oldpath,const char *newpath)
5004 TRACE(":from %s to %s\n", oldpath, newpath);
5005 if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
5006 return 0;
5007 TRACE(":failed (%ld)\n", GetLastError());
5008 msvcrt_set_errno(GetLastError());
5009 return -1;
5012 /*********************************************************************
5013 * _wrename (MSVCRT.@)
5015 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
5017 TRACE(":from %s to %s\n", debugstr_w(oldpath), debugstr_w(newpath));
5018 if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
5019 return 0;
5020 TRACE(":failed (%ld)\n", GetLastError());
5021 msvcrt_set_errno(GetLastError());
5022 return -1;
5025 /*********************************************************************
5026 * setvbuf (MSVCRT.@)
5028 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
5030 if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
5031 if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1;
5032 if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1;
5034 _lock_file(file);
5036 _fflush_nolock(file);
5037 if(file->_flag & _IOMYBUF)
5038 free(file->_base);
5039 file->_flag &= ~(_IONBF | _IOMYBUF | MSVCRT__USERBUF);
5040 file->_cnt = 0;
5042 if(mode == _IONBF) {
5043 file->_flag |= _IONBF;
5044 file->_base = file->_ptr = (char*)&file->_charbuf;
5045 file->_bufsiz = 2;
5046 }else if(buf) {
5047 file->_base = file->_ptr = buf;
5048 file->_flag |= MSVCRT__USERBUF;
5049 file->_bufsiz = size;
5050 }else {
5051 file->_base = file->_ptr = malloc(size);
5052 if(!file->_base) {
5053 file->_bufsiz = 0;
5054 _unlock_file(file);
5055 return -1;
5058 file->_flag |= _IOMYBUF;
5059 file->_bufsiz = size;
5061 _unlock_file(file);
5062 return 0;
5065 /*********************************************************************
5066 * setbuf (MSVCRT.@)
5068 void CDECL setbuf(FILE* file, char *buf)
5070 setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
5073 static int tmpnam_helper(char *s, size_t size, LONG *tmpnam_unique, int tmp_max)
5075 char tmpstr[8];
5076 char *p = s;
5077 int digits;
5079 if (!MSVCRT_CHECK_PMT(s != NULL)) return EINVAL;
5081 if (size < 3) {
5082 if (size) *s = 0;
5083 *_errno() = ERANGE;
5084 return ERANGE;
5086 *p++ = '\\';
5087 *p++ = 's';
5088 size -= 2;
5089 digits = msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
5090 if (digits+1 > size) {
5091 *s = 0;
5092 *_errno() = ERANGE;
5093 return ERANGE;
5095 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5096 p += digits;
5097 *p++ = '.';
5098 size -= digits+1;
5100 while(1) {
5101 while ((digits = *tmpnam_unique)+1 < tmp_max) {
5102 if (InterlockedCompareExchange(tmpnam_unique, digits+1, digits) == digits)
5103 break;
5106 digits = msvcrt_int_to_base32(digits, tmpstr);
5107 if (digits+1 > size) {
5108 *s = 0;
5109 *_errno() = ERANGE;
5110 return ERANGE;
5112 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5113 p[digits] = 0;
5115 if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
5116 GetLastError() == ERROR_FILE_NOT_FOUND)
5117 break;
5119 return 0;
5122 int CDECL tmpnam_s(char *s, size_t size)
5124 return tmpnam_helper(s, size, &tmpnam_s_unique, TMP_MAX_S);
5127 /*********************************************************************
5128 * tmpnam (MSVCRT.@)
5130 char * CDECL tmpnam(char *s)
5132 if (!s) {
5133 thread_data_t *data = msvcrt_get_thread_data();
5135 if(!data->tmpnam_buffer)
5136 data->tmpnam_buffer = malloc(MAX_PATH);
5138 s = data->tmpnam_buffer;
5141 return tmpnam_helper(s, -1, &tmpnam_unique, TMP_MAX) ? NULL : s;
5144 static int wtmpnam_helper(wchar_t *s, size_t size, LONG *tmpnam_unique, int tmp_max)
5146 wchar_t tmpstr[8];
5147 wchar_t *p = s;
5148 int digits;
5150 if (!MSVCRT_CHECK_PMT(s != NULL)) return EINVAL;
5152 if (size < 3) {
5153 if (size) *s = 0;
5154 *_errno() = ERANGE;
5155 return ERANGE;
5157 *p++ = '\\';
5158 *p++ = 's';
5159 size -= 2;
5160 digits = msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
5161 if (digits+1 > size) {
5162 *s = 0;
5163 *_errno() = ERANGE;
5164 return ERANGE;
5166 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5167 p += digits;
5168 *p++ = '.';
5169 size -= digits+1;
5171 while(1) {
5172 while ((digits = *tmpnam_unique)+1 < tmp_max) {
5173 if (InterlockedCompareExchange(tmpnam_unique, digits+1, digits) == digits)
5174 break;
5177 digits = msvcrt_int_to_base32_w(digits, tmpstr);
5178 if (digits+1 > size) {
5179 *s = 0;
5180 *_errno() = ERANGE;
5181 return ERANGE;
5183 memcpy(p, tmpstr, digits*sizeof(tmpstr[0]));
5184 p[digits] = 0;
5186 if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
5187 GetLastError() == ERROR_FILE_NOT_FOUND)
5188 break;
5190 return 0;
5193 /*********************************************************************
5194 * _wtmpnam_s (MSVCRT.@)
5196 int CDECL _wtmpnam_s(wchar_t *s, size_t size)
5198 return wtmpnam_helper(s, size, &tmpnam_s_unique, TMP_MAX_S);
5201 /*********************************************************************
5202 * _wtmpnam (MSVCRT.@)
5204 wchar_t * CDECL _wtmpnam(wchar_t *s)
5206 if (!s) {
5207 thread_data_t *data = msvcrt_get_thread_data();
5209 if(!data->wtmpnam_buffer)
5210 data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
5212 s = data->wtmpnam_buffer;
5215 return wtmpnam_helper(s, -1, &tmpnam_unique, TMP_MAX) ? NULL : s;
5218 /*********************************************************************
5219 * tmpfile (MSVCRT.@)
5221 FILE* CDECL tmpfile(void)
5223 char *filename = _tempnam(",", "t");
5224 int fd;
5225 FILE* file = NULL;
5227 LOCK_FILES();
5228 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
5229 _S_IREAD | _S_IWRITE);
5230 if (fd != -1 && (file = msvcrt_alloc_fp()))
5232 if (msvcrt_init_fp(file, fd, _IORW) == -1)
5234 file->_flag = 0;
5235 file = NULL;
5237 else file->_tmpfname = _strdup(filename);
5240 if(fd != -1 && !file)
5241 _close(fd);
5242 free(filename);
5243 UNLOCK_FILES();
5244 return file;
5247 /*********************************************************************
5248 * tmpfile_s (MSVCRT.@)
5250 int CDECL tmpfile_s(FILE** file)
5252 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
5254 *file = tmpfile();
5255 return 0;
5258 static int puts_clbk_file_a(void *file, int len, const char *str)
5260 return fwrite(str, sizeof(char), len, file);
5263 static int puts_clbk_file_w(void *file, int len, const wchar_t *str)
5265 int i, ret;
5267 _lock_file(file);
5269 if(!(get_ioinfo_nolock(((FILE*)file)->_file)->wxflag & WX_TEXT)) {
5270 ret = _fwrite_nolock(str, sizeof(wchar_t), len, file);
5271 _unlock_file(file);
5272 return ret;
5275 for(i=0; i<len; i++) {
5276 if(_fputwc_nolock(str[i], file) == WEOF) {
5277 _unlock_file(file);
5278 return -1;
5282 _unlock_file(file);
5283 return len;
5286 static int vfprintf_helper(DWORD options, FILE* file, const char *format,
5287 _locale_t locale, va_list valist)
5289 printf_arg args_ctx[_ARGMAX+1];
5290 BOOL tmp_buf;
5291 int ret;
5293 if(!MSVCRT_CHECK_PMT( file != NULL )) return -1;
5294 if(!MSVCRT_CHECK_PMT( format != NULL )) return -1;
5296 if(options & MSVCRT_PRINTF_POSITIONAL_PARAMS) {
5297 memset(args_ctx, 0, sizeof(args_ctx));
5298 ret = create_positional_ctx_a(args_ctx, format, valist);
5299 if(ret < 0) {
5300 _invalid_parameter(NULL, NULL, NULL, 0, 0);
5301 *_errno() = EINVAL;
5302 return ret;
5303 } else if(!ret)
5304 options &= ~MSVCRT_PRINTF_POSITIONAL_PARAMS;
5307 _lock_file(file);
5308 tmp_buf = add_std_buffer(file);
5309 ret = pf_printf_a(puts_clbk_file_a, file, format, locale, options,
5310 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? arg_clbk_positional : arg_clbk_valist,
5311 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? args_ctx : NULL, &valist);
5312 if(tmp_buf) remove_std_buffer(file);
5313 _unlock_file(file);
5315 return ret;
5318 static int vfwprintf_helper(DWORD options, FILE* file, const wchar_t *format,
5319 _locale_t locale, va_list valist)
5321 printf_arg args_ctx[_ARGMAX+1];
5322 BOOL tmp_buf;
5323 int ret;
5325 if(!MSVCRT_CHECK_PMT( file != NULL )) return -1;
5326 if(!MSVCRT_CHECK_PMT( format != NULL )) return -1;
5328 if(options & MSVCRT_PRINTF_POSITIONAL_PARAMS) {
5329 memset(args_ctx, 0, sizeof(args_ctx));
5330 ret = create_positional_ctx_w(args_ctx, format, valist);
5331 if(ret < 0) {
5332 _invalid_parameter(NULL, NULL, NULL, 0, 0);
5333 *_errno() = EINVAL;
5334 return ret;
5335 } else if(!ret)
5336 options &= ~MSVCRT_PRINTF_POSITIONAL_PARAMS;
5339 _lock_file(file);
5340 tmp_buf = add_std_buffer(file);
5341 ret = pf_printf_w(puts_clbk_file_w, file, format, locale, options,
5342 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? arg_clbk_positional : arg_clbk_valist,
5343 options & MSVCRT_PRINTF_POSITIONAL_PARAMS ? args_ctx : NULL, &valist);
5344 if(tmp_buf) remove_std_buffer(file);
5345 _unlock_file(file);
5347 return ret;
5350 /*********************************************************************
5351 * _vfprintf_s_l (MSVCRT.@)
5353 int CDECL _vfprintf_s_l(FILE* file, const char *format,
5354 _locale_t locale, va_list valist)
5356 return vfprintf_helper(MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5359 /*********************************************************************
5360 * _vfwprintf_s_l (MSVCRT.@)
5362 int CDECL _vfwprintf_s_l(FILE* file, const wchar_t *format,
5363 _locale_t locale, va_list valist)
5365 return vfwprintf_helper(MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5368 /*********************************************************************
5369 * vfprintf (MSVCRT.@)
5371 int CDECL vfprintf(FILE* file, const char *format, va_list valist)
5373 return vfprintf_helper(0, file, format, NULL, valist);
5376 /*********************************************************************
5377 * vfprintf_s (MSVCRT.@)
5379 int CDECL vfprintf_s(FILE* file, const char *format, va_list valist)
5381 return _vfprintf_s_l(file, format, NULL, valist);
5384 /*********************************************************************
5385 * vfwprintf (MSVCRT.@)
5387 int CDECL vfwprintf(FILE* file, const wchar_t *format, va_list valist)
5389 return vfwprintf_helper(0, file, format, NULL, valist);
5392 /*********************************************************************
5393 * vfwprintf_s (MSVCRT.@)
5395 int CDECL vfwprintf_s(FILE* file, const wchar_t *format, va_list valist)
5397 return _vfwprintf_s_l(file, format, NULL, valist);
5400 #if _MSVCR_VER >= 140
5402 /*********************************************************************
5403 * __stdio_common_vfprintf (UCRTBASE.@)
5405 int CDECL _stdio_common_vfprintf(unsigned __int64 options, FILE *file, const char *format,
5406 _locale_t locale, va_list valist)
5408 if (options & ~UCRTBASE_PRINTF_MASK)
5409 FIXME("options %#I64x not handled\n", options);
5411 return vfprintf_helper(options & UCRTBASE_PRINTF_MASK, file, format, locale, valist);
5414 /*********************************************************************
5415 * __stdio_common_vfprintf_p (UCRTBASE.@)
5417 int CDECL __stdio_common_vfprintf_p(unsigned __int64 options, FILE *file, const char *format,
5418 _locale_t locale, va_list valist)
5420 if (options & ~UCRTBASE_PRINTF_MASK)
5421 FIXME("options %#I64x not handled\n", options);
5423 return vfprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_POSITIONAL_PARAMS
5424 | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5428 /*********************************************************************
5429 * __stdio_common_vfprintf_s (UCRTBASE.@)
5431 int CDECL __stdio_common_vfprintf_s(unsigned __int64 options, FILE *file, const char *format,
5432 _locale_t locale, va_list valist)
5434 if (options & ~UCRTBASE_PRINTF_MASK)
5435 FIXME("options %#I64x not handled\n", options);
5437 return vfprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5438 file, format, locale, valist);
5441 /*********************************************************************
5442 * __stdio_common_vfwprintf (UCRTBASE.@)
5444 int CDECL __stdio_common_vfwprintf(unsigned __int64 options, FILE *file, const wchar_t *format,
5445 _locale_t locale, va_list valist)
5447 if (options & ~UCRTBASE_PRINTF_MASK)
5448 FIXME("options %#I64x not handled\n", options);
5450 return vfwprintf_helper(options & UCRTBASE_PRINTF_MASK, file, format, locale, valist);
5453 /*********************************************************************
5454 * __stdio_common_vfwprintf_p (UCRTBASE.@)
5456 int CDECL __stdio_common_vfwprintf_p(unsigned __int64 options, FILE *file, const wchar_t *format,
5457 _locale_t locale, va_list valist)
5459 if (options & ~UCRTBASE_PRINTF_MASK)
5460 FIXME("options %#I64x not handled\n", options);
5462 return vfwprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_POSITIONAL_PARAMS
5463 | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER, file, format, locale, valist);
5467 /*********************************************************************
5468 * __stdio_common_vfwprintf_s (UCRTBASE.@)
5470 int CDECL __stdio_common_vfwprintf_s(unsigned __int64 options, FILE *file, const wchar_t *format,
5471 _locale_t locale, va_list valist)
5473 if (options & ~UCRTBASE_PRINTF_MASK)
5474 FIXME("options %#I64x not handled\n", options);
5476 return vfwprintf_helper((options & UCRTBASE_PRINTF_MASK) | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5477 file, format, locale, valist);
5480 #endif /* _MSVCR_VER >= 140 */
5482 /*********************************************************************
5483 * _vfprintf_l (MSVCRT.@)
5485 int CDECL _vfprintf_l(FILE* file, const char *format,
5486 _locale_t locale, va_list valist)
5488 return vfprintf_helper(0, file, format, locale, valist);
5491 /*********************************************************************
5492 * _vfwprintf_l (MSVCRT.@)
5494 int CDECL _vfwprintf_l(FILE* file, const wchar_t *format,
5495 _locale_t locale, va_list valist)
5497 return vfwprintf_helper(0, file, format, locale, valist);
5500 /*********************************************************************
5501 * _vfprintf_p_l (MSVCRT.@)
5503 int CDECL _vfprintf_p_l(FILE* file, const char *format,
5504 _locale_t locale, va_list valist)
5506 return vfprintf_helper(MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5507 file, format, locale, valist);
5510 /*********************************************************************
5511 * _vfprintf_p (MSVCRT.@)
5513 int CDECL _vfprintf_p(FILE* file, const char *format, va_list valist)
5515 return _vfprintf_p_l(file, format, NULL, valist);
5518 /*********************************************************************
5519 * _vfwprintf_p_l (MSVCRT.@)
5521 int CDECL _vfwprintf_p_l(FILE* file, const wchar_t *format,
5522 _locale_t locale, va_list valist)
5524 return vfwprintf_helper(MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
5525 file, format, locale, valist);
5528 /*********************************************************************
5529 * _vfwprintf_p (MSVCRT.@)
5531 int CDECL _vfwprintf_p(FILE* file, const wchar_t *format, va_list valist)
5533 return _vfwprintf_p_l(file, format, NULL, valist);
5536 /*********************************************************************
5537 * vprintf (MSVCRT.@)
5539 int CDECL vprintf(const char *format, va_list valist)
5541 return vfprintf(MSVCRT_stdout,format,valist);
5544 /*********************************************************************
5545 * vprintf_s (MSVCRT.@)
5547 int CDECL vprintf_s(const char *format, va_list valist)
5549 return vfprintf_s(MSVCRT_stdout,format,valist);
5552 /*********************************************************************
5553 * vwprintf (MSVCRT.@)
5555 int CDECL vwprintf(const wchar_t *format, va_list valist)
5557 return vfwprintf(MSVCRT_stdout,format,valist);
5560 /*********************************************************************
5561 * vwprintf_s (MSVCRT.@)
5563 int CDECL vwprintf_s(const wchar_t *format, va_list valist)
5565 return vfwprintf_s(MSVCRT_stdout,format,valist);
5568 /*********************************************************************
5569 * fprintf (MSVCRT.@)
5571 int WINAPIV fprintf(FILE* file, const char *format, ...)
5573 va_list valist;
5574 int res;
5575 va_start(valist, format);
5576 res = vfprintf(file, format, valist);
5577 va_end(valist);
5578 return res;
5581 /*********************************************************************
5582 * fprintf_s (MSVCRT.@)
5584 int WINAPIV fprintf_s(FILE* file, const char *format, ...)
5586 va_list valist;
5587 int res;
5588 va_start(valist, format);
5589 res = vfprintf_s(file, format, valist);
5590 va_end(valist);
5591 return res;
5594 /*********************************************************************
5595 * _fprintf_l (MSVCRT.@)
5597 int WINAPIV _fprintf_l(FILE* file, const char *format, _locale_t locale, ...)
5599 va_list valist;
5600 int res;
5601 va_start(valist, locale);
5602 res = _vfprintf_l(file, format, locale, valist);
5603 va_end(valist);
5604 return res;
5608 /*********************************************************************
5609 * _fprintf_p (MSVCRT.@)
5611 int WINAPIV _fprintf_p(FILE* file, const char *format, ...)
5613 va_list valist;
5614 int res;
5615 va_start(valist, format);
5616 res = _vfprintf_p_l(file, format, NULL, valist);
5617 va_end(valist);
5618 return res;
5621 /*********************************************************************
5622 * _fprintf_p_l (MSVCRT.@)
5624 int WINAPIV _fprintf_p_l(FILE* file, const char *format, _locale_t locale, ...)
5626 va_list valist;
5627 int res;
5628 va_start(valist, locale);
5629 res = _vfprintf_p_l(file, format, locale, valist);
5630 va_end(valist);
5631 return res;
5634 /*********************************************************************
5635 * _fprintf_s_l (MSVCRT.@)
5637 int WINAPIV _fprintf_s_l(FILE* file, const char *format, _locale_t locale, ...)
5639 va_list valist;
5640 int res;
5641 va_start(valist, locale);
5642 res = _vfprintf_s_l(file, format, locale, valist);
5643 va_end(valist);
5644 return res;
5647 /*********************************************************************
5648 * fwprintf (MSVCRT.@)
5650 int WINAPIV fwprintf(FILE* file, const wchar_t *format, ...)
5652 va_list valist;
5653 int res;
5654 va_start(valist, format);
5655 res = vfwprintf(file, format, valist);
5656 va_end(valist);
5657 return res;
5660 /*********************************************************************
5661 * fwprintf_s (MSVCRT.@)
5663 int WINAPIV fwprintf_s(FILE* file, const wchar_t *format, ...)
5665 va_list valist;
5666 int res;
5667 va_start(valist, format);
5668 res = vfwprintf_s(file, format, valist);
5669 va_end(valist);
5670 return res;
5673 /*********************************************************************
5674 * _fwprintf_l (MSVCRT.@)
5676 int WINAPIV _fwprintf_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5678 va_list valist;
5679 int res;
5680 va_start(valist, locale);
5681 res = _vfwprintf_l(file, format, locale, valist);
5682 va_end(valist);
5683 return res;
5686 /*********************************************************************
5687 * _fwprintf_p (MSVCRT.@)
5689 int WINAPIV _fwprintf_p(FILE* file, const wchar_t *format, ...)
5691 va_list valist;
5692 int res;
5693 va_start(valist, format);
5694 res = _vfwprintf_p_l(file, format, NULL, valist);
5695 va_end(valist);
5696 return res;
5699 /*********************************************************************
5700 * _fwprintf_p_l (MSVCRT.@)
5702 int WINAPIV _fwprintf_p_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5704 va_list valist;
5705 int res;
5706 va_start(valist, locale);
5707 res = _vfwprintf_p_l(file, format, locale, valist);
5708 va_end(valist);
5709 return res;
5712 /*********************************************************************
5713 * _fwprintf_s_l (MSVCRT.@)
5715 int WINAPIV _fwprintf_s_l(FILE* file, const wchar_t *format, _locale_t locale, ...)
5717 va_list valist;
5718 int res;
5719 va_start(valist, locale);
5720 res = _vfwprintf_s_l(file, format, locale, valist);
5721 va_end(valist);
5722 return res;
5725 /*********************************************************************
5726 * printf (MSVCRT.@)
5728 int WINAPIV printf(const char *format, ...)
5730 va_list valist;
5731 int res;
5732 va_start(valist, format);
5733 res = vfprintf(MSVCRT_stdout, format, valist);
5734 va_end(valist);
5735 return res;
5738 /*********************************************************************
5739 * printf_s (MSVCRT.@)
5741 int WINAPIV printf_s(const char *format, ...)
5743 va_list valist;
5744 int res;
5745 va_start(valist, format);
5746 res = vprintf_s(format, valist);
5747 va_end(valist);
5748 return res;
5751 /*********************************************************************
5752 * ungetc (MSVCRT.@)
5754 int CDECL ungetc(int c, FILE * file)
5756 int ret;
5758 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
5760 _lock_file(file);
5761 ret = _ungetc_nolock(c, file);
5762 _unlock_file(file);
5764 return ret;
5767 /*********************************************************************
5768 * _ungetc_nolock (MSVCRT.@)
5770 int CDECL _ungetc_nolock(int c, FILE * file)
5772 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
5774 if (c == EOF || !(file->_flag&_IOREAD ||
5775 (file->_flag&_IORW && !(file->_flag&_IOWRT))))
5776 return EOF;
5778 if((!(file->_flag & (_IONBF | _IOMYBUF | MSVCRT__USERBUF))
5779 && msvcrt_alloc_buffer(file))
5780 || (!file->_cnt && file->_ptr==file->_base))
5781 file->_ptr++;
5783 if(file->_ptr>file->_base) {
5784 file->_ptr--;
5785 if(file->_flag & _IOSTRG) {
5786 if(*file->_ptr != c) {
5787 file->_ptr++;
5788 return EOF;
5790 }else {
5791 *file->_ptr = c;
5793 file->_cnt++;
5794 file->_flag &= ~(_IOERR | _IOEOF);
5795 file->_flag |= _IOREAD;
5796 return c;
5799 return EOF;
5802 /*********************************************************************
5803 * ungetwc (MSVCRT.@)
5805 wint_t CDECL ungetwc(wint_t wc, FILE * file)
5807 wint_t ret;
5809 if(!MSVCRT_CHECK_PMT(file != NULL)) return WEOF;
5811 _lock_file(file);
5812 ret = _ungetwc_nolock(wc, file);
5813 _unlock_file(file);
5815 return ret;
5818 /*********************************************************************
5819 * _ungetwc_nolock (MSVCRT.@)
5821 wint_t CDECL _ungetwc_nolock(wint_t wc, FILE * file)
5823 wchar_t mwc = wc;
5825 if(!MSVCRT_CHECK_PMT(file != NULL)) return WEOF;
5826 if (wc == WEOF)
5827 return WEOF;
5829 if(ioinfo_get_textmode(get_ioinfo_nolock(file->_file)) != TEXTMODE_ANSI
5830 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
5831 unsigned char * pp = (unsigned char *)&mwc;
5832 int i;
5834 for(i=sizeof(wchar_t)-1;i>=0;i--) {
5835 if(pp[i] != _ungetc_nolock(pp[i],file))
5836 return WEOF;
5838 }else {
5839 char mbs[MB_LEN_MAX];
5840 int len;
5842 len = wctomb(mbs, mwc);
5843 if(len == -1)
5844 return WEOF;
5846 for(len--; len>=0; len--) {
5847 if(mbs[len] != _ungetc_nolock(mbs[len], file))
5848 return WEOF;
5852 return mwc;
5855 /*********************************************************************
5856 * wprintf (MSVCRT.@)
5858 int WINAPIV wprintf(const wchar_t *format, ...)
5860 va_list valist;
5861 int res;
5862 va_start(valist, format);
5863 res = vwprintf(format, valist);
5864 va_end(valist);
5865 return res;
5868 /*********************************************************************
5869 * wprintf_s (MSVCRT.@)
5871 int WINAPIV wprintf_s(const wchar_t *format, ...)
5873 va_list valist;
5874 int res;
5875 va_start(valist, format);
5876 res = vwprintf_s(format, valist);
5877 va_end(valist);
5878 return res;
5881 /*********************************************************************
5882 * _getmaxstdio (MSVCRT.@)
5884 int CDECL _getmaxstdio(void)
5886 return MSVCRT_max_streams;
5889 /*********************************************************************
5890 * _setmaxstdio (MSVCRT.@)
5892 int CDECL _setmaxstdio(int newmax)
5894 TRACE("%d\n", newmax);
5896 if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
5897 return -1;
5899 MSVCRT_max_streams = newmax;
5900 return MSVCRT_max_streams;
5903 #if _MSVCR_VER >= 140
5904 /*********************************************************************
5905 * _get_stream_buffer_pointers (UCRTBASE.@)
5907 int CDECL _get_stream_buffer_pointers(FILE *file, char*** base,
5908 char*** ptr, int** count)
5910 if (base)
5911 *base = &file->_base;
5912 if (ptr)
5913 *ptr = &file->_ptr;
5914 if (count)
5915 *count = &file->_cnt;
5916 return 0;
5918 #endif