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