[CRT] Update file descriptor handling to match Wine (7/7). CORE-14504
[reactos.git] / sdk / lib / crt / stdio / file.c
1 /*
2 * PROJECT: ReactOS CRT library
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: lib/sdk/crt/stdio/file.c
5 * PURPOSE: File CRT functions
6 * PROGRAMMERS: Wine team
7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /*********************************************
11 * This file contains ReactOS changes!!
12 * Don't blindly sync it with Wine code!
13 *
14 * If you break Unicode output on the console again, please update this counter:
15 * int hours_wasted_on_this = 42;
16 *********************************************/
17
18 /*
19 * msvcrt.dll file functions
20 *
21 * Copyright 1996,1998 Marcus Meissner
22 * Copyright 1996 Jukka Iivonen
23 * Copyright 1997,2000 Uwe Bonnes
24 * Copyright 2000 Jon Griffiths
25 * Copyright 2004 Eric Pouech
26 * Copyright 2004 Juan Lang
27 *
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Lesser General Public
30 * License as published by the Free Software Foundation; either
31 * version 2.1 of the License, or (at your option) any later version.
32 *
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Lesser General Public License for more details.
37 *
38 * You should have received a copy of the GNU Lesser General Public
39 * License along with this library; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41 *
42 * TODO
43 * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
44 */
45
46 #include <precomp.h>
47 #include "wine/unicode.h"
48 #include "internal/wine/msvcrt.h"
49
50 #include <sys/utime.h>
51 #include <direct.h>
52
53 int *__p__fmode(void);
54 int *__p___mb_cur_max(void);
55
56 extern int _commode;
57
58 #ifndef _IOCOMMIT
59 #define _IOCOMMIT 0x4000
60 #endif
61
62 #ifdef feof
63 #undef feof
64 #endif
65 #ifdef _fileno
66 #undef _fileno
67 #endif
68 #ifdef ferror
69 #undef ferror
70 #endif
71 #ifdef clearerr
72 #undef clearerr
73 #endif
74
75 #undef getc
76 #undef getwc
77 #undef getchar
78 #undef getwchar
79 #undef putc
80 #undef putwc
81 #undef putchar
82 #undef putwchar
83
84 #undef vprintf
85 #undef vwprintf
86
87 /* _access() bit flags FIXME: incomplete */
88 /* defined in crt/io.h */
89
90 /* values for wxflag in file descriptor */
91 #define WX_OPEN 0x01
92 #define WX_ATEOF 0x02
93 #define WX_READNL 0x04 /* read started with \n */
94 #define WX_READEOF 0x04 /* like ATEOF, but for underlying file rather than buffer */
95 #define WX_PIPE 0x08
96 #define WX_READCR 0x08 /* underlying file is at \r */
97 #define WX_DONTINHERIT 0x10
98 #define WX_APPEND 0x20
99 #define WX_TTY 0x40
100 #define WX_TEXT 0x80
101
102 /* values for exflag - it's used differently in msvcr90.dll*/
103 #define EF_UTF8 0x01
104 #define EF_UTF16 0x02
105 #define EF_CRIT_INIT 0x04
106 #define EF_UNK_UNICODE 0x08
107
108 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
109 static char utf16_bom[2] = { 0xff, 0xfe };
110
111 /* FIXME: this should be allocated dynamically */
112 #define MSVCRT_MAX_FILES 2048
113 #define MSVCRT_FD_BLOCK_SIZE 32
114
115 #define MSVCRT_INTERNAL_BUFSIZ 4096
116
117 /*********************************************************************
118 * __pioinfo (MSVCRT.@)
119 * array of pointers to ioinfo arrays [32]
120 */
121 ioinfo * __pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
122
123 /*********************************************************************
124 * __badioinfo (MSVCRT.@)
125 */
126 ioinfo __badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
127
128 typedef struct {
129 FILE file;
130 CRITICAL_SECTION crit;
131 } file_crit;
132
133 FILE _iob[_IOB_ENTRIES] = { { 0 } };
134 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { NULL };
135 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
136
137 /* INTERNAL: process umask */
138 static int MSVCRT_umask = 0;
139
140 /* INTERNAL: static data for tmpnam and _wtmpname functions */
141 static int tmpnam_unique;
142
143 /* This critical section protects the MSVCRT_fstreams table
144 * and MSVCRT_stream_idx from race conditions. It also
145 * protects fd critical sections creation code.
146 */
147 static CRITICAL_SECTION MSVCRT_file_cs;
148 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
149 {
150 0, 0, &MSVCRT_file_cs,
151 { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
152 0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
153 };
154 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
155 #define LOCK_FILES() do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
156 #define UNLOCK_FILES() do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
157
158 static inline ioinfo* get_ioinfo_nolock(int fd)
159 {
160 ioinfo *ret = NULL;
161 if(fd>=0 && fd<MSVCRT_MAX_FILES)
162 ret = __pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
163 if(!ret)
164 return &__badioinfo;
165
166 return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
167 }
168
169 static inline void init_ioinfo_cs(ioinfo *info)
170 {
171 if(!(info->exflag & EF_CRIT_INIT)) {
172 LOCK_FILES();
173 if(!(info->exflag & EF_CRIT_INIT)) {
174 InitializeCriticalSection(&info->crit);
175 info->exflag |= EF_CRIT_INIT;
176 }
177 UNLOCK_FILES();
178 }
179 }
180
181 /*static*/ inline ioinfo* get_ioinfo(int fd)
182 {
183 ioinfo *ret = get_ioinfo_nolock(fd);
184 if(ret == &__badioinfo)
185 return ret;
186 init_ioinfo_cs(ret);
187 EnterCriticalSection(&ret->crit);
188 return ret;
189 }
190
191 static inline BOOL alloc_pioinfo_block(int fd)
192 {
193 ioinfo *block;
194 int i;
195
196 if(fd<0 || fd>=MSVCRT_MAX_FILES)
197 {
198 *_errno() = ENFILE;
199 return FALSE;
200 }
201
202 block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
203 if(!block)
204 {
205 WARN(":out of memory!\n");
206 *_errno() = ENOMEM;
207 return FALSE;
208 }
209 for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
210 block[i].handle = INVALID_HANDLE_VALUE;
211 if(InterlockedCompareExchangePointer((void**)&__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL))
212 free(block);
213 return TRUE;
214 }
215
216 static inline ioinfo* get_ioinfo_alloc_fd(int fd)
217 {
218 ioinfo *ret;
219
220 ret = get_ioinfo(fd);
221 if(ret != &__badioinfo)
222 return ret;
223
224 if(!alloc_pioinfo_block(fd))
225 return &__badioinfo;
226
227 return get_ioinfo(fd);
228 }
229
230 static inline ioinfo* get_ioinfo_alloc(int *fd)
231 {
232 int i;
233
234 *fd = -1;
235 for(i=0; i<MSVCRT_MAX_FILES; i++)
236 {
237 ioinfo *info = get_ioinfo_nolock(i);
238
239 if(info == &__badioinfo)
240 {
241 if(!alloc_pioinfo_block(i))
242 return &__badioinfo;
243 info = get_ioinfo_nolock(i);
244 }
245
246 init_ioinfo_cs(info);
247 if(TryEnterCriticalSection(&info->crit))
248 {
249 if(info->handle == INVALID_HANDLE_VALUE)
250 {
251 *fd = i;
252 return info;
253 }
254 LeaveCriticalSection(&info->crit);
255 }
256 }
257
258 WARN(":files exhausted!\n");
259 *_errno() = ENFILE;
260 return &__badioinfo;
261 }
262
263 /*static*/ inline void release_ioinfo(ioinfo *info)
264 {
265 if(info!=&__badioinfo && info->exflag & EF_CRIT_INIT)
266 LeaveCriticalSection(&info->crit);
267 }
268
269 static inline FILE* msvcrt_get_file(int i)
270 {
271 file_crit *ret;
272
273 if(i >= MSVCRT_max_streams)
274 return NULL;
275
276 if(i < _IOB_ENTRIES)
277 return &_iob[i];
278
279 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
280 if(!ret) {
281 MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
282 if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
283 ERR("out of memory\n");
284 *_errno() = ENOMEM;
285 return NULL;
286 }
287
288 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
289 } else
290 ret += i%MSVCRT_FD_BLOCK_SIZE;
291
292 return &ret->file;
293 }
294
295 /* INTERNAL: free a file entry fd */
296 static void msvcrt_free_fd(int fd)
297 {
298 ioinfo *fdinfo = get_ioinfo(fd);
299
300 if(fdinfo != &__badioinfo)
301 {
302 fdinfo->handle = INVALID_HANDLE_VALUE;
303 fdinfo->wxflag = 0;
304 }
305 TRACE(":fd (%d) freed\n",fd);
306
307 if (fd < 3)
308 {
309 switch (fd)
310 {
311 case 0:
312 SetStdHandle(STD_INPUT_HANDLE, 0);
313 break;
314 case 1:
315 SetStdHandle(STD_OUTPUT_HANDLE, 0);
316 break;
317 case 2:
318 SetStdHandle(STD_ERROR_HANDLE, 0);
319 break;
320 }
321 }
322 release_ioinfo(fdinfo);
323 }
324
325 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag)
326 {
327 fdinfo->handle = hand;
328 fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY));
329 fdinfo->lookahead[0] = '\n';
330 fdinfo->lookahead[1] = '\n';
331 fdinfo->lookahead[2] = '\n';
332 fdinfo->exflag &= EF_CRIT_INIT;
333
334 switch (fdinfo-__pioinfo[0])
335 {
336 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
337 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
338 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
339 }
340 }
341
342 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
343 /*static*/ int msvcrt_alloc_fd(HANDLE hand, int flag)
344 {
345 int fd;
346 ioinfo *info = get_ioinfo_alloc(&fd);
347
348 TRACE(":handle (%p) allocating fd (%d)\n", hand, fd);
349
350 if(info == &__badioinfo)
351 return -1;
352
353 msvcrt_set_fd(info, hand, flag);
354 release_ioinfo(info);
355 return fd;
356 }
357
358 /* INTERNAL: Allocate a FILE* for an fd slot */
359 /* caller must hold the files lock */
360 static FILE* msvcrt_alloc_fp(void)
361 {
362 int i;
363 FILE *file;
364
365 for (i = 3; i < MSVCRT_max_streams; i++)
366 {
367 file = msvcrt_get_file(i);
368 if (!file)
369 return NULL;
370
371 if (file->_flag == 0)
372 {
373 if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++;
374 return file;
375 }
376 }
377
378 return NULL;
379 }
380
381 /* INTERNAL: initialize a FILE* from an open fd */
382 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags)
383 {
384 TRACE(":fd (%d) allocating FILE*\n",fd);
385 if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN))
386 {
387 WARN(":invalid fd %d\n",fd);
388 *__doserrno() = 0;
389 *_errno() = EBADF;
390 return -1;
391 }
392 file->_ptr = file->_base = NULL;
393 file->_cnt = 0;
394 file->_file = fd;
395 file->_flag = stream_flags;
396 file->_tmpfname = NULL;
397
398 if(file<_iob || file>=_iob+_IOB_ENTRIES)
399 InitializeCriticalSection(&((file_crit*)file)->crit);
400
401 TRACE(":got FILE* (%p)\n",file);
402 return 0;
403 }
404
405 /* INTERNAL: Create an inheritance data block (for spawned process)
406 * The inheritance block is made of:
407 * 00 int nb of file descriptor (NBFD)
408 * 04 char file flags (wxflag): repeated for each fd
409 * 4+NBFD HANDLE file handle: repeated for each fd
410 */
411 unsigned create_io_inherit_block(WORD *size, BYTE **block)
412 {
413 int fd, last_fd;
414 char* wxflag_ptr;
415 HANDLE* handle_ptr;
416 ioinfo* fdinfo;
417
418 for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--)
419 if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE)
420 break;
421 last_fd++;
422
423 *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd;
424 *block = calloc(1, *size);
425 if (!*block)
426 {
427 *size = 0;
428 return FALSE;
429 }
430 wxflag_ptr = (char*)*block + sizeof(unsigned);
431 handle_ptr = (HANDLE*)(wxflag_ptr + last_fd);
432
433 *(unsigned*)*block = last_fd;
434 for (fd = 0; fd < last_fd; fd++)
435 {
436 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
437 fdinfo = get_ioinfo(fd);
438 if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
439 {
440 *wxflag_ptr = fdinfo->wxflag;
441 *handle_ptr = fdinfo->handle;
442 }
443 else
444 {
445 *wxflag_ptr = 0;
446 *handle_ptr = INVALID_HANDLE_VALUE;
447 }
448 release_ioinfo(fdinfo);
449 wxflag_ptr++; handle_ptr++;
450 }
451 return TRUE;
452 }
453
454 /* INTERNAL: Set up all file descriptors,
455 * as well as default streams (stdin, stderr and stdout)
456 */
457 void msvcrt_init_io(void)
458 {
459 STARTUPINFOA si;
460 unsigned int i;
461 ioinfo *fdinfo;
462
463 GetStartupInfoA(&si);
464 if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
465 {
466 BYTE* wxflag_ptr;
467 HANDLE* handle_ptr;
468 unsigned int count;
469
470 count = *(unsigned*)si.lpReserved2;
471 wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
472 handle_ptr = (HANDLE*)(wxflag_ptr + count);
473
474 count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
475 count = min(count, MSVCRT_MAX_FILES);
476 for (i = 0; i < count; i++)
477 {
478 if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
479 {
480 fdinfo = get_ioinfo_alloc_fd(i);
481 if(fdinfo != &__badioinfo)
482 msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr);
483 release_ioinfo(fdinfo);
484 }
485
486 wxflag_ptr++; handle_ptr++;
487 }
488 }
489
490 fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO);
491 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
492 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
493 DWORD type = GetFileType(h);
494
495 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
496 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
497 }
498 release_ioinfo(fdinfo);
499
500 fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO);
501 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
502 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
503 DWORD type = GetFileType(h);
504
505 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
506 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
507 }
508 release_ioinfo(fdinfo);
509
510 fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO);
511 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
512 HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
513 DWORD type = GetFileType(h);
514
515 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
516 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
517 }
518 release_ioinfo(fdinfo);
519
520 TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle,
521 get_ioinfo_nolock(STDOUT_FILENO)->handle,
522 get_ioinfo_nolock(STDERR_FILENO)->handle);
523
524 memset(_iob,0,3*sizeof(FILE));
525 for (i = 0; i < 3; i++)
526 {
527 /* FILE structs for stdin/out/err are static and never deleted */
528 _iob[i]._file = i;
529 _iob[i]._tmpfname = NULL;
530 _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
531 }
532 MSVCRT_stream_idx = 3;
533 }
534
535 /* INTERNAL: Flush stdio file buffer */
536 static int msvcrt_flush_buffer(FILE* file)
537 {
538 if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT &&
539 file->_flag & (_IOMYBUF|_USERBUF)) {
540 int cnt=file->_ptr-file->_base;
541 if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
542 file->_flag |= _IOERR;
543 return EOF;
544 }
545
546 if(file->_flag & _IORW)
547 file->_flag &= ~_IOWRT;
548
549 #ifdef __REACTOS__ /* CORE-11949 */
550 file->_ptr=file->_base;
551 file->_cnt=0;
552 #endif
553 }
554
555 #ifndef __REACTOS__ /* CORE-11949 */
556 file->_ptr=file->_base;
557 file->_cnt=0;
558 #endif
559 return 0;
560 }
561
562 /*********************************************************************
563 * _isatty (MSVCRT.@)
564 */
565 int CDECL _isatty(int fd)
566 {
567 TRACE(":fd (%d)\n",fd);
568
569 return get_ioinfo_nolock(fd)->wxflag & WX_TTY;
570 }
571
572 /* INTERNAL: Allocate stdio file buffer */
573 /*static*/ BOOL msvcrt_alloc_buffer(FILE* file)
574 {
575 if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
576 && _isatty(file->_file))
577 return FALSE;
578
579 file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ);
580 if(file->_base) {
581 file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
582 file->_flag |= _IOMYBUF;
583 } else {
584 file->_base = (char*)(&file->_charbuf);
585 file->_bufsiz = 2;
586 file->_flag |= _IONBF;
587 }
588 file->_ptr = file->_base;
589 file->_cnt = 0;
590 return TRUE;
591 }
592
593 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
594 static BOOL add_std_buffer(FILE *file)
595 {
596 static char buffers[2][BUFSIZ];
597
598 if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
599 || (file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
600 || !_isatty(file->_file))
601 return FALSE;
602
603 file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
604 file->_bufsiz = file->_cnt = BUFSIZ;
605 file->_flag |= _USERBUF;
606 return TRUE;
607 }
608
609 /* INTERNAL: Removes temporary buffer from stdout or stderr */
610 /* Only call this function when add_std_buffer returned TRUE */
611 static void remove_std_buffer(FILE *file)
612 {
613 msvcrt_flush_buffer(file);
614 file->_ptr = file->_base = NULL;
615 file->_bufsiz = file->_cnt = 0;
616 file->_flag &= ~_USERBUF;
617 }
618
619 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
620 static int msvcrt_int_to_base32(int num, char *str)
621 {
622 char *p;
623 int n = num;
624 int digits = 0;
625
626 while (n != 0)
627 {
628 n >>= 5;
629 digits++;
630 }
631 p = str + digits;
632 *p = 0;
633 while (--p >= str)
634 {
635 *p = (num & 31) + '0';
636 if (*p > '9')
637 *p += ('a' - '0' - 10);
638 num >>= 5;
639 }
640
641 return digits;
642 }
643
644 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
645 static int msvcrt_int_to_base32_w(int num, wchar_t *str)
646 {
647 wchar_t *p;
648 int n = num;
649 int digits = 0;
650
651 while (n != 0)
652 {
653 n >>= 5;
654 digits++;
655 }
656 p = str + digits;
657 *p = 0;
658 while (--p >= str)
659 {
660 *p = (num & 31) + '0';
661 if (*p > '9')
662 *p += ('a' - '0' - 10);
663 num >>= 5;
664 }
665
666 return digits;
667 }
668
669 /* INTERNAL: Create a wide string from an ascii string */
670 wchar_t *msvcrt_wstrdupa(const char *str)
671 {
672 const unsigned int len = strlen(str) + 1 ;
673 wchar_t *wstr = malloc(len* sizeof (wchar_t));
674 if (!wstr)
675 return NULL;
676 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
677 return wstr;
678 }
679
680 /*********************************************************************
681 * __iob_func(MSVCRT.@)
682 */
683 FILE * CDECL __iob_func(void)
684 {
685 return &_iob[0];
686 }
687
688 /*********************************************************************
689 * _access (MSVCRT.@)
690 */
691 int CDECL _access(const char *filename, int mode)
692 {
693 DWORD attr = GetFileAttributesA(filename);
694
695 TRACE("(%s,%d) %d\n",filename,mode,attr);
696
697 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
698 {
699 _dosmaperr(GetLastError());
700 return -1;
701 }
702 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
703 {
704 _set_errno(ERROR_ACCESS_DENIED);
705 return -1;
706 }
707 return 0;
708 }
709
710 /*********************************************************************
711 * _access_s (MSVCRT.@)
712 */
713 int CDECL _access_s(const char *filename, int mode)
714 {
715 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
716 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
717 {
718 _set_errno(EINVAL);
719 return -1;
720 }
721
722 return _access(filename, mode);
723 }
724
725 /*********************************************************************
726 * _waccess (MSVCRT.@)
727 */
728 int CDECL _waccess(const wchar_t *filename, int mode)
729 {
730 DWORD attr = GetFileAttributesW(filename);
731
732 TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
733
734 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
735 {
736 _dosmaperr(GetLastError());
737 return -1;
738 }
739 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
740 {
741 _set_errno(ERROR_ACCESS_DENIED);
742 return -1;
743 }
744 return 0;
745 }
746
747 /*********************************************************************
748 * _waccess_s (MSVCRT.@)
749 */
750 int CDECL _waccess_s(const wchar_t *filename, int mode)
751 {
752 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
753 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
754 {
755 *_errno() = EINVAL;
756 return -1;
757 }
758
759 return _waccess(filename, mode);
760 }
761
762 /*********************************************************************
763 * _chmod (MSVCRT.@)
764 */
765 int CDECL _chmod(const char *path, int flags)
766 {
767 DWORD oldFlags = GetFileAttributesA(path);
768
769 if (oldFlags != INVALID_FILE_ATTRIBUTES)
770 {
771 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
772 oldFlags | FILE_ATTRIBUTE_READONLY;
773
774 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
775 return 0;
776 }
777 _dosmaperr(GetLastError());
778 return -1;
779 }
780
781 /*********************************************************************
782 * _wchmod (MSVCRT.@)
783 */
784 int CDECL _wchmod(const wchar_t *path, int flags)
785 {
786 DWORD oldFlags = GetFileAttributesW(path);
787
788 if (oldFlags != INVALID_FILE_ATTRIBUTES)
789 {
790 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
791 oldFlags | FILE_ATTRIBUTE_READONLY;
792
793 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
794 return 0;
795 }
796 _dosmaperr(GetLastError());
797 return -1;
798 }
799
800 /*********************************************************************
801 * _unlink (MSVCRT.@)
802 */
803 int CDECL _unlink(const char *path)
804 {
805 TRACE("%s\n",debugstr_a(path));
806 if(DeleteFileA(path))
807 return 0;
808 TRACE("failed (%d)\n",GetLastError());
809 _dosmaperr(GetLastError());
810 return -1;
811 }
812
813 /*********************************************************************
814 * _wunlink (MSVCRT.@)
815 */
816 int CDECL _wunlink(const wchar_t *path)
817 {
818 TRACE("(%s)\n",debugstr_w(path));
819 if(DeleteFileW(path))
820 return 0;
821 TRACE("failed (%d)\n",GetLastError());
822 _dosmaperr(GetLastError());
823 return -1;
824 }
825
826 /*********************************************************************
827 * _commit (MSVCRT.@)
828 */
829 int CDECL _commit(int fd)
830 {
831 ioinfo *info = get_ioinfo(fd);
832 int ret;
833
834 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
835 if (info->handle == INVALID_HANDLE_VALUE)
836 ret = -1;
837 else if (!FlushFileBuffers(info->handle))
838 {
839 if (GetLastError() == ERROR_INVALID_HANDLE)
840 {
841 /* FlushFileBuffers fails for console handles
842 * so we ignore this error.
843 */
844 ret = 0;
845 }
846 else
847 {
848 TRACE(":failed-last error (%d)\n",GetLastError());
849 _dosmaperr(GetLastError());
850 ret = -1;
851 }
852 }
853 else
854 {
855 TRACE(":ok\n");
856 ret = 0;
857 }
858
859 release_ioinfo(info);
860 return ret;
861 }
862
863 /* _flushall calls fflush which calls _flushall */
864 int CDECL fflush(FILE* file);
865
866 /* INTERNAL: Flush all stream buffer */
867 static int msvcrt_flush_all_buffers(int mask)
868 {
869 int i, num_flushed = 0;
870 FILE *file;
871
872 LOCK_FILES();
873 for (i = 0; i < MSVCRT_stream_idx; i++) {
874 file = msvcrt_get_file(i);
875
876 if (file->_flag)
877 {
878 if(file->_flag & mask) {
879 fflush(file);
880 num_flushed++;
881 }
882 }
883 }
884 UNLOCK_FILES();
885
886 TRACE(":flushed (%d) handles\n",num_flushed);
887 return num_flushed;
888 }
889
890 /*********************************************************************
891 * _flushall (MSVCRT.@)
892 */
893 int CDECL _flushall(void)
894 {
895 return msvcrt_flush_all_buffers(_IOWRT | _IOREAD);
896 }
897
898 /*********************************************************************
899 * fflush (MSVCRT.@)
900 */
901 int CDECL fflush(FILE* file)
902 {
903 if(!file) {
904 msvcrt_flush_all_buffers(_IOWRT);
905 } else if(file->_flag & _IOWRT) {
906 int res;
907
908 _lock_file(file);
909 res = msvcrt_flush_buffer(file);
910 /* FIXME
911 if(!res && (file->_flag & _IOCOMMIT))
912 res = _commit(file->_file) ? EOF : 0;
913 */
914 _unlock_file(file);
915
916 return res;
917 } else if(file->_flag & _IOREAD) {
918 _lock_file(file);
919 file->_cnt = 0;
920 file->_ptr = file->_base;
921 _unlock_file(file);
922
923 return 0;
924 }
925 return 0;
926 }
927
928 /*********************************************************************
929 * _close (MSVCRT.@)
930 */
931 int CDECL _close(int fd)
932 {
933 ioinfo *info = get_ioinfo(fd);
934 int ret;
935
936 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
937 if (!(info->wxflag & WX_OPEN)) {
938 ret = -1;
939 } else {
940 ret = CloseHandle(info->handle) ? 0 : -1;
941 msvcrt_free_fd(fd);
942 if (ret) {
943 WARN(":failed-last error (%d)\n",GetLastError());
944 _dosmaperr(GetLastError());
945 ret = -1;
946 }
947 }
948 release_ioinfo(info);
949 return ret;
950 }
951
952 /*********************************************************************
953 * _dup2 (MSVCRT.@)
954 * NOTES
955 * MSDN isn't clear on this point, but the remarks for _pipe
956 * indicate file descriptors duplicated with _dup and _dup2 are always
957 * inheritable.
958 */
959 int CDECL _dup2(int od, int nd)
960 {
961 ioinfo *info_od, *info_nd;
962 int ret;
963
964 TRACE("(od=%d, nd=%d)\n", od, nd);
965
966 if (od < nd)
967 {
968 info_od = get_ioinfo(od);
969 info_nd = get_ioinfo_alloc_fd(nd);
970 }
971 else
972 {
973 info_nd = get_ioinfo_alloc_fd(nd);
974 info_od = get_ioinfo(od);
975 }
976
977 if (info_nd == &__badioinfo)
978 {
979 ret = -1;
980 }
981 else if (info_od->wxflag & WX_OPEN)
982 {
983 HANDLE handle;
984
985 if (DuplicateHandle(GetCurrentProcess(), info_od->handle,
986 GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
987 {
988 int wxflag = info_od->wxflag & ~_O_NOINHERIT;
989
990 if (info_nd->wxflag & WX_OPEN)
991 _close(nd);
992
993 msvcrt_set_fd(info_nd, handle, wxflag);
994 /* _dup2 returns 0, not nd, on success */
995 ret = 0;
996 }
997 else
998 {
999 ret = -1;
1000 _dosmaperr(GetLastError());
1001 }
1002 }
1003 else
1004 {
1005 *_errno() = EBADF;
1006 ret = -1;
1007 }
1008
1009 release_ioinfo(info_od);
1010 release_ioinfo(info_nd);
1011 return ret;
1012 }
1013
1014 /*********************************************************************
1015 * _dup (MSVCRT.@)
1016 */
1017 int CDECL _dup(int od)
1018 {
1019 int fd, ret;
1020 ioinfo *info = get_ioinfo_alloc(&fd);
1021
1022 if (_dup2(od, fd) == 0)
1023 ret = fd;
1024 else
1025 ret = -1;
1026 release_ioinfo(info);
1027 return ret;
1028 }
1029
1030 /*********************************************************************
1031 * _eof (MSVCRT.@)
1032 */
1033 int CDECL _eof(int fd)
1034 {
1035 ioinfo *info = get_ioinfo(fd);
1036 DWORD curpos,endpos;
1037 LONG hcurpos,hendpos;
1038
1039 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1040
1041 if (info->handle == INVALID_HANDLE_VALUE)
1042 {
1043 release_ioinfo(info);
1044 return -1;
1045 }
1046
1047 if (info->wxflag & WX_ATEOF)
1048 {
1049 release_ioinfo(info);
1050 return TRUE;
1051 }
1052
1053 /* Otherwise we do it the hard way */
1054 hcurpos = hendpos = 0;
1055 curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT);
1056 endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END);
1057
1058 if (curpos == endpos && hcurpos == hendpos)
1059 {
1060 /* FIXME: shouldn't WX_ATEOF be set here? */
1061 release_ioinfo(info);
1062 return TRUE;
1063 }
1064
1065 SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN);
1066 release_ioinfo(info);
1067 return FALSE;
1068 }
1069
1070 /*********************************************************************
1071 * _fcloseall (MSVCRT.@)
1072 */
1073 int CDECL _fcloseall(void)
1074 {
1075 int num_closed = 0, i;
1076 FILE *file;
1077
1078 LOCK_FILES();
1079 for (i = 3; i < MSVCRT_stream_idx; i++) {
1080 file = msvcrt_get_file(i);
1081
1082 if (file->_flag && !fclose(file))
1083 num_closed++;
1084 }
1085 UNLOCK_FILES();
1086
1087 TRACE(":closed (%d) handles\n",num_closed);
1088 return num_closed;
1089 }
1090
1091 /* free everything on process exit */
1092 void msvcrt_free_io(void)
1093 {
1094 unsigned int i;
1095 int j;
1096
1097 _flushall();
1098 _fcloseall();
1099
1100 for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
1101 {
1102 if(!__pioinfo[i])
1103 continue;
1104
1105 for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++)
1106 {
1107 if(__pioinfo[i][j].exflag & EF_CRIT_INIT)
1108 DeleteCriticalSection(&__pioinfo[i][j].crit);
1109 }
1110 free(__pioinfo[i]);
1111 }
1112
1113 for(j=0; j<MSVCRT_stream_idx; j++)
1114 {
1115 FILE *file = msvcrt_get_file(j);
1116 if(file<_iob || file>=_iob+_IOB_ENTRIES)
1117 {
1118 ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1119 DeleteCriticalSection(&((file_crit*)file)->crit);
1120 }
1121 }
1122
1123 for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1124 free(MSVCRT_fstream[i]);
1125 }
1126
1127 /*********************************************************************
1128 * _lseeki64 (MSVCRT.@)
1129 */
1130 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1131 {
1132 ioinfo *info = get_ioinfo(fd);
1133 LARGE_INTEGER ofs;
1134
1135 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1136
1137 if (info->handle == INVALID_HANDLE_VALUE)
1138 {
1139 release_ioinfo(info);
1140 return -1;
1141 }
1142
1143 if (whence < 0 || whence > 2)
1144 {
1145 release_ioinfo(info);
1146 *_errno() = EINVAL;
1147 return -1;
1148 }
1149
1150 TRACE(":fd (%d) to %s pos %s\n",
1151 fd,wine_dbgstr_longlong(offset),
1152 (whence==SEEK_SET)?"SEEK_SET":
1153 (whence==SEEK_CUR)?"SEEK_CUR":
1154 (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1155
1156 /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1157 * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1158 ofs.QuadPart = offset;
1159 if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1160 GetLastError() == ERROR_SUCCESS)
1161 {
1162 info->wxflag &= ~(WX_ATEOF|WX_READEOF);
1163 /* FIXME: What if we seek _to_ EOF - is EOF set? */
1164
1165 release_ioinfo(info);
1166 return ofs.QuadPart;
1167 }
1168 release_ioinfo(info);
1169 TRACE(":error-last error (%d)\n",GetLastError());
1170 _dosmaperr(GetLastError());
1171 return -1;
1172 }
1173
1174 /*********************************************************************
1175 * _lseek (MSVCRT.@)
1176 */
1177 LONG CDECL _lseek(int fd, LONG offset, int whence)
1178 {
1179 return (LONG)_lseeki64(fd, offset, whence);
1180 }
1181
1182 /*********************************************************************
1183 * _lock_file (MSVCRT.@)
1184 */
1185 void CDECL _lock_file(FILE *file)
1186 {
1187 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1188 _lock(_STREAM_LOCKS+(file-_iob));
1189 /* ReactOS: string streams dont need to be locked */
1190 else if(!(file->_flag & _IOSTRG))
1191 EnterCriticalSection(&((file_crit*)file)->crit);
1192 }
1193
1194 /*********************************************************************
1195 * _unlock_file (MSVCRT.@)
1196 */
1197 void CDECL _unlock_file(FILE *file)
1198 {
1199 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1200 _unlock(_STREAM_LOCKS+(file-_iob));
1201 /* ReactOS: string streams dont need to be locked */
1202 else if(!(file->_flag & _IOSTRG))
1203 LeaveCriticalSection(&((file_crit*)file)->crit);
1204
1205 }
1206
1207 /*********************************************************************
1208 * _locking (MSVCRT.@)
1209 *
1210 * This is untested; the underlying LockFile doesn't work yet.
1211 */
1212 int CDECL _locking(int fd, int mode, LONG nbytes)
1213 {
1214 ioinfo *info = get_ioinfo(fd);
1215 BOOL ret;
1216 DWORD cur_locn;
1217
1218 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1219 if (info->handle == INVALID_HANDLE_VALUE)
1220 {
1221 release_ioinfo(info);
1222 return -1;
1223 }
1224
1225 if (mode < 0 || mode > 4)
1226 {
1227 release_ioinfo(info);
1228 *_errno() = EINVAL;
1229 return -1;
1230 }
1231
1232 TRACE(":fd (%d) by 0x%08x mode %s\n",
1233 fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
1234 (mode==_LK_LOCK)?"_LK_LOCK":
1235 (mode==_LK_NBLCK)?"_LK_NBLCK":
1236 (mode==_LK_RLCK)?"_LK_RLCK":
1237 (mode==_LK_NBRLCK)?"_LK_NBRLCK":
1238 "UNKNOWN");
1239
1240 if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
1241 {
1242 release_ioinfo(info);
1243 FIXME ("Seek failed\n");
1244 *_errno() = EINVAL; /* FIXME */
1245 return -1;
1246 }
1247 if (mode == _LK_LOCK || mode == _LK_RLCK)
1248 {
1249 int nretry = 10;
1250 ret = 1; /* just to satisfy gcc */
1251 while (nretry--)
1252 {
1253 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1254 if (ret) break;
1255 Sleep(1);
1256 }
1257 }
1258 else if (mode == _LK_UNLCK)
1259 ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1260 else
1261 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1262 /* FIXME - what about error settings? */
1263 release_ioinfo(info);
1264 return ret ? 0 : -1;
1265 }
1266
1267 /*********************************************************************
1268 * _fseeki64 (MSVCRT.@)
1269 */
1270 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1271 {
1272 int ret;
1273
1274 _lock_file(file);
1275 /* Flush output if needed */
1276 if(file->_flag & _IOWRT)
1277 msvcrt_flush_buffer(file);
1278
1279 if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1280 whence = SEEK_SET;
1281 offset += _ftelli64(file);
1282 }
1283
1284 /* Discard buffered input */
1285 file->_cnt = 0;
1286 file->_ptr = file->_base;
1287 /* Reset direction of i/o */
1288 if(file->_flag & _IORW) {
1289 file->_flag &= ~(_IOREAD|_IOWRT);
1290 }
1291 /* Clear end of file flag */
1292 file->_flag &= ~_IOEOF;
1293 ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1294
1295 _unlock_file(file);
1296 return ret;
1297 }
1298
1299 /*********************************************************************
1300 * fseek (MSVCRT.@)
1301 */
1302 int CDECL fseek(FILE* file, long offset, int whence)
1303 {
1304 return _fseeki64( file, offset, whence );
1305 }
1306
1307 /*********************************************************************
1308 * _chsize_s (MSVCRT.@)
1309 */
1310 int CDECL _chsize_s(int fd, __int64 size)
1311 {
1312 ioinfo *info;
1313 __int64 cur, pos;
1314 BOOL ret = FALSE;
1315
1316 TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size));
1317
1318 if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
1319
1320 info = get_ioinfo(fd);
1321 if (info->handle != INVALID_HANDLE_VALUE)
1322 {
1323 /* save the current file pointer */
1324 cur = _lseeki64(fd, 0, SEEK_CUR);
1325 if (cur >= 0)
1326 {
1327 pos = _lseeki64(fd, size, SEEK_SET);
1328 if (pos >= 0)
1329 {
1330 ret = SetEndOfFile(info->handle);
1331 if (!ret) _dosmaperr(GetLastError());
1332 }
1333
1334 /* restore the file pointer */
1335 _lseeki64(fd, cur, SEEK_SET);
1336 }
1337 }
1338
1339 release_ioinfo(info);
1340 return ret ? 0 : *_errno();
1341 }
1342
1343 /*********************************************************************
1344 * _chsize (MSVCRT.@)
1345 */
1346 int CDECL _chsize(int fd, long size)
1347 {
1348 /* _chsize_s returns errno on failure but _chsize should return -1 */
1349 return _chsize_s( fd, size ) == 0 ? 0 : -1;
1350 }
1351
1352 /*********************************************************************
1353 * clearerr (MSVCRT.@)
1354 */
1355 void CDECL clearerr(FILE* file)
1356 {
1357 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1358
1359 _lock_file(file);
1360 file->_flag &= ~(_IOERR | _IOEOF);
1361 _unlock_file(file);
1362 }
1363
1364 /*********************************************************************
1365 * rewind (MSVCRT.@)
1366 */
1367 void CDECL rewind(FILE* file)
1368 {
1369 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1370
1371 _lock_file(file);
1372 fseek(file, 0L, SEEK_SET);
1373 clearerr(file);
1374 _unlock_file(file);
1375 }
1376
1377 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1378 {
1379 int plus = strchrW(mode, '+') != NULL;
1380
1381 TRACE("%s\n", debugstr_w(mode));
1382
1383 while(*mode == ' ') mode++;
1384
1385 switch(*mode++)
1386 {
1387 case 'R': case 'r':
1388 *open_flags = plus ? _O_RDWR : _O_RDONLY;
1389 *stream_flags = plus ? _IORW : _IOREAD;
1390 break;
1391 case 'W': case 'w':
1392 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1393 *stream_flags = plus ? _IORW : _IOWRT;
1394 break;
1395 case 'A': case 'a':
1396 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1397 *stream_flags = plus ? _IORW : _IOWRT;
1398 break;
1399 default:
1400 MSVCRT_INVALID_PMT(0, EINVAL);
1401 return -1;
1402 }
1403
1404 *stream_flags |= _commode;
1405
1406 while (*mode && *mode!=',')
1407 switch (*mode++)
1408 {
1409 case 'B': case 'b':
1410 *open_flags |= _O_BINARY;
1411 *open_flags &= ~_O_TEXT;
1412 break;
1413 case 't':
1414 *open_flags |= _O_TEXT;
1415 *open_flags &= ~_O_BINARY;
1416 break;
1417 case 'D':
1418 *open_flags |= _O_TEMPORARY;
1419 break;
1420 case 'T':
1421 *open_flags |= _O_SHORT_LIVED;
1422 break;
1423 case 'c':
1424 *stream_flags |= _IOCOMMIT;
1425 break;
1426 case 'n':
1427 *stream_flags &= ~_IOCOMMIT;
1428 break;
1429 case 'N':
1430 *open_flags |= _O_NOINHERIT;
1431 break;
1432 case '+':
1433 case ' ':
1434 case 'a':
1435 case 'w':
1436 break;
1437 case 'S':
1438 case 'R':
1439 FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1440 break;
1441 default:
1442 ERR("incorrect mode flag: %c\n", mode[-1]);
1443 break;
1444 }
1445
1446 if(*mode == ',')
1447 {
1448 static const WCHAR ccs[] = {'c','c','s'};
1449 static const WCHAR utf8[] = {'u','t','f','-','8'};
1450 static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1451 static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1452
1453 mode++;
1454 while(*mode == ' ') mode++;
1455 if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1456 return -1;
1457 mode += sizeof(ccs)/sizeof(ccs[0]);
1458 while(*mode == ' ') mode++;
1459 if(!MSVCRT_CHECK_PMT(*mode == '='))
1460 return -1;
1461 mode++;
1462 while(*mode == ' ') mode++;
1463
1464 if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1465 {
1466 *open_flags |= _O_U8TEXT;
1467 mode += sizeof(utf8)/sizeof(utf8[0]);
1468 }
1469 else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1470 {
1471 *open_flags |= _O_U16TEXT;
1472 mode += sizeof(utf16le)/sizeof(utf16le[0]);
1473 }
1474 else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1475 {
1476 *open_flags |= _O_WTEXT;
1477 mode += sizeof(unicode)/sizeof(unicode[0]);
1478 }
1479 else
1480 {
1481 MSVCRT_INVALID_PMT(0, EINVAL);
1482 return -1;
1483 }
1484
1485 while(*mode == ' ') mode++;
1486 }
1487
1488 if(!MSVCRT_CHECK_PMT(*mode == 0))
1489 return -1;
1490 return 0;
1491 }
1492
1493 /*********************************************************************
1494 * _fdopen (MSVCRT.@)
1495 */
1496 FILE* CDECL _fdopen(int fd, const char *mode)
1497 {
1498 FILE *ret;
1499 wchar_t *modeW = NULL;
1500
1501 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1502
1503 ret = _wfdopen(fd, modeW);
1504
1505 free(modeW);
1506 return ret;
1507 }
1508
1509 /*********************************************************************
1510 * _wfdopen (MSVCRT.@)
1511 */
1512 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1513 {
1514 int open_flags, stream_flags;
1515 FILE* file;
1516
1517 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1518
1519 LOCK_FILES();
1520 if (!(file = msvcrt_alloc_fp()))
1521 file = NULL;
1522 else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1523 {
1524 file->_flag = 0;
1525 file = NULL;
1526 }
1527 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1528 UNLOCK_FILES();
1529
1530 return file;
1531 }
1532
1533 /*********************************************************************
1534 * _filelength (MSVCRT.@)
1535 */
1536 LONG CDECL _filelength(int fd)
1537 {
1538 LONG curPos = _lseek(fd, 0, SEEK_CUR);
1539 if (curPos != -1)
1540 {
1541 LONG endPos = _lseek(fd, 0, SEEK_END);
1542 if (endPos != -1)
1543 {
1544 if (endPos != curPos)
1545 _lseek(fd, curPos, SEEK_SET);
1546 return endPos;
1547 }
1548 }
1549 return -1;
1550 }
1551
1552 /*********************************************************************
1553 * _filelengthi64 (MSVCRT.@)
1554 */
1555 __int64 CDECL _filelengthi64(int fd)
1556 {
1557 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1558 if (curPos != -1)
1559 {
1560 __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1561 if (endPos != -1)
1562 {
1563 if (endPos != curPos)
1564 _lseeki64(fd, curPos, SEEK_SET);
1565 return endPos;
1566 }
1567 }
1568 return -1;
1569 }
1570
1571 /*********************************************************************
1572 * _fileno (MSVCRT.@)
1573 */
1574 int CDECL _fileno(FILE* file)
1575 {
1576 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1577 return file->_file;
1578 }
1579
1580 /*********************************************************************
1581 * _get_osfhandle (MSVCRT.@)
1582 */
1583 intptr_t CDECL _get_osfhandle(int fd)
1584 {
1585 HANDLE hand = get_ioinfo_nolock(fd)->handle;
1586 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1587
1588 if(hand == INVALID_HANDLE_VALUE)
1589 *_errno() = EBADF;
1590 return (intptr_t)hand;
1591 }
1592
1593 /*********************************************************************
1594 * _mktemp (MSVCRT.@)
1595 */
1596 char * CDECL _mktemp(char *pattern)
1597 {
1598 int numX = 0;
1599 char *retVal = pattern;
1600 int id;
1601 char letter = 'a';
1602
1603 if(!pattern)
1604 return NULL;
1605
1606 while(*pattern)
1607 numX = (*pattern++ == 'X')? numX + 1 : 0;
1608 if (numX < 6)
1609 return NULL;
1610 pattern--;
1611 id = GetCurrentProcessId();
1612 numX = 6;
1613 while(numX--)
1614 {
1615 int tempNum = id / 10;
1616 *pattern-- = id - (tempNum * 10) + '0';
1617 id = tempNum;
1618 }
1619 pattern++;
1620 do
1621 {
1622 *pattern = letter++;
1623 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
1624 return retVal;
1625 } while(letter <= 'z');
1626 return NULL;
1627 }
1628
1629 /*********************************************************************
1630 * _wmktemp (MSVCRT.@)
1631 */
1632 wchar_t * CDECL _wmktemp(wchar_t *pattern)
1633 {
1634 int numX = 0;
1635 wchar_t *retVal = pattern;
1636 int id;
1637 wchar_t letter = 'a';
1638
1639 while(*pattern)
1640 numX = (*pattern++ == 'X')? numX + 1 : 0;
1641 if (numX < 5)
1642 return NULL;
1643 pattern--;
1644 id = GetCurrentProcessId();
1645 numX = 6;
1646 while(numX--)
1647 {
1648 int tempNum = id / 10;
1649 *pattern-- = id - (tempNum * 10) + '0';
1650 id = tempNum;
1651 }
1652 pattern++;
1653 do
1654 {
1655 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1656 GetLastError() == ERROR_FILE_NOT_FOUND)
1657 return retVal;
1658 *pattern = letter++;
1659 } while(letter != '|');
1660 return NULL;
1661 }
1662
1663 /*static*/ unsigned split_oflags(unsigned oflags)
1664 {
1665 int wxflags = 0;
1666 unsigned unsupp; /* until we support everything */
1667
1668 if (oflags & _O_APPEND) wxflags |= WX_APPEND;
1669 if (oflags & _O_BINARY) {/* Nothing to do */}
1670 else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
1671 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
1672 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
1673 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
1674 else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */}
1675 else wxflags |= WX_TEXT; /* default to TEXT*/
1676 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
1677
1678 if ((unsupp = oflags & ~(
1679 _O_BINARY|_O_TEXT|_O_APPEND|
1680 _O_TRUNC|_O_EXCL|_O_CREAT|
1681 _O_RDWR|_O_WRONLY|_O_TEMPORARY|
1682 _O_NOINHERIT|
1683 _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
1684 _O_WTEXT|_O_U16TEXT|_O_U8TEXT
1685 )))
1686 ERR(":unsupported oflags 0x%04x\n",unsupp);
1687
1688 return wxflags;
1689 }
1690
1691 /*********************************************************************
1692 * _pipe (MSVCRT.@)
1693 */
1694 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
1695 {
1696 int ret = -1;
1697 SECURITY_ATTRIBUTES sa;
1698 HANDLE readHandle, writeHandle;
1699
1700 if (!pfds)
1701 {
1702 *_errno() = EINVAL;
1703 return -1;
1704 }
1705
1706 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1707 sa.bInheritHandle = !(textmode & _O_NOINHERIT);
1708 sa.lpSecurityDescriptor = NULL;
1709 if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1710 {
1711 unsigned int wxflags = split_oflags(textmode);
1712 int fd;
1713
1714 fd = msvcrt_alloc_fd(readHandle, wxflags);
1715 if (fd != -1)
1716 {
1717 pfds[0] = fd;
1718 fd = msvcrt_alloc_fd(writeHandle, wxflags);
1719 if (fd != -1)
1720 {
1721 pfds[1] = fd;
1722 ret = 0;
1723 }
1724 else
1725 {
1726 _close(pfds[0]);
1727 CloseHandle(writeHandle);
1728 *_errno() = EMFILE;
1729 }
1730 }
1731 else
1732 {
1733 CloseHandle(readHandle);
1734 CloseHandle(writeHandle);
1735 *_errno() = EMFILE;
1736 }
1737 }
1738 else
1739 _dosmaperr(GetLastError());
1740
1741 return ret;
1742 }
1743
1744 static int check_bom(HANDLE h, int oflags, BOOL seek)
1745 {
1746 char bom[sizeof(utf8_bom)];
1747 DWORD r;
1748
1749 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1750
1751 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1752 return oflags;
1753
1754 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1755 oflags |= _O_U8TEXT;
1756 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1757 if (seek && r>2)
1758 SetFilePointer(h, 2, NULL, FILE_BEGIN);
1759 oflags |= _O_U16TEXT;
1760 }else if (seek) {
1761 SetFilePointer(h, 0, NULL, FILE_BEGIN);
1762 }
1763
1764 return oflags;
1765 }
1766
1767 /*********************************************************************
1768 * _wsopen_s (MSVCRT.@)
1769 */
1770 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
1771 {
1772 DWORD access = 0, creation = 0, attrib;
1773 SECURITY_ATTRIBUTES sa;
1774 DWORD sharing, type;
1775 int wxflag;
1776 HANDLE hand;
1777
1778 TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1779 fd, debugstr_w(path), oflags, shflags, pmode);
1780
1781 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
1782
1783 *fd = -1;
1784 wxflag = split_oflags(oflags);
1785 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1786 {
1787 case _O_RDONLY: access |= GENERIC_READ; break;
1788 case _O_WRONLY: access |= GENERIC_WRITE; break;
1789 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
1790 }
1791
1792 if (oflags & _O_CREAT)
1793 {
1794 if(pmode & ~(_S_IREAD | _S_IWRITE))
1795 FIXME(": pmode 0x%04x ignored\n", pmode);
1796 else
1797 WARN(": pmode 0x%04x ignored\n", pmode);
1798
1799 if (oflags & _O_EXCL)
1800 creation = CREATE_NEW;
1801 else if (oflags & _O_TRUNC)
1802 creation = CREATE_ALWAYS;
1803 else
1804 creation = OPEN_ALWAYS;
1805 }
1806 else /* no _O_CREAT */
1807 {
1808 if (oflags & _O_TRUNC)
1809 creation = TRUNCATE_EXISTING;
1810 else
1811 creation = OPEN_EXISTING;
1812 }
1813
1814 switch( shflags )
1815 {
1816 case _SH_DENYRW:
1817 sharing = 0L;
1818 break;
1819 case _SH_DENYWR:
1820 sharing = FILE_SHARE_READ;
1821 break;
1822 case _SH_DENYRD:
1823 sharing = FILE_SHARE_WRITE;
1824 break;
1825 case _SH_DENYNO:
1826 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1827 break;
1828 default:
1829 ERR( "Unhandled shflags 0x%x\n", shflags );
1830 return EINVAL;
1831 }
1832 attrib = FILE_ATTRIBUTE_NORMAL;
1833
1834 if (oflags & _O_TEMPORARY)
1835 {
1836 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1837 access |= DELETE;
1838 sharing |= FILE_SHARE_DELETE;
1839 }
1840
1841 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
1842 sa.lpSecurityDescriptor = NULL;
1843 sa.bInheritHandle = !(oflags & _O_NOINHERIT);
1844
1845 if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1846 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1847 && !(access&GENERIC_READ))
1848 {
1849 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1850 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1851 if (hand != INVALID_HANDLE_VALUE)
1852 {
1853 oflags = check_bom(hand, oflags, FALSE);
1854 CloseHandle(hand);
1855 }
1856 else
1857 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1858 }
1859
1860 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1861 if (hand == INVALID_HANDLE_VALUE) {
1862 WARN(":failed-last error (%d)\n",GetLastError());
1863 _dosmaperr(GetLastError());
1864 return *_errno();
1865 }
1866
1867 if (oflags & (_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1868 {
1869 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1870 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1871 || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1872 {
1873 if (oflags & _O_U8TEXT)
1874 {
1875 DWORD written = 0, tmp;
1876
1877 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1878 sizeof(utf8_bom)-written, &tmp, NULL))
1879 written += tmp;
1880 if (written != sizeof(utf8_bom)) {
1881 WARN("error writing BOM\n");
1882 CloseHandle(hand);
1883 _dosmaperr(GetLastError());
1884 return *_errno();
1885 }
1886 }
1887 else
1888 {
1889 DWORD written = 0, tmp;
1890
1891 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1892 sizeof(utf16_bom)-written, &tmp, NULL))
1893 written += tmp;
1894 if (written != sizeof(utf16_bom))
1895 {
1896 WARN("error writing BOM\n");
1897 CloseHandle(hand);
1898 _dosmaperr(GetLastError());
1899 return *_errno();
1900 }
1901 }
1902 }
1903 else if (access & GENERIC_READ)
1904 oflags = check_bom(hand, oflags, TRUE);
1905 }
1906
1907 type = GetFileType(hand);
1908 if (type == FILE_TYPE_CHAR)
1909 wxflag |= WX_TTY;
1910 else if (type == FILE_TYPE_PIPE)
1911 wxflag |= WX_PIPE;
1912
1913 *fd = msvcrt_alloc_fd(hand, wxflag);
1914 if (*fd == -1)
1915 return *_errno();
1916
1917 if (oflags & _O_WTEXT)
1918 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1919 else if (oflags & _O_U16TEXT)
1920 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16;
1921 else if (oflags & _O_U8TEXT)
1922 get_ioinfo_nolock(*fd)->exflag |= EF_UTF8;
1923
1924 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1925 return 0;
1926 }
1927
1928 /*********************************************************************
1929 * _wsopen (MSVCRT.@)
1930 */
1931 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
1932 {
1933 int pmode;
1934 int fd;
1935
1936 if (oflags & _O_CREAT)
1937 {
1938 __ms_va_list ap;
1939
1940 __ms_va_start(ap, shflags);
1941 pmode = va_arg(ap, int);
1942 __ms_va_end(ap);
1943 }
1944 else
1945 pmode = 0;
1946
1947 _wsopen_s(&fd, path, oflags, shflags, pmode);
1948 return fd;
1949 }
1950
1951 /*********************************************************************
1952 * _sopen_s (MSVCRT.@)
1953 */
1954 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1955 {
1956 wchar_t *pathW;
1957 int ret;
1958
1959 if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
1960 return EINVAL;
1961
1962 ret = _wsopen_s(fd, pathW, oflags, shflags, pmode);
1963 free(pathW);
1964 return ret;
1965 }
1966
1967 /*********************************************************************
1968 * _sopen (MSVCRT.@)
1969 */
1970 int CDECL _sopen( const char *path, int oflags, int shflags, ... )
1971 {
1972 int pmode;
1973 int fd;
1974
1975 if (oflags & _O_CREAT)
1976 {
1977 va_list ap;
1978
1979 va_start(ap, shflags);
1980 pmode = va_arg(ap, int);
1981 va_end(ap);
1982 }
1983 else
1984 pmode = 0;
1985
1986 _sopen_s(&fd, path, oflags, shflags, pmode);
1987 return fd;
1988 }
1989
1990 /*********************************************************************
1991 * _open (MSVCRT.@)
1992 */
1993 int CDECL _open( const char *path, int flags, ... )
1994 {
1995 va_list ap;
1996
1997 if (flags & _O_CREAT)
1998 {
1999 int pmode;
2000 va_start(ap, flags);
2001 pmode = va_arg(ap, int);
2002 va_end(ap);
2003 return _sopen( path, flags, _SH_DENYNO, pmode );
2004 }
2005 else
2006 return _sopen( path, flags, _SH_DENYNO);
2007 }
2008
2009 /*********************************************************************
2010 * _wopen (MSVCRT.@)
2011 */
2012 int CDECL _wopen(const wchar_t *path,int flags,...)
2013 {
2014 va_list ap;
2015
2016 if (flags & _O_CREAT)
2017 {
2018 int pmode;
2019 va_start(ap, flags);
2020 pmode = va_arg(ap, int);
2021 va_end(ap);
2022 return _wsopen( path, flags, _SH_DENYNO, pmode );
2023 }
2024 else
2025 return _wsopen( path, flags, _SH_DENYNO);
2026 }
2027
2028 /*********************************************************************
2029 * _creat (MSVCRT.@)
2030 */
2031 int CDECL _creat(const char *path, int flags)
2032 {
2033 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2034 return _open(path, usedFlags);
2035 }
2036
2037 /*********************************************************************
2038 * _wcreat (MSVCRT.@)
2039 */
2040 int CDECL _wcreat(const wchar_t *path, int flags)
2041 {
2042 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2043 return _wopen(path, usedFlags);
2044 }
2045
2046 /*********************************************************************
2047 * _open_osfhandle (MSVCRT.@)
2048 */
2049 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2050 {
2051 DWORD flags;
2052 int fd;
2053
2054 /* _O_RDONLY (0) always matches, so set the read flag
2055 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2056 * file, so set the write flag. It also only sets _O_TEXT if it wants
2057 * text - it never sets _O_BINARY.
2058 */
2059 /* don't let split_oflags() decide the mode if no mode is passed */
2060 if (!(oflags & (_O_BINARY | _O_TEXT)))
2061 oflags |= _O_BINARY;
2062
2063 flags = GetFileType((HANDLE)handle);
2064 if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2065 {
2066 _dosmaperr(GetLastError());
2067 return -1;
2068 }
2069
2070 if (flags == FILE_TYPE_CHAR)
2071 flags = WX_TTY;
2072 else if (flags == FILE_TYPE_PIPE)
2073 flags = WX_PIPE;
2074 else
2075 flags = 0;
2076 flags |= split_oflags(oflags);
2077
2078 fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2079 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags);
2080 return fd;
2081 }
2082
2083 /*********************************************************************
2084 * _rmtmp (MSVCRT.@)
2085 */
2086 int CDECL _rmtmp(void)
2087 {
2088 int num_removed = 0, i;
2089 FILE *file;
2090
2091 LOCK_FILES();
2092 for (i = 3; i < MSVCRT_stream_idx; i++) {
2093 file = msvcrt_get_file(i);
2094
2095 if (file->_tmpfname)
2096 {
2097 fclose(file);
2098 num_removed++;
2099 }
2100 }
2101 UNLOCK_FILES();
2102
2103 if (num_removed)
2104 TRACE(":removed (%d) temp files\n",num_removed);
2105 return num_removed;
2106 }
2107
2108 static inline int get_utf8_char_len(char ch)
2109 {
2110 if((ch&0xf8) == 0xf0)
2111 return 4;
2112 else if((ch&0xf0) == 0xe0)
2113 return 3;
2114 else if((ch&0xe0) == 0xc0)
2115 return 2;
2116 return 1;
2117 }
2118
2119 /*********************************************************************
2120 * (internal) read_utf8
2121 */
2122 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2123 {
2124 HANDLE hand = fdinfo->handle;
2125 char min_buf[4], *readbuf, lookahead;
2126 DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2127
2128 /* make the buffer big enough to hold at least one character */
2129 /* read bytes have to fit to output and lookahead buffers */
2130 count /= 2;
2131 readbuf_size = count < 4 ? 4 : count;
2132 if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2133 readbuf_size = 4;
2134 readbuf = min_buf;
2135 }
2136
2137 if(fdinfo->lookahead[0] != '\n') {
2138 readbuf[pos++] = fdinfo->lookahead[0];
2139 fdinfo->lookahead[0] = '\n';
2140
2141 if(fdinfo->lookahead[1] != '\n') {
2142 readbuf[pos++] = fdinfo->lookahead[1];
2143 fdinfo->lookahead[1] = '\n';
2144
2145 if(fdinfo->lookahead[2] != '\n') {
2146 readbuf[pos++] = fdinfo->lookahead[2];
2147 fdinfo->lookahead[2] = '\n';
2148 }
2149 }
2150 }
2151
2152 /* NOTE: this case is broken in native dll, reading
2153 * sometimes fails when small buffer is passed
2154 */
2155 if(count < 4) {
2156 if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2157 if (GetLastError() == ERROR_BROKEN_PIPE) {
2158 fdinfo->wxflag |= WX_ATEOF;
2159 return 0;
2160 }else {
2161 _dosmaperr(GetLastError());
2162 return -1;
2163 }
2164 }else if(!num_read) {
2165 fdinfo->wxflag |= WX_ATEOF;
2166 return 0;
2167 }else {
2168 pos++;
2169 }
2170
2171 char_len = get_utf8_char_len(readbuf[0]);
2172 if(char_len>pos) {
2173 if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2174 pos += num_read;
2175 }
2176
2177 if(readbuf[0] == '\n')
2178 fdinfo->wxflag |= WX_READNL;
2179 else
2180 fdinfo->wxflag &= ~WX_READNL;
2181
2182 if(readbuf[0] == 0x1a) {
2183 fdinfo->wxflag |= WX_ATEOF;
2184 return 0;
2185 }
2186
2187 if(readbuf[0] == '\r') {
2188 if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2189 buf[0] = '\r';
2190 else if(lookahead == '\n')
2191 buf[0] = '\n';
2192 else {
2193 buf[0] = '\r';
2194 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2195 fdinfo->lookahead[0] = lookahead;
2196 else
2197 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2198 }
2199 return 2;
2200 }
2201
2202 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2203 _dosmaperr(GetLastError());
2204 return -1;
2205 }
2206
2207 return num_read*2;
2208 }
2209
2210 if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2211 if(pos) {
2212 num_read = 0;
2213 }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2214 fdinfo->wxflag |= WX_ATEOF;
2215 if (readbuf != min_buf) free(readbuf);
2216 return 0;
2217 }else {
2218 _dosmaperr(GetLastError());
2219 if (readbuf != min_buf) free(readbuf);
2220 return -1;
2221 }
2222 }else if(!pos && !num_read) {
2223 fdinfo->wxflag |= WX_ATEOF;
2224 if (readbuf != min_buf) free(readbuf);
2225 return 0;
2226 }
2227
2228 pos += num_read;
2229 if(readbuf[0] == '\n')
2230 fdinfo->wxflag |= WX_READNL;
2231 else
2232 fdinfo->wxflag &= ~WX_READNL;
2233
2234 /* Find first byte of last character (may be incomplete) */
2235 for(i=pos-1; i>0 && i>pos-4; i--)
2236 if((readbuf[i]&0xc0) != 0x80)
2237 break;
2238 char_len = get_utf8_char_len(readbuf[i]);
2239 if(char_len+i <= pos)
2240 i += char_len;
2241
2242 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2243 if(i < pos)
2244 fdinfo->lookahead[0] = readbuf[i];
2245 if(i+1 < pos)
2246 fdinfo->lookahead[1] = readbuf[i+1];
2247 if(i+2 < pos)
2248 fdinfo->lookahead[2] = readbuf[i+2];
2249 }else if(i < pos) {
2250 SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2251 }
2252 pos = i;
2253
2254 for(i=0, j=0; i<pos; i++) {
2255 if(readbuf[i] == 0x1a) {
2256 fdinfo->wxflag |= WX_ATEOF;
2257 break;
2258 }
2259
2260 /* strip '\r' if followed by '\n' */
2261 if(readbuf[i] == '\r' && i+1==pos) {
2262 if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2263 readbuf[j++] = '\r';
2264 }else if(lookahead == '\n' && j==0) {
2265 readbuf[j++] = '\n';
2266 }else {
2267 if(lookahead != '\n')
2268 readbuf[j++] = '\r';
2269
2270 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2271 fdinfo->lookahead[0] = lookahead;
2272 else
2273 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2274 }
2275 }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2276 readbuf[j++] = readbuf[i];
2277 }
2278 }
2279 pos = j;
2280
2281 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2282 _dosmaperr(GetLastError());
2283 if (readbuf != min_buf) free(readbuf);
2284 return -1;
2285 }
2286
2287 if (readbuf != min_buf) free(readbuf);
2288 return num_read*2;
2289 }
2290
2291 /*********************************************************************
2292 * (internal) read_i
2293 *
2294 * When reading \r as last character in text mode, read() positions
2295 * the file pointer on the \r character while getc() goes on to
2296 * the following \n
2297 */
2298 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2299 {
2300 DWORD num_read, utf16;
2301 char *bufstart = buf;
2302
2303 if (count == 0)
2304 return 0;
2305
2306 if (fdinfo->wxflag & WX_ATEOF) {
2307 TRACE("already at EOF, returning 0\n");
2308 return 0;
2309 }
2310 /* Don't trace small reads, it gets *very* annoying */
2311 if (count > 4)
2312 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2313 if (fdinfo->handle == INVALID_HANDLE_VALUE)
2314 {
2315 *_errno() = EBADF;
2316 return -1;
2317 }
2318
2319 utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2320 if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2321 {
2322 *_errno() = EINVAL;
2323 return -1;
2324 }
2325
2326 if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2327 return read_utf8(fdinfo, buf, count);
2328
2329 if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2330 {
2331 if (fdinfo->lookahead[0] != '\n')
2332 {
2333 bufstart[0] = fdinfo->lookahead[0];
2334 fdinfo->lookahead[0] = '\n';
2335
2336 if (utf16)
2337 {
2338 bufstart[1] = fdinfo->lookahead[1];
2339 fdinfo->lookahead[1] = '\n';
2340 }
2341
2342 if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2343 num_read += 1+utf16;
2344 else
2345 num_read = 1+utf16;
2346 }
2347
2348 if(utf16 && (num_read&1))
2349 {
2350 /* msvcr90 uses uninitialized value from the buffer in this case */
2351 /* msvcrt ignores additional data */
2352 ERR("got odd number of bytes in UTF16 mode\n");
2353 num_read--;
2354 }
2355
2356 if (count != 0 && num_read == 0)
2357 {
2358 fdinfo->wxflag |= WX_ATEOF;
2359 TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2360 }
2361 else if (fdinfo->wxflag & WX_TEXT)
2362 {
2363 DWORD i, j;
2364
2365 if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2366 fdinfo->wxflag |= WX_READNL;
2367 else
2368 fdinfo->wxflag &= ~WX_READNL;
2369
2370 for (i=0, j=0; i<num_read; i+=1+utf16)
2371 {
2372 /* in text mode, a ctrl-z signals EOF */
2373 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2374 {
2375 fdinfo->wxflag |= WX_ATEOF;
2376 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2377 break;
2378 }
2379
2380 /* in text mode, strip \r if followed by \n */
2381 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2382 {
2383 char lookahead[2];
2384 DWORD len;
2385
2386 lookahead[1] = '\n';
2387 if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
2388 {
2389 if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2390 {
2391 bufstart[j++] = '\n';
2392 if(utf16) bufstart[j++] = 0;
2393 }
2394 else
2395 {
2396 if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2397 {
2398 bufstart[j++] = '\r';
2399 if(utf16) bufstart[j++] = 0;
2400 }
2401
2402 if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
2403 {
2404 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
2405 {
2406 bufstart[j++] = '\n';
2407 if (utf16) bufstart[j++] = 0;
2408 }
2409 else
2410 {
2411 fdinfo->lookahead[0] = lookahead[0];
2412 fdinfo->lookahead[1] = lookahead[1];
2413 }
2414 }
2415 else
2416 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2417 }
2418 }
2419 else
2420 {
2421 bufstart[j++] = '\r';
2422 if(utf16) bufstart[j++] = 0;
2423 }
2424 }
2425 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2426 || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2427 {
2428 bufstart[j++] = bufstart[i];
2429 if(utf16) bufstart[j++] = bufstart[i+1];
2430 }
2431 }
2432 num_read = j;
2433 }
2434 }
2435 else
2436 {
2437 if (GetLastError() == ERROR_BROKEN_PIPE)
2438 {
2439 TRACE(":end-of-pipe\n");
2440 fdinfo->wxflag |= WX_ATEOF;
2441 return 0;
2442 }
2443 else
2444 {
2445 TRACE(":failed-last error (%d)\n",GetLastError());
2446 return -1;
2447 }
2448 }
2449
2450 if (count > 4)
2451 TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2452 return num_read;
2453 }
2454
2455 /*********************************************************************
2456 * _read (MSVCRT.@)
2457 */
2458 int CDECL _read(int fd, void *buf, unsigned int count)
2459 {
2460 ioinfo *info = get_ioinfo(fd);
2461 int num_read = read_i(fd, info, buf, count);
2462 release_ioinfo(info);
2463 return num_read;
2464 }
2465
2466 /*********************************************************************
2467 * _setmode (MSVCRT.@)
2468 */
2469 int CDECL _setmode(int fd,int mode)
2470 {
2471 ioinfo *info = get_ioinfo(fd);
2472 int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
2473 if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16)))
2474 ret = _O_WTEXT;
2475
2476 if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
2477 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
2478 *_errno() = EINVAL;
2479 release_ioinfo(info);
2480 return -1;
2481 }
2482
2483 if(mode == _O_BINARY) {
2484 info->wxflag &= ~WX_TEXT;
2485 info->exflag &= ~(EF_UTF8|EF_UTF16);
2486 release_ioinfo(info);
2487 return ret;
2488 }
2489
2490 info->wxflag |= WX_TEXT;
2491 if(mode == _O_TEXT)
2492 info->exflag &= ~(EF_UTF8|EF_UTF16);
2493 else if(mode == _O_U8TEXT)
2494 info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8;
2495 else
2496 info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16;
2497
2498 release_ioinfo(info);
2499 return ret;
2500
2501 }
2502
2503 /*********************************************************************
2504 * _tell (MSVCRT.@)
2505 */
2506 long CDECL _tell(int fd)
2507 {
2508 return _lseek(fd, 0, SEEK_CUR);
2509 }
2510
2511 /*********************************************************************
2512 * _telli64 (MSVCRT.@)
2513 */
2514 __int64 CDECL _telli64(int fd)
2515 {
2516 return _lseeki64(fd, 0, SEEK_CUR);
2517 }
2518
2519 /*********************************************************************
2520 * _tempnam (MSVCRT.@)
2521 */
2522 char * CDECL _tempnam(const char *dir, const char *prefix)
2523 {
2524 char tmpbuf[MAX_PATH];
2525 const char *tmp_dir = getenv("TMP");
2526
2527 if (tmp_dir) dir = tmp_dir;
2528
2529 TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2530 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2531 {
2532 TRACE("got name (%s)\n",tmpbuf);
2533 DeleteFileA(tmpbuf);
2534 return _strdup(tmpbuf);
2535 }
2536 TRACE("failed (%d)\n",GetLastError());
2537 return NULL;
2538 }
2539
2540 /*********************************************************************
2541 * _wtempnam (MSVCRT.@)
2542 */
2543 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
2544 {
2545 wchar_t tmpbuf[MAX_PATH];
2546
2547 TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2548 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2549 {
2550 TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2551 DeleteFileW(tmpbuf);
2552 return _wcsdup(tmpbuf);
2553 }
2554 TRACE("failed (%d)\n",GetLastError());
2555 return NULL;
2556 }
2557
2558 /*********************************************************************
2559 * _umask (MSVCRT.@)
2560 */
2561 int CDECL _umask(int umask)
2562 {
2563 int old_umask = MSVCRT_umask;
2564 TRACE("(%d)\n",umask);
2565 MSVCRT_umask = umask;
2566 return old_umask;
2567 }
2568
2569 /*********************************************************************
2570 * _write (MSVCRT.@)
2571 */
2572 int CDECL _write(int fd, const void* buf, unsigned int count)
2573 {
2574 DWORD num_written;
2575 ioinfo *info = get_ioinfo(fd);
2576 HANDLE hand = info->handle;
2577
2578 /* Don't trace small writes, it gets *very* annoying */
2579 #if 0
2580 if (count > 32)
2581 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2582 #endif
2583 if (hand == INVALID_HANDLE_VALUE)
2584 {
2585 *_errno() = EBADF;
2586 release_ioinfo(info);
2587 return -1;
2588 }
2589
2590 if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2591 {
2592 *_errno() = EINVAL;
2593 release_ioinfo(info);
2594 return -1;
2595 }
2596
2597 /* If appending, go to EOF */
2598 if (info->wxflag & WX_APPEND)
2599 _lseek(fd, 0, FILE_END);
2600
2601 if (!(info->wxflag & WX_TEXT))
2602 {
2603 if (WriteFile(hand, buf, count, &num_written, NULL)
2604 && (num_written == count))
2605 {
2606 release_ioinfo(info);
2607 return num_written;
2608 }
2609 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2610 hand, GetLastError());
2611 *_errno() = ENOSPC;
2612 }
2613 else
2614 {
2615 unsigned int i, j, nr_lf, size;
2616 char *p = NULL;
2617 const char *q;
2618 const char *s = buf, *buf_start = buf;
2619
2620 if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2621 {
2622 /* find number of \n */
2623 for (nr_lf=0, i=0; i<count; i++)
2624 if (s[i] == '\n')
2625 nr_lf++;
2626 if (nr_lf)
2627 {
2628 size = count+nr_lf;
2629 if ((q = p = malloc(size)))
2630 {
2631 for (s = buf, i = 0, j = 0; i < count; i++)
2632 {
2633 if (s[i] == '\n')
2634 p[j++] = '\r';
2635 p[j++] = s[i];
2636 }
2637 }
2638 else
2639 {
2640 FIXME("Malloc failed\n");
2641 nr_lf = 0;
2642 size = count;
2643 q = buf;
2644 }
2645 }
2646 else
2647 {
2648 size = count;
2649 q = buf;
2650 }
2651 }
2652 else if (info->exflag & EF_UTF16)
2653 {
2654 for (nr_lf=0, i=0; i<count; i+=2)
2655 if (s[i]=='\n' && s[i+1]==0)
2656 nr_lf += 2;
2657 if (nr_lf)
2658 {
2659 size = count+nr_lf;
2660 if ((q = p = malloc(size)))
2661 {
2662 for (s=buf, i=0, j=0; i<count; i++)
2663 {
2664 if (s[i]=='\n' && s[i+1]==0)
2665 {
2666 p[j++] = '\r';
2667 p[j++] = 0;
2668 }
2669 p[j++] = s[i++];
2670 p[j++] = s[i];
2671 }
2672 }
2673 else
2674 {
2675 FIXME("Malloc failed\n");
2676 nr_lf = 0;
2677 size = count;
2678 q = buf;
2679 }
2680 }
2681 else
2682 {
2683 size = count;
2684 q = buf;
2685 }
2686 }
2687 else
2688 {
2689 DWORD conv_len;
2690
2691 for(nr_lf=0, i=0; i<count; i+=2)
2692 if (s[i]=='\n' && s[i+1]==0)
2693 nr_lf++;
2694
2695 conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2696 if(!conv_len) {
2697 _dosmaperr(GetLastError());
2698 free(p);
2699 release_ioinfo(info);
2700 return -1;
2701 }
2702
2703 size = conv_len+nr_lf;
2704 if((p = malloc(count+nr_lf*2+size)))
2705 {
2706 for (s=buf, i=0, j=0; i<count; i++)
2707 {
2708 if (s[i]=='\n' && s[i+1]==0)
2709 {
2710 p[j++] = '\r';
2711 p[j++] = 0;
2712 }
2713 p[j++] = s[i++];
2714 p[j++] = s[i];
2715 }
2716 q = p+count+nr_lf*2;
2717 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
2718 p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
2719 }
2720 else
2721 {
2722 FIXME("Malloc failed\n");
2723 nr_lf = 0;
2724 size = count;
2725 q = buf;
2726 }
2727 }
2728
2729 if (!WriteFile(hand, q, size, &num_written, NULL))
2730 num_written = -1;
2731 release_ioinfo(info);
2732 if(p)
2733 free(p);
2734 if (num_written != size)
2735 {
2736 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2737 fd, hand, GetLastError(), num_written);
2738 *_errno() = ENOSPC;
2739 return s - buf_start;
2740 }
2741 return count;
2742 }
2743
2744 release_ioinfo(info);
2745 return -1;
2746 }
2747
2748 /*********************************************************************
2749 * _putw (MSVCRT.@)
2750 */
2751 int CDECL _putw(int val, FILE* file)
2752 {
2753 int len;
2754
2755 _lock_file(file);
2756 len = _write(file->_file, &val, sizeof(val));
2757 if (len == sizeof(val)) {
2758 _unlock_file(file);
2759 return val;
2760 }
2761
2762 file->_flag |= _IOERR;
2763 _unlock_file(file);
2764 return EOF;
2765 }
2766
2767 /*********************************************************************
2768 * fclose (MSVCRT.@)
2769 */
2770 int CDECL fclose(FILE* file)
2771 {
2772 int r, flag;
2773
2774 _lock_file(file);
2775 flag = file->_flag;
2776 free(file->_tmpfname);
2777 file->_tmpfname = NULL;
2778 /* flush stdio buffers */
2779 if(file->_flag & _IOWRT)
2780 fflush(file);
2781 if(file->_flag & _IOMYBUF)
2782 free(file->_base);
2783
2784 r=_close(file->_file);
2785
2786 file->_flag = 0;
2787 _unlock_file(file);
2788 if(file<_iob || file>=_iob+_IOB_ENTRIES)
2789 DeleteCriticalSection(&((file_crit*)file)->crit);
2790
2791 if(file == msvcrt_get_file(MSVCRT_stream_idx-1)) {
2792 while(MSVCRT_stream_idx>3 && !file->_flag) {
2793 MSVCRT_stream_idx--;
2794 file = msvcrt_get_file(MSVCRT_stream_idx-1);
2795 }
2796 }
2797
2798 return ((r == -1) || (flag & _IOERR) ? EOF : 0);
2799 }
2800
2801 /*********************************************************************
2802 * feof (MSVCRT.@)
2803 */
2804 int CDECL feof(FILE* file)
2805 {
2806 return file->_flag & _IOEOF;
2807 }
2808
2809 /*********************************************************************
2810 * ferror (MSVCRT.@)
2811 */
2812 int CDECL ferror(FILE* file)
2813 {
2814 return file->_flag & _IOERR;
2815 }
2816
2817 /*********************************************************************
2818 * _filbuf (MSVCRT.@)
2819 */
2820 int CDECL _filbuf(FILE* file)
2821 {
2822 unsigned char c;
2823 _lock_file(file);
2824
2825 if(file->_flag & _IOSTRG) {
2826 _unlock_file(file);
2827 return EOF;
2828 }
2829
2830 /* Allocate buffer if needed */
2831 if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
2832 msvcrt_alloc_buffer(file);
2833
2834 if(!(file->_flag & _IOREAD)) {
2835 if(file->_flag & _IORW)
2836 file->_flag |= _IOREAD;
2837 else {
2838 _unlock_file(file);
2839 return EOF;
2840 }
2841 }
2842
2843 if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
2844 int r;
2845 if ((r = _read(file->_file,&c,1)) != 1) {
2846 file->_flag |= (r == 0) ? _IOEOF : _IOERR;
2847 _unlock_file(file);
2848 return EOF;
2849 }
2850
2851 _unlock_file(file);
2852 return c;
2853 } else {
2854 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
2855 if(file->_cnt<=0) {
2856 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2857 file->_cnt = 0;
2858 _unlock_file(file);
2859 return EOF;
2860 }
2861
2862 file->_cnt--;
2863 file->_ptr = file->_base+1;
2864 c = *(unsigned char *)file->_base;
2865 _unlock_file(file);
2866 return c;
2867 }
2868 }
2869
2870 /*********************************************************************
2871 * fgetc (MSVCRT.@)
2872 */
2873 int CDECL fgetc(FILE* file)
2874 {
2875 unsigned char *i;
2876 unsigned int j;
2877
2878 _lock_file(file);
2879 if (file->_cnt>0) {
2880 file->_cnt--;
2881 i = (unsigned char *)file->_ptr++;
2882 j = *i;
2883 } else
2884 j = _filbuf(file);
2885
2886 _unlock_file(file);
2887 return j;
2888 }
2889
2890 /*********************************************************************
2891 * _fgetchar (MSVCRT.@)
2892 */
2893 int CDECL _fgetchar(void)
2894 {
2895 return fgetc(stdin);
2896 }
2897
2898 /*********************************************************************
2899 * fgets (MSVCRT.@)
2900 */
2901 char * CDECL fgets(char *s, int size, FILE* file)
2902 {
2903 int cc = EOF;
2904 char * buf_start = s;
2905
2906 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2907 file,file->_file,s,size);
2908
2909 _lock_file(file);
2910
2911 while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n')
2912 {
2913 *s++ = (char)cc;
2914 size --;
2915 }
2916 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
2917 {
2918 TRACE(":nothing read\n");
2919 _unlock_file(file);
2920 return NULL;
2921 }
2922 if ((cc != EOF) && (size > 1))
2923 *s++ = cc;
2924 *s = '\0';
2925 TRACE(":got %s\n", debugstr_a(buf_start));
2926 _unlock_file(file);
2927 return buf_start;
2928 }
2929
2930 /*********************************************************************
2931 * fgetwc (MSVCRT.@)
2932 */
2933 wint_t CDECL fgetwc(FILE* file)
2934 {
2935 wint_t ret;
2936 int ch;
2937
2938 _lock_file(file);
2939
2940 if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
2941 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
2942 char *p;
2943
2944 for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
2945 ch = fgetc(file);
2946 if(ch == EOF) {
2947 ret = WEOF;
2948 break;
2949 }
2950 *p = (char)ch;
2951 }
2952 }else {
2953 char mbs[MB_LEN_MAX];
2954 int len = 0;
2955
2956 ch = fgetc(file);
2957 if(ch != EOF) {
2958 mbs[0] = (char)ch;
2959 if(isleadbyte((unsigned char)mbs[0])) {
2960 ch = fgetc(file);
2961 if(ch != EOF) {
2962 mbs[1] = (char)ch;
2963 len = 2;
2964 }
2965 }else {
2966 len = 1;
2967 }
2968 }
2969
2970 if(!len || mbtowc(&ret, mbs, len)==-1)
2971 ret = WEOF;
2972 }
2973
2974 _unlock_file(file);
2975 return ret;
2976 }
2977
2978 /*********************************************************************
2979 * _getw (MSVCRT.@)
2980 */
2981 int CDECL _getw(FILE* file)
2982 {
2983 char *ch;
2984 int i, k;
2985 unsigned int j;
2986 ch = (char *)&i;
2987
2988 _lock_file(file);
2989 for (j=0; j<sizeof(int); j++) {
2990 k = fgetc(file);
2991 if (k == EOF) {
2992 file->_flag |= _IOEOF;
2993 _unlock_file(file);
2994 return EOF;
2995 }
2996 ch[j] = k;
2997 }
2998
2999 _unlock_file(file);
3000 return i;
3001 }
3002
3003 /*********************************************************************
3004 * getwc (MSVCRT.@)
3005 */
3006 wint_t CDECL getwc(FILE* file)
3007 {
3008 return fgetwc(file);
3009 }
3010
3011 /*********************************************************************
3012 * _fgetwchar (MSVCRT.@)
3013 */
3014 wint_t CDECL _fgetwchar(void)
3015 {
3016 return fgetwc(stdin);
3017 }
3018
3019 /*********************************************************************
3020 * getwchar (MSVCRT.@)
3021 */
3022 wint_t CDECL getwchar(void)
3023 {
3024 return _fgetwchar();
3025 }
3026
3027 /*********************************************************************
3028 * fgetws (MSVCRT.@)
3029 */
3030 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
3031 {
3032 int cc = WEOF;
3033 wchar_t * buf_start = s;
3034
3035 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3036 file,file->_file,s,size);
3037
3038 _lock_file(file);
3039
3040 while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n')
3041 {
3042 *s++ = (char)cc;
3043 size --;
3044 }
3045 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3046 {
3047 TRACE(":nothing read\n");
3048 _unlock_file(file);
3049 return NULL;
3050 }
3051 if ((cc != WEOF) && (size > 1))
3052 *s++ = cc;
3053 *s = 0;
3054 TRACE(":got %s\n", debugstr_w(buf_start));
3055 _unlock_file(file);
3056 return buf_start;
3057 }
3058
3059 /*********************************************************************
3060 * fwrite (MSVCRT.@)
3061 */
3062 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
3063 {
3064 size_t wrcnt=size * nmemb;
3065 int written = 0;
3066 if (size == 0)
3067 return 0;
3068
3069 _lock_file(file);
3070
3071 while(wrcnt) {
3072 #ifndef __REACTOS__
3073 if(file->_cnt < 0) {
3074 WARN("negative file->_cnt value in %p\n", file);
3075 file->_flag |= MSVCRT__IOERR;
3076 break;
3077 } else
3078 #endif
3079 if(file->_cnt) {
3080 int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3081 memcpy(file->_ptr, ptr, pcnt);
3082 file->_cnt -= pcnt;
3083 file->_ptr += pcnt;
3084 written += pcnt;
3085 wrcnt -= pcnt;
3086 ptr = (const char*)ptr + pcnt;
3087 } else if((file->_flag & _IONBF)
3088 || ((file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= file->_bufsiz)
3089 || (!(file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
3090 size_t pcnt;
3091 int bufsiz;
3092
3093 if(file->_flag & _IONBF)
3094 bufsiz = 1;
3095 else if(!(file->_flag & (_IOMYBUF | _USERBUF)))
3096 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
3097 else
3098 bufsiz = file->_bufsiz;
3099
3100 pcnt = (wrcnt / bufsiz) * bufsiz;
3101
3102 if(msvcrt_flush_buffer(file) == EOF)
3103 break;
3104
3105 if(_write(file->_file, ptr, pcnt) <= 0) {
3106 file->_flag |= _IOERR;
3107 break;
3108 }
3109 written += pcnt;
3110 wrcnt -= pcnt;
3111 ptr = (const char*)ptr + pcnt;
3112 } else {
3113 if(_flsbuf(*(const char*)ptr, file) == EOF)
3114 break;
3115 written++;
3116 wrcnt--;
3117 ptr = (const char*)ptr + 1;
3118 }
3119 }
3120
3121 _unlock_file(file);
3122 return written / size;
3123 }
3124
3125 /*********************************************************************
3126 * fputwc (MSVCRT.@)
3127 * FORKED for ReactOS, don't sync with Wine!
3128 * References:
3129 * - http://jira.reactos.org/browse/CORE-6495
3130 * - http://bugs.winehq.org/show_bug.cgi?id=8598
3131 */
3132 wint_t CDECL fputwc(wchar_t c, FILE* stream)
3133 {
3134 /* If this is a real file stream (and not some temporary one for
3135 sprintf-like functions), check whether it is opened in text mode.
3136 In this case, we have to perform an implicit conversion to ANSI. */
3137 if (!(stream->_flag & _IOSTRG) && get_ioinfo_nolock(stream->_file)->wxflag & WX_TEXT)
3138 {
3139 /* Convert to multibyte in text mode */
3140 char mbc[MB_LEN_MAX];
3141 int mb_return;
3142
3143 mb_return = wctomb(mbc, c);
3144
3145 if(mb_return == -1)
3146 return WEOF;
3147
3148 /* Output all characters */
3149 if (fwrite(mbc, mb_return, 1, stream) != 1)
3150 return WEOF;
3151 }
3152 else
3153 {
3154 if (fwrite(&c, sizeof(c), 1, stream) != 1)
3155 return WEOF;
3156 }
3157
3158 return c;
3159 }
3160
3161 /*********************************************************************
3162 * _fputwchar (MSVCRT.@)
3163 */
3164 wint_t CDECL _fputwchar(wint_t wc)
3165 {
3166 return fputwc(wc, stdout);
3167 }
3168
3169 /*********************************************************************
3170 * _wfsopen (MSVCRT.@)
3171 */
3172 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
3173 {
3174 FILE* file;
3175 int open_flags, stream_flags, fd;
3176
3177 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3178
3179 /* map mode string to open() flags. "man fopen" for possibilities. */
3180 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3181 return NULL;
3182
3183 LOCK_FILES();
3184 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
3185 if (fd < 0)
3186 file = NULL;
3187 else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3188 != -1)
3189 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3190 else if (file)
3191 {
3192 file->_flag = 0;
3193 file = NULL;
3194 }
3195
3196 TRACE(":got (%p)\n",file);
3197 if (fd >= 0 && !file)
3198 _close(fd);
3199 UNLOCK_FILES();
3200 return file;
3201 }
3202
3203 /*********************************************************************
3204 * _fsopen (MSVCRT.@)
3205 */
3206 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
3207 {
3208 FILE *ret;
3209 wchar_t *pathW = NULL, *modeW = NULL;
3210
3211 if (path && !(pathW = msvcrt_wstrdupa(path))) {
3212 _invalid_parameter(NULL, NULL, NULL, 0, 0);
3213 *_errno() = EINVAL;
3214 return NULL;
3215 }
3216 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3217 {
3218 free(pathW);
3219 _invalid_parameter(NULL, NULL, NULL, 0, 0);
3220 *_errno() = EINVAL;
3221 return NULL;
3222 }
3223
3224 ret = _wfsopen(pathW, modeW, share);
3225
3226 free(pathW);
3227 free(modeW);
3228 return ret;
3229 }
3230
3231 /*********************************************************************
3232 * fopen (MSVCRT.@)
3233 */
3234 FILE * CDECL fopen(const char *path, const char *mode)
3235 {
3236 return _fsopen( path, mode, _SH_DENYNO );
3237 }
3238
3239 /*********************************************************************
3240 * fopen_s (MSVCRT.@)
3241 */
3242 int CDECL fopen_s(FILE** pFile,
3243 const char *filename, const char *mode)
3244 {
3245 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
3246 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;