3458343145a29fb410cca2c317faebd4b7f54cad
[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 static int fdstart = 3; /* first unallocated fd */
129 static int fdend = 3; /* highest allocated fd */
130
131 typedef struct {
132 FILE file;
133 CRITICAL_SECTION crit;
134 } file_crit;
135
136 FILE _iob[_IOB_ENTRIES] = { { 0 } };
137 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { NULL };
138 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
139
140 /* INTERNAL: process umask */
141 static int MSVCRT_umask = 0;
142
143 /* INTERNAL: static data for tmpnam and _wtmpname functions */
144 static int tmpnam_unique;
145
146 /* This critical section protects the tables __pioinfo and fstreams,
147 * and their related indexes, fdstart, fdend,
148 * and MSVCRT_stream_idx, from race conditions.
149 * It doesn't protect against race conditions manipulating the underlying files
150 * or flags; doing so would probably be better accomplished with per-file
151 * protection, rather than locking the whole table for every change.
152 */
153 static CRITICAL_SECTION MSVCRT_file_cs;
154 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
155 {
156 0, 0, &MSVCRT_file_cs,
157 { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
158 0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
159 };
160 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
161 #define LOCK_FILES() do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
162 #define UNLOCK_FILES() do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
163
164 static inline ioinfo* get_ioinfo_nolock(int fd)
165 {
166 ioinfo *ret = NULL;
167 if(fd>=0 && fd<MSVCRT_MAX_FILES)
168 ret = __pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
169 if(!ret)
170 return &__badioinfo;
171
172 return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
173 }
174
175 /*static*/ inline ioinfo* get_ioinfo(int fd)
176 {
177 ioinfo *ret = get_ioinfo_nolock(fd);
178 if(ret == &__badioinfo)
179 return ret;
180 if(!(ret->exflag & EF_CRIT_INIT)) {
181 LOCK_FILES();
182 if(!(ret->exflag & EF_CRIT_INIT)) {
183 InitializeCriticalSection(&ret->crit);
184 ret->exflag |= EF_CRIT_INIT;
185 }
186 UNLOCK_FILES();
187 }
188 EnterCriticalSection(&ret->crit);
189 return ret;
190 }
191
192 static inline BOOL alloc_pioinfo_block(int fd)
193 {
194 ioinfo *block;
195 int i;
196
197 if(fd<0 || fd>=MSVCRT_MAX_FILES)
198 {
199 *_errno() = ENFILE;
200 return FALSE;
201 }
202
203 block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
204 if(!block)
205 {
206 WARN(":out of memory!\n");
207 *_errno() = ENOMEM;
208 return FALSE;
209 }
210 for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
211 block[i].handle = INVALID_HANDLE_VALUE;
212 if(InterlockedCompareExchangePointer((void**)&__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL))
213 free(block);
214 return TRUE;
215 }
216
217 static inline ioinfo* get_ioinfo_alloc_fd(int fd)
218 {
219 ioinfo *ret, *info;
220
221 ret = get_ioinfo(fd);
222 if(ret != &__badioinfo)
223 {
224 LOCK_FILES();
225 /* locate next free slot */
226 if (fd == fdstart && fd == fdend)
227 fdstart = fdend + 1;
228 else if (fd == fdstart)
229 {
230 fdstart++;
231 while (fdstart < fdend &&
232 ((info = get_ioinfo_nolock(fdstart))->exflag & EF_CRIT_INIT))
233 {
234 if (TryEnterCriticalSection(&info->crit))
235 {
236 if (info->handle == INVALID_HANDLE_VALUE)
237 {
238 LeaveCriticalSection(&info->crit);
239 break;
240 }
241 LeaveCriticalSection(&info->crit);
242 }
243 fdstart++;
244 }
245 }
246 /* update last fd in use */
247 if (fd >= fdend)
248 fdend = fd + 1;
249 TRACE("fdstart is %d, fdend is %d\n", fdstart, fdend);
250 UNLOCK_FILES();
251 return ret;
252 }
253
254 if(!alloc_pioinfo_block(fd))
255 return &__badioinfo;
256
257 ret = get_ioinfo(fd);
258 if(ret == &__badioinfo)
259 return ret;
260
261 LOCK_FILES();
262 /* locate next free slot */
263 if (fd == fdstart && fd == fdend)
264 fdstart = fdend + 1;
265 else if (fd == fdstart)
266 {
267 fdstart++;
268 while (fdstart < fdend &&
269 ((info = get_ioinfo_nolock(fdstart))->exflag & EF_CRIT_INIT))
270 {
271 if (TryEnterCriticalSection(&info->crit))
272 {
273 if (info->handle == INVALID_HANDLE_VALUE)
274 {
275 LeaveCriticalSection(&info->crit);
276 break;
277 }
278 LeaveCriticalSection(&info->crit);
279 }
280 fdstart++;
281 }
282 }
283 /* update last fd in use */
284 if (fd >= fdend)
285 fdend = fd + 1;
286 TRACE("fdstart is %d, fdend is %d\n", fdstart, fdend);
287 UNLOCK_FILES();
288
289 return ret;
290 }
291
292 /*static*/ inline void release_ioinfo(ioinfo *info)
293 {
294 if(info!=&__badioinfo && info->exflag & EF_CRIT_INIT)
295 LeaveCriticalSection(&info->crit);
296 }
297
298 static inline FILE* msvcrt_get_file(int i)
299 {
300 file_crit *ret;
301
302 if(i >= MSVCRT_max_streams)
303 return NULL;
304
305 if(i < _IOB_ENTRIES)
306 return &_iob[i];
307
308 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
309 if(!ret) {
310 MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
311 if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
312 ERR("out of memory\n");
313 *_errno() = ENOMEM;
314 return NULL;
315 }
316
317 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
318 } else
319 ret += i%MSVCRT_FD_BLOCK_SIZE;
320
321 return &ret->file;
322 }
323
324 /* INTERNAL: free a file entry fd */
325 static void msvcrt_free_fd(int fd)
326 {
327 ioinfo *fdinfo = get_ioinfo(fd);
328
329 if(fdinfo != &__badioinfo)
330 {
331 fdinfo->handle = INVALID_HANDLE_VALUE;
332 fdinfo->wxflag = 0;
333 }
334 TRACE(":fd (%d) freed\n",fd);
335
336 if (fd < 3)
337 {
338 switch (fd)
339 {
340 case 0:
341 SetStdHandle(STD_INPUT_HANDLE, 0);
342 break;
343 case 1:
344 SetStdHandle(STD_OUTPUT_HANDLE, 0);
345 break;
346 case 2:
347 SetStdHandle(STD_ERROR_HANDLE, 0);
348 break;
349 }
350 }
351 release_ioinfo(fdinfo);
352
353 LOCK_FILES();
354 if (fd == fdend - 1)
355 fdend--;
356 if (fd < fdstart)
357 fdstart = fd;
358 UNLOCK_FILES();
359 }
360
361 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag)
362 {
363 fdinfo->handle = hand;
364 fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY));
365 fdinfo->lookahead[0] = '\n';
366 fdinfo->lookahead[1] = '\n';
367 fdinfo->lookahead[2] = '\n';
368 fdinfo->exflag &= EF_CRIT_INIT;
369
370 switch (fdinfo-__pioinfo[0])
371 {
372 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
373 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
374 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
375 }
376 }
377
378 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
379 /*static*/ int msvcrt_alloc_fd(HANDLE hand, int flag)
380 {
381 ioinfo *info;
382 int fd;
383
384 LOCK_FILES();
385 fd = fdstart;
386 TRACE(":handle (%p) allocating fd (%d)\n", hand, fd);
387
388 if (fd >= MSVCRT_MAX_FILES)
389 {
390 UNLOCK_FILES();
391 WARN(":files exhausted!\n");
392 *_errno() = ENFILE;
393 return -1;
394 }
395
396 info = get_ioinfo_alloc_fd(fd);
397 UNLOCK_FILES();
398 if(info == &__badioinfo)
399 return -1;
400
401 msvcrt_set_fd(info, hand, flag);
402 release_ioinfo(info);
403 return fd;
404 }
405
406 /* INTERNAL: Allocate a FILE* for an fd slot */
407 /* caller must hold the files lock */
408 static FILE* msvcrt_alloc_fp(void)
409 {
410 int i;
411 FILE *file;
412
413 for (i = 3; i < MSVCRT_max_streams; i++)
414 {
415 file = msvcrt_get_file(i);
416 if (!file)
417 return NULL;
418
419 if (file->_flag == 0)
420 {
421 if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++;
422 return file;
423 }
424 }
425
426 return NULL;
427 }
428
429 /* INTERNAL: initialize a FILE* from an open fd */
430 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags)
431 {
432 TRACE(":fd (%d) allocating FILE*\n",fd);
433 if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN))
434 {
435 WARN(":invalid fd %d\n",fd);
436 *__doserrno() = 0;
437 *_errno() = EBADF;
438 return -1;
439 }
440 file->_ptr = file->_base = NULL;
441 file->_cnt = 0;
442 file->_file = fd;
443 file->_flag = stream_flags;
444 file->_tmpfname = NULL;
445
446 if(file<_iob || file>=_iob+_IOB_ENTRIES)
447 InitializeCriticalSection(&((file_crit*)file)->crit);
448
449 TRACE(":got FILE* (%p)\n",file);
450 return 0;
451 }
452
453 /* INTERNAL: Create an inheritance data block (for spawned process)
454 * The inheritance block is made of:
455 * 00 int nb of file descriptor (NBFD)
456 * 04 char file flags (wxflag): repeated for each fd
457 * 4+NBFD HANDLE file handle: repeated for each fd
458 */
459 unsigned create_io_inherit_block(WORD *size, BYTE **block)
460 {
461 int fd, last_fd;
462 char* wxflag_ptr;
463 HANDLE* handle_ptr;
464 ioinfo* fdinfo;
465
466 for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--)
467 if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE)
468 break;
469 last_fd++;
470
471 *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd;
472 *block = calloc(1, *size);
473 if (!*block)
474 {
475 *size = 0;
476 return FALSE;
477 }
478 wxflag_ptr = (char*)*block + sizeof(unsigned);
479 handle_ptr = (HANDLE*)(wxflag_ptr + last_fd);
480
481 *(unsigned*)*block = last_fd;
482 for (fd = 0; fd < last_fd; fd++)
483 {
484 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
485 fdinfo = get_ioinfo(fd);
486 if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
487 {
488 *wxflag_ptr = fdinfo->wxflag;
489 *handle_ptr = fdinfo->handle;
490 }
491 else
492 {
493 *wxflag_ptr = 0;
494 *handle_ptr = INVALID_HANDLE_VALUE;
495 }
496 release_ioinfo(fdinfo);
497 wxflag_ptr++; handle_ptr++;
498 }
499 return TRUE;
500 }
501
502 /* INTERNAL: Set up all file descriptors,
503 * as well as default streams (stdin, stderr and stdout)
504 */
505 void msvcrt_init_io(void)
506 {
507 STARTUPINFOA si;
508 unsigned int i;
509 ioinfo *fdinfo;
510
511 GetStartupInfoA(&si);
512 if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
513 {
514 BYTE* wxflag_ptr;
515 HANDLE* handle_ptr;
516 unsigned int count;
517
518 count = *(unsigned*)si.lpReserved2;
519 wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
520 handle_ptr = (HANDLE*)(wxflag_ptr + count);
521
522 count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
523 count = min(count, MSVCRT_MAX_FILES);
524 for (i = 0; i < count; i++)
525 {
526 if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
527 {
528 fdinfo = get_ioinfo_alloc_fd(i);
529 if(fdinfo != &__badioinfo)
530 msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr);
531 release_ioinfo(fdinfo);
532 }
533
534 wxflag_ptr++; handle_ptr++;
535 }
536 fdend = max( 3, count );
537 for (fdstart = 3; fdstart < fdend; fdstart++)
538 if (get_ioinfo_nolock(fdstart)->handle == INVALID_HANDLE_VALUE) break;
539 }
540
541 fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO);
542 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
543 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
544 DWORD type = GetFileType(h);
545
546 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
547 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
548 }
549 release_ioinfo(fdinfo);
550
551 fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO);
552 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
553 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
554 DWORD type = GetFileType(h);
555
556 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
557 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
558 }
559 release_ioinfo(fdinfo);
560
561 fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO);
562 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
563 HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
564 DWORD type = GetFileType(h);
565
566 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
567 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
568 }
569 release_ioinfo(fdinfo);
570
571 TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle,
572 get_ioinfo_nolock(STDOUT_FILENO)->handle,
573 get_ioinfo_nolock(STDERR_FILENO)->handle);
574
575 memset(_iob,0,3*sizeof(FILE));
576 for (i = 0; i < 3; i++)
577 {
578 /* FILE structs for stdin/out/err are static and never deleted */
579 _iob[i]._file = i;
580 _iob[i]._tmpfname = NULL;
581 _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
582 }
583 MSVCRT_stream_idx = 3;
584 }
585
586 /* INTERNAL: Flush stdio file buffer */
587 static int msvcrt_flush_buffer(FILE* file)
588 {
589 if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT &&
590 file->_flag & (_IOMYBUF|_USERBUF)) {
591 int cnt=file->_ptr-file->_base;
592 if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
593 file->_flag |= _IOERR;
594 return EOF;
595 }
596
597 if(file->_flag & _IORW)
598 file->_flag &= ~_IOWRT;
599
600 #ifdef __REACTOS__ /* CORE-11949 */
601 file->_ptr=file->_base;
602 file->_cnt=0;
603 #endif
604 }
605
606 #ifndef __REACTOS__ /* CORE-11949 */
607 file->_ptr=file->_base;
608 file->_cnt=0;
609 #endif
610 return 0;
611 }
612
613 /*********************************************************************
614 * _isatty (MSVCRT.@)
615 */
616 int CDECL _isatty(int fd)
617 {
618 TRACE(":fd (%d)\n",fd);
619
620 return get_ioinfo_nolock(fd)->wxflag & WX_TTY;
621 }
622
623 /* INTERNAL: Allocate stdio file buffer */
624 /*static*/ BOOL msvcrt_alloc_buffer(FILE* file)
625 {
626 if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
627 && _isatty(file->_file))
628 return FALSE;
629
630 file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ);
631 if(file->_base) {
632 file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
633 file->_flag |= _IOMYBUF;
634 } else {
635 file->_base = (char*)(&file->_charbuf);
636 file->_bufsiz = 2;
637 file->_flag |= _IONBF;
638 }
639 file->_ptr = file->_base;
640 file->_cnt = 0;
641 return TRUE;
642 }
643
644 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
645 static BOOL add_std_buffer(FILE *file)
646 {
647 static char buffers[2][BUFSIZ];
648
649 if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
650 || (file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
651 || !_isatty(file->_file))
652 return FALSE;
653
654 file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
655 file->_bufsiz = file->_cnt = BUFSIZ;
656 file->_flag |= _USERBUF;
657 return TRUE;
658 }
659
660 /* INTERNAL: Removes temporary buffer from stdout or stderr */
661 /* Only call this function when add_std_buffer returned TRUE */
662 static void remove_std_buffer(FILE *file)
663 {
664 msvcrt_flush_buffer(file);
665 file->_ptr = file->_base = NULL;
666 file->_bufsiz = file->_cnt = 0;
667 file->_flag &= ~_USERBUF;
668 }
669
670 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
671 static int msvcrt_int_to_base32(int num, char *str)
672 {
673 char *p;
674 int n = num;
675 int digits = 0;
676
677 while (n != 0)
678 {
679 n >>= 5;
680 digits++;
681 }
682 p = str + digits;
683 *p = 0;
684 while (--p >= str)
685 {
686 *p = (num & 31) + '0';
687 if (*p > '9')
688 *p += ('a' - '0' - 10);
689 num >>= 5;
690 }
691
692 return digits;
693 }
694
695 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
696 static int msvcrt_int_to_base32_w(int num, wchar_t *str)
697 {
698 wchar_t *p;
699 int n = num;
700 int digits = 0;
701
702 while (n != 0)
703 {
704 n >>= 5;
705 digits++;
706 }
707 p = str + digits;
708 *p = 0;
709 while (--p >= str)
710 {
711 *p = (num & 31) + '0';
712 if (*p > '9')
713 *p += ('a' - '0' - 10);
714 num >>= 5;
715 }
716
717 return digits;
718 }
719
720 /* INTERNAL: Create a wide string from an ascii string */
721 wchar_t *msvcrt_wstrdupa(const char *str)
722 {
723 const unsigned int len = strlen(str) + 1 ;
724 wchar_t *wstr = malloc(len* sizeof (wchar_t));
725 if (!wstr)
726 return NULL;
727 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
728 return wstr;
729 }
730
731 /*********************************************************************
732 * __iob_func(MSVCRT.@)
733 */
734 FILE * CDECL __iob_func(void)
735 {
736 return &_iob[0];
737 }
738
739 /*********************************************************************
740 * _access (MSVCRT.@)
741 */
742 int CDECL _access(const char *filename, int mode)
743 {
744 DWORD attr = GetFileAttributesA(filename);
745
746 TRACE("(%s,%d) %d\n",filename,mode,attr);
747
748 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
749 {
750 _dosmaperr(GetLastError());
751 return -1;
752 }
753 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
754 {
755 _set_errno(ERROR_ACCESS_DENIED);
756 return -1;
757 }
758 return 0;
759 }
760
761 /*********************************************************************
762 * _access_s (MSVCRT.@)
763 */
764 int CDECL _access_s(const char *filename, int mode)
765 {
766 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
767 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
768 {
769 _set_errno(EINVAL);
770 return -1;
771 }
772
773 return _access(filename, mode);
774 }
775
776 /*********************************************************************
777 * _waccess (MSVCRT.@)
778 */
779 int CDECL _waccess(const wchar_t *filename, int mode)
780 {
781 DWORD attr = GetFileAttributesW(filename);
782
783 TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
784
785 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
786 {
787 _dosmaperr(GetLastError());
788 return -1;
789 }
790 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
791 {
792 _set_errno(ERROR_ACCESS_DENIED);
793 return -1;
794 }
795 return 0;
796 }
797
798 /*********************************************************************
799 * _waccess_s (MSVCRT.@)
800 */
801 int CDECL _waccess_s(const wchar_t *filename, int mode)
802 {
803 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
804 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
805 {
806 *_errno() = EINVAL;
807 return -1;
808 }
809
810 return _waccess(filename, mode);
811 }
812
813 /*********************************************************************
814 * _chmod (MSVCRT.@)
815 */
816 int CDECL _chmod(const char *path, int flags)
817 {
818 DWORD oldFlags = GetFileAttributesA(path);
819
820 if (oldFlags != INVALID_FILE_ATTRIBUTES)
821 {
822 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
823 oldFlags | FILE_ATTRIBUTE_READONLY;
824
825 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
826 return 0;
827 }
828 _dosmaperr(GetLastError());
829 return -1;
830 }
831
832 /*********************************************************************
833 * _wchmod (MSVCRT.@)
834 */
835 int CDECL _wchmod(const wchar_t *path, int flags)
836 {
837 DWORD oldFlags = GetFileAttributesW(path);
838
839 if (oldFlags != INVALID_FILE_ATTRIBUTES)
840 {
841 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
842 oldFlags | FILE_ATTRIBUTE_READONLY;
843
844 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
845 return 0;
846 }
847 _dosmaperr(GetLastError());
848 return -1;
849 }
850
851 /*********************************************************************
852 * _unlink (MSVCRT.@)
853 */
854 int CDECL _unlink(const char *path)
855 {
856 TRACE("%s\n",debugstr_a(path));
857 if(DeleteFileA(path))
858 return 0;
859 TRACE("failed (%d)\n",GetLastError());
860 _dosmaperr(GetLastError());
861 return -1;
862 }
863
864 /*********************************************************************
865 * _wunlink (MSVCRT.@)
866 */
867 int CDECL _wunlink(const wchar_t *path)
868 {
869 TRACE("(%s)\n",debugstr_w(path));
870 if(DeleteFileW(path))
871 return 0;
872 TRACE("failed (%d)\n",GetLastError());
873 _dosmaperr(GetLastError());
874 return -1;
875 }
876
877 /*********************************************************************
878 * _commit (MSVCRT.@)
879 */
880 int CDECL _commit(int fd)
881 {
882 ioinfo *info = get_ioinfo(fd);
883 int ret;
884
885 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
886 if (info->handle == INVALID_HANDLE_VALUE)
887 ret = -1;
888 else if (!FlushFileBuffers(info->handle))
889 {
890 if (GetLastError() == ERROR_INVALID_HANDLE)
891 {
892 /* FlushFileBuffers fails for console handles
893 * so we ignore this error.
894 */
895 ret = 0;
896 }
897 else
898 {
899 TRACE(":failed-last error (%d)\n",GetLastError());
900 _dosmaperr(GetLastError());
901 ret = -1;
902 }
903 }
904 else
905 {
906 TRACE(":ok\n");
907 ret = 0;
908 }
909
910 release_ioinfo(info);
911 return ret;
912 }
913
914 /* _flushall calls fflush which calls _flushall */
915 int CDECL fflush(FILE* file);
916
917 /* INTERNAL: Flush all stream buffer */
918 static int msvcrt_flush_all_buffers(int mask)
919 {
920 int i, num_flushed = 0;
921 FILE *file;
922
923 LOCK_FILES();
924 for (i = 0; i < MSVCRT_stream_idx; i++) {
925 file = msvcrt_get_file(i);
926
927 if (file->_flag)
928 {
929 if(file->_flag & mask) {
930 fflush(file);
931 num_flushed++;
932 }
933 }
934 }
935 UNLOCK_FILES();
936
937 TRACE(":flushed (%d) handles\n",num_flushed);
938 return num_flushed;
939 }
940
941 /*********************************************************************
942 * _flushall (MSVCRT.@)
943 */
944 int CDECL _flushall(void)
945 {
946 return msvcrt_flush_all_buffers(_IOWRT | _IOREAD);
947 }
948
949 /*********************************************************************
950 * fflush (MSVCRT.@)
951 */
952 int CDECL fflush(FILE* file)
953 {
954 if(!file) {
955 msvcrt_flush_all_buffers(_IOWRT);
956 } else if(file->_flag & _IOWRT) {
957 int res;
958
959 _lock_file(file);
960 res = msvcrt_flush_buffer(file);
961 /* FIXME
962 if(!res && (file->_flag & _IOCOMMIT))
963 res = _commit(file->_file) ? EOF : 0;
964 */
965 _unlock_file(file);
966
967 return res;
968 } else if(file->_flag & _IOREAD) {
969 _lock_file(file);
970 file->_cnt = 0;
971 file->_ptr = file->_base;
972 _unlock_file(file);
973
974 return 0;
975 }
976 return 0;
977 }
978
979 /*********************************************************************
980 * _close (MSVCRT.@)
981 */
982 int CDECL _close(int fd)
983 {
984 ioinfo *info = get_ioinfo(fd);
985 int ret;
986
987 LOCK_FILES();
988 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
989 if (!(info->wxflag & WX_OPEN)) {
990 ret = -1;
991 } else {
992 ret = CloseHandle(info->handle) ? 0 : -1;
993 msvcrt_free_fd(fd);
994 if (ret) {
995 WARN(":failed-last error (%d)\n",GetLastError());
996 _dosmaperr(GetLastError());
997 ret = -1;
998 }
999 }
1000 UNLOCK_FILES();
1001 release_ioinfo(info);
1002 return ret;
1003 }
1004
1005 /*********************************************************************
1006 * _dup2 (MSVCRT.@)
1007 * NOTES
1008 * MSDN isn't clear on this point, but the remarks for _pipe
1009 * indicate file descriptors duplicated with _dup and _dup2 are always
1010 * inheritable.
1011 */
1012 int CDECL _dup2(int od, int nd)
1013 {
1014 ioinfo *info_od, *info_nd;
1015 int ret;
1016
1017 TRACE("(od=%d, nd=%d)\n", od, nd);
1018 LOCK_FILES();
1019
1020 if (od < nd)
1021 {
1022 info_od = get_ioinfo(od);
1023 info_nd = get_ioinfo_alloc_fd(nd);
1024 }
1025 else
1026 {
1027 info_nd = get_ioinfo_alloc_fd(nd);
1028 info_od = get_ioinfo(od);
1029 }
1030
1031 if (info_nd == &__badioinfo)
1032 {
1033 ret = -1;
1034 }
1035 else if (info_od->wxflag & WX_OPEN)
1036 {
1037 HANDLE handle;
1038
1039 if (DuplicateHandle(GetCurrentProcess(), info_od->handle,
1040 GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
1041 {
1042 int wxflag = info_od->wxflag & ~_O_NOINHERIT;
1043
1044 if (info_nd->wxflag & WX_OPEN)
1045 _close(nd);
1046
1047 msvcrt_set_fd(info_nd, handle, wxflag);
1048 /* _dup2 returns 0, not nd, on success */
1049 ret = 0;
1050 }
1051 else
1052 {
1053 ret = -1;
1054 _dosmaperr(GetLastError());
1055 }
1056 }
1057 else
1058 {
1059 *_errno() = EBADF;
1060 ret = -1;
1061 }
1062
1063 release_ioinfo(info_od);
1064 release_ioinfo(info_nd);
1065 UNLOCK_FILES();
1066 return ret;
1067 }
1068
1069 /*********************************************************************
1070 * _dup (MSVCRT.@)
1071 */
1072 int CDECL _dup(int od)
1073 {
1074 int fd, ret;
1075
1076 LOCK_FILES();
1077 fd = fdstart;
1078 if (_dup2(od, fd) == 0)
1079 ret = fd;
1080 else
1081 ret = -1;
1082 UNLOCK_FILES();
1083 return ret;
1084 }
1085
1086 /*********************************************************************
1087 * _eof (MSVCRT.@)
1088 */
1089 int CDECL _eof(int fd)
1090 {
1091 ioinfo *info = get_ioinfo(fd);
1092 DWORD curpos,endpos;
1093 LONG hcurpos,hendpos;
1094
1095 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1096
1097 if (info->handle == INVALID_HANDLE_VALUE)
1098 {
1099 release_ioinfo(info);
1100 return -1;
1101 }
1102
1103 if (info->wxflag & WX_ATEOF)
1104 {
1105 release_ioinfo(info);
1106 return TRUE;
1107 }
1108
1109 /* Otherwise we do it the hard way */
1110 hcurpos = hendpos = 0;
1111 curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT);
1112 endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END);
1113
1114 if (curpos == endpos && hcurpos == hendpos)
1115 {
1116 /* FIXME: shouldn't WX_ATEOF be set here? */
1117 release_ioinfo(info);
1118 return TRUE;
1119 }
1120
1121 SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN);
1122 release_ioinfo(info);
1123 return FALSE;
1124 }
1125
1126 /*********************************************************************
1127 * _fcloseall (MSVCRT.@)
1128 */
1129 int CDECL _fcloseall(void)
1130 {
1131 int num_closed = 0, i;
1132 FILE *file;
1133
1134 LOCK_FILES();
1135 for (i = 3; i < MSVCRT_stream_idx; i++) {
1136 file = msvcrt_get_file(i);
1137
1138 if (file->_flag && !fclose(file))
1139 num_closed++;
1140 }
1141 UNLOCK_FILES();
1142
1143 TRACE(":closed (%d) handles\n",num_closed);
1144 return num_closed;
1145 }
1146
1147 /* free everything on process exit */
1148 void msvcrt_free_io(void)
1149 {
1150 unsigned int i;
1151 int j;
1152
1153 _flushall();
1154 _fcloseall();
1155
1156 for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
1157 {
1158 if(!__pioinfo[i])
1159 continue;
1160
1161 for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++)
1162 {
1163 if(__pioinfo[i][j].exflag & EF_CRIT_INIT)
1164 DeleteCriticalSection(&__pioinfo[i][j].crit);
1165 }
1166 free(__pioinfo[i]);
1167 }
1168
1169 for(j=0; j<MSVCRT_stream_idx; j++)
1170 {
1171 FILE *file = msvcrt_get_file(j);
1172 if(file<_iob || file>=_iob+_IOB_ENTRIES)
1173 {
1174 ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1175 DeleteCriticalSection(&((file_crit*)file)->crit);
1176 }
1177 }
1178
1179 for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1180 free(MSVCRT_fstream[i]);
1181 }
1182
1183 /*********************************************************************
1184 * _lseeki64 (MSVCRT.@)
1185 */
1186 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1187 {
1188 ioinfo *info = get_ioinfo(fd);
1189 LARGE_INTEGER ofs;
1190
1191 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1192
1193 if (info->handle == INVALID_HANDLE_VALUE)
1194 {
1195 release_ioinfo(info);
1196 return -1;
1197 }
1198
1199 if (whence < 0 || whence > 2)
1200 {
1201 release_ioinfo(info);
1202 *_errno() = EINVAL;
1203 return -1;
1204 }
1205
1206 TRACE(":fd (%d) to %s pos %s\n",
1207 fd,wine_dbgstr_longlong(offset),
1208 (whence==SEEK_SET)?"SEEK_SET":
1209 (whence==SEEK_CUR)?"SEEK_CUR":
1210 (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1211
1212 /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1213 * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1214 ofs.QuadPart = offset;
1215 if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1216 GetLastError() == ERROR_SUCCESS)
1217 {
1218 info->wxflag &= ~(WX_ATEOF|WX_READEOF);
1219 /* FIXME: What if we seek _to_ EOF - is EOF set? */
1220
1221 release_ioinfo(info);
1222 return ofs.QuadPart;
1223 }
1224 release_ioinfo(info);
1225 TRACE(":error-last error (%d)\n",GetLastError());
1226 _dosmaperr(GetLastError());
1227 return -1;
1228 }
1229
1230 /*********************************************************************
1231 * _lseek (MSVCRT.@)
1232 */
1233 LONG CDECL _lseek(int fd, LONG offset, int whence)
1234 {
1235 return (LONG)_lseeki64(fd, offset, whence);
1236 }
1237
1238 /*********************************************************************
1239 * _lock_file (MSVCRT.@)
1240 */
1241 void CDECL _lock_file(FILE *file)
1242 {
1243 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1244 _lock(_STREAM_LOCKS+(file-_iob));
1245 /* ReactOS: string streams dont need to be locked */
1246 else if(!(file->_flag & _IOSTRG))
1247 EnterCriticalSection(&((file_crit*)file)->crit);
1248 }
1249
1250 /*********************************************************************
1251 * _unlock_file (MSVCRT.@)
1252 */
1253 void CDECL _unlock_file(FILE *file)
1254 {
1255 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1256 _unlock(_STREAM_LOCKS+(file-_iob));
1257 /* ReactOS: string streams dont need to be locked */
1258 else if(!(file->_flag & _IOSTRG))
1259 LeaveCriticalSection(&((file_crit*)file)->crit);
1260
1261 }
1262
1263 /*********************************************************************
1264 * _locking (MSVCRT.@)
1265 *
1266 * This is untested; the underlying LockFile doesn't work yet.
1267 */
1268 int CDECL _locking(int fd, int mode, LONG nbytes)
1269 {
1270 ioinfo *info = get_ioinfo(fd);
1271 BOOL ret;
1272 DWORD cur_locn;
1273
1274 TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1275 if (info->handle == INVALID_HANDLE_VALUE)
1276 {
1277 release_ioinfo(info);
1278 return -1;
1279 }
1280
1281 if (mode < 0 || mode > 4)
1282 {
1283 release_ioinfo(info);
1284 *_errno() = EINVAL;
1285 return -1;
1286 }
1287
1288 TRACE(":fd (%d) by 0x%08x mode %s\n",
1289 fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
1290 (mode==_LK_LOCK)?"_LK_LOCK":
1291 (mode==_LK_NBLCK)?"_LK_NBLCK":
1292 (mode==_LK_RLCK)?"_LK_RLCK":
1293 (mode==_LK_NBRLCK)?"_LK_NBRLCK":
1294 "UNKNOWN");
1295
1296 if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
1297 {
1298 release_ioinfo(info);
1299 FIXME ("Seek failed\n");
1300 *_errno() = EINVAL; /* FIXME */
1301 return -1;
1302 }
1303 if (mode == _LK_LOCK || mode == _LK_RLCK)
1304 {
1305 int nretry = 10;
1306 ret = 1; /* just to satisfy gcc */
1307 while (nretry--)
1308 {
1309 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1310 if (ret) break;
1311 Sleep(1);
1312 }
1313 }
1314 else if (mode == _LK_UNLCK)
1315 ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1316 else
1317 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1318 /* FIXME - what about error settings? */
1319 release_ioinfo(info);
1320 return ret ? 0 : -1;
1321 }
1322
1323 /*********************************************************************
1324 * _fseeki64 (MSVCRT.@)
1325 */
1326 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1327 {
1328 int ret;
1329
1330 _lock_file(file);
1331 /* Flush output if needed */
1332 if(file->_flag & _IOWRT)
1333 msvcrt_flush_buffer(file);
1334
1335 if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1336 whence = SEEK_SET;
1337 offset += _ftelli64(file);
1338 }
1339
1340 /* Discard buffered input */
1341 file->_cnt = 0;
1342 file->_ptr = file->_base;
1343 /* Reset direction of i/o */
1344 if(file->_flag & _IORW) {
1345 file->_flag &= ~(_IOREAD|_IOWRT);
1346 }
1347 /* Clear end of file flag */
1348 file->_flag &= ~_IOEOF;
1349 ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1350
1351 _unlock_file(file);
1352 return ret;
1353 }
1354
1355 /*********************************************************************
1356 * fseek (MSVCRT.@)
1357 */
1358 int CDECL fseek(FILE* file, long offset, int whence)
1359 {
1360 return _fseeki64( file, offset, whence );
1361 }
1362
1363 /*********************************************************************
1364 * _chsize_s (MSVCRT.@)
1365 */
1366 int CDECL _chsize_s(int fd, __int64 size)
1367 {
1368 ioinfo *info;
1369 __int64 cur, pos;
1370 BOOL ret = FALSE;
1371
1372 TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size));
1373
1374 if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
1375
1376 info = get_ioinfo(fd);
1377 if (info->handle != INVALID_HANDLE_VALUE)
1378 {
1379 /* save the current file pointer */
1380 cur = _lseeki64(fd, 0, SEEK_CUR);
1381 if (cur >= 0)
1382 {
1383 pos = _lseeki64(fd, size, SEEK_SET);
1384 if (pos >= 0)
1385 {
1386 ret = SetEndOfFile(info->handle);
1387 if (!ret) _dosmaperr(GetLastError());
1388 }
1389
1390 /* restore the file pointer */
1391 _lseeki64(fd, cur, SEEK_SET);
1392 }
1393 }
1394
1395 release_ioinfo(info);
1396 return ret ? 0 : *_errno();
1397 }
1398
1399 /*********************************************************************
1400 * _chsize (MSVCRT.@)
1401 */
1402 int CDECL _chsize(int fd, long size)
1403 {
1404 /* _chsize_s returns errno on failure but _chsize should return -1 */
1405 return _chsize_s( fd, size ) == 0 ? 0 : -1;
1406 }
1407
1408 /*********************************************************************
1409 * clearerr (MSVCRT.@)
1410 */
1411 void CDECL clearerr(FILE* file)
1412 {
1413 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1414
1415 _lock_file(file);
1416 file->_flag &= ~(_IOERR | _IOEOF);
1417 _unlock_file(file);
1418 }
1419
1420 /*********************************************************************
1421 * rewind (MSVCRT.@)
1422 */
1423 void CDECL rewind(FILE* file)
1424 {
1425 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1426
1427 _lock_file(file);
1428 fseek(file, 0L, SEEK_SET);
1429 clearerr(file);
1430 _unlock_file(file);
1431 }
1432
1433 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1434 {
1435 int plus = strchrW(mode, '+') != NULL;
1436
1437 TRACE("%s\n", debugstr_w(mode));
1438
1439 while(*mode == ' ') mode++;
1440
1441 switch(*mode++)
1442 {
1443 case 'R': case 'r':
1444 *open_flags = plus ? _O_RDWR : _O_RDONLY;
1445 *stream_flags = plus ? _IORW : _IOREAD;
1446 break;
1447 case 'W': case 'w':
1448 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1449 *stream_flags = plus ? _IORW : _IOWRT;
1450 break;
1451 case 'A': case 'a':
1452 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1453 *stream_flags = plus ? _IORW : _IOWRT;
1454 break;
1455 default:
1456 MSVCRT_INVALID_PMT(0, EINVAL);
1457 return -1;
1458 }
1459
1460 *stream_flags |= _commode;
1461
1462 while (*mode && *mode!=',')
1463 switch (*mode++)
1464 {
1465 case 'B': case 'b':
1466 *open_flags |= _O_BINARY;
1467 *open_flags &= ~_O_TEXT;
1468 break;
1469 case 't':
1470 *open_flags |= _O_TEXT;
1471 *open_flags &= ~_O_BINARY;
1472 break;
1473 case 'D':
1474 *open_flags |= _O_TEMPORARY;
1475 break;
1476 case 'T':
1477 *open_flags |= _O_SHORT_LIVED;
1478 break;
1479 case 'c':
1480 *stream_flags |= _IOCOMMIT;
1481 break;
1482 case 'n':
1483 *stream_flags &= ~_IOCOMMIT;
1484 break;
1485 case 'N':
1486 *open_flags |= _O_NOINHERIT;
1487 break;
1488 case '+':
1489 case ' ':
1490 case 'a':
1491 case 'w':
1492 break;
1493 case 'S':
1494 case 'R':
1495 FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1496 break;
1497 default:
1498 ERR("incorrect mode flag: %c\n", mode[-1]);
1499 break;
1500 }
1501
1502 if(*mode == ',')
1503 {
1504 static const WCHAR ccs[] = {'c','c','s'};
1505 static const WCHAR utf8[] = {'u','t','f','-','8'};
1506 static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1507 static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1508
1509 mode++;
1510 while(*mode == ' ') mode++;
1511 if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1512 return -1;
1513 mode += sizeof(ccs)/sizeof(ccs[0]);
1514 while(*mode == ' ') mode++;
1515 if(!MSVCRT_CHECK_PMT(*mode == '='))
1516 return -1;
1517 mode++;
1518 while(*mode == ' ') mode++;
1519
1520 if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1521 {
1522 *open_flags |= _O_U8TEXT;
1523 mode += sizeof(utf8)/sizeof(utf8[0]);
1524 }
1525 else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1526 {
1527 *open_flags |= _O_U16TEXT;
1528 mode += sizeof(utf16le)/sizeof(utf16le[0]);
1529 }
1530 else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1531 {
1532 *open_flags |= _O_WTEXT;
1533 mode += sizeof(unicode)/sizeof(unicode[0]);
1534 }
1535 else
1536 {
1537 MSVCRT_INVALID_PMT(0, EINVAL);
1538 return -1;
1539 }
1540
1541 while(*mode == ' ') mode++;
1542 }
1543
1544 if(!MSVCRT_CHECK_PMT(*mode == 0))
1545 return -1;
1546 return 0;
1547 }
1548
1549 /*********************************************************************
1550 * _fdopen (MSVCRT.@)
1551 */
1552 FILE* CDECL _fdopen(int fd, const char *mode)
1553 {
1554 FILE *ret;
1555 wchar_t *modeW = NULL;
1556
1557 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1558
1559 ret = _wfdopen(fd, modeW);
1560
1561 free(modeW);
1562 return ret;
1563 }
1564
1565 /*********************************************************************
1566 * _wfdopen (MSVCRT.@)
1567 */
1568 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1569 {
1570 int open_flags, stream_flags;
1571 FILE* file;
1572
1573 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1574
1575 LOCK_FILES();
1576 if (!(file = msvcrt_alloc_fp()))
1577 file = NULL;
1578 else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1579 {
1580 file->_flag = 0;
1581 file = NULL;
1582 }
1583 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1584 UNLOCK_FILES();
1585
1586 return file;
1587 }
1588
1589 /*********************************************************************
1590 * _filelength (MSVCRT.@)
1591 */
1592 LONG CDECL _filelength(int fd)
1593 {
1594 LONG curPos = _lseek(fd, 0, SEEK_CUR);
1595 if (curPos != -1)
1596 {
1597 LONG endPos = _lseek(fd, 0, SEEK_END);
1598 if (endPos != -1)
1599 {
1600 if (endPos != curPos)
1601 _lseek(fd, curPos, SEEK_SET);
1602 return endPos;
1603 }
1604 }
1605 return -1;
1606 }
1607
1608 /*********************************************************************
1609 * _filelengthi64 (MSVCRT.@)
1610 */
1611 __int64 CDECL _filelengthi64(int fd)
1612 {
1613 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1614 if (curPos != -1)
1615 {
1616 __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1617 if (endPos != -1)
1618 {
1619 if (endPos != curPos)
1620 _lseeki64(fd, curPos, SEEK_SET);
1621 return endPos;
1622 }
1623 }
1624 return -1;
1625 }
1626
1627 /*********************************************************************
1628 * _fileno (MSVCRT.@)
1629 */
1630 int CDECL _fileno(FILE* file)
1631 {
1632 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1633 return file->_file;
1634 }
1635
1636 /*********************************************************************
1637 * _get_osfhandle (MSVCRT.@)
1638 */
1639 intptr_t CDECL _get_osfhandle(int fd)
1640 {
1641 HANDLE hand = get_ioinfo_nolock(fd)->handle;
1642 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1643
1644 if(hand == INVALID_HANDLE_VALUE)
1645 *_errno() = EBADF;
1646 return (intptr_t)hand;
1647 }
1648
1649 /*********************************************************************
1650 * _mktemp (MSVCRT.@)
1651 */
1652 char * CDECL _mktemp(char *pattern)
1653 {
1654 int numX = 0;
1655 char *retVal = pattern;
1656 int id;
1657 char letter = 'a';
1658
1659 if(!pattern)
1660 return NULL;
1661
1662 while(*pattern)
1663 numX = (*pattern++ == 'X')? numX + 1 : 0;
1664 if (numX < 6)
1665 return NULL;
1666 pattern--;
1667 id = GetCurrentProcessId();
1668 numX = 6;
1669 while(numX--)
1670 {
1671 int tempNum = id / 10;
1672 *pattern-- = id - (tempNum * 10) + '0';
1673 id = tempNum;
1674 }
1675 pattern++;
1676 do
1677 {
1678 *pattern = letter++;
1679 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
1680 return retVal;
1681 } while(letter <= 'z');
1682 return NULL;
1683 }
1684
1685 /*********************************************************************
1686 * _wmktemp (MSVCRT.@)
1687 */
1688 wchar_t * CDECL _wmktemp(wchar_t *pattern)
1689 {
1690 int numX = 0;
1691 wchar_t *retVal = pattern;
1692 int id;
1693 wchar_t letter = 'a';
1694
1695 while(*pattern)
1696 numX = (*pattern++ == 'X')? numX + 1 : 0;
1697 if (numX < 5)
1698 return NULL;
1699 pattern--;
1700 id = GetCurrentProcessId();
1701 numX = 6;
1702 while(numX--)
1703 {
1704 int tempNum = id / 10;
1705 *pattern-- = id - (tempNum * 10) + '0';
1706 id = tempNum;
1707 }
1708 pattern++;
1709 do
1710 {
1711 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1712 GetLastError() == ERROR_FILE_NOT_FOUND)
1713 return retVal;
1714 *pattern = letter++;
1715 } while(letter != '|');
1716 return NULL;
1717 }
1718
1719 /*static*/ unsigned split_oflags(unsigned oflags)
1720 {
1721 int wxflags = 0;
1722 unsigned unsupp; /* until we support everything */
1723
1724 if (oflags & _O_APPEND) wxflags |= WX_APPEND;
1725 if (oflags & _O_BINARY) {/* Nothing to do */}
1726 else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
1727 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
1728 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
1729 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
1730 else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */}
1731 else wxflags |= WX_TEXT; /* default to TEXT*/
1732 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
1733
1734 if ((unsupp = oflags & ~(
1735 _O_BINARY|_O_TEXT|_O_APPEND|
1736 _O_TRUNC|_O_EXCL|_O_CREAT|
1737 _O_RDWR|_O_WRONLY|_O_TEMPORARY|
1738 _O_NOINHERIT|
1739 _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
1740 _O_WTEXT|_O_U16TEXT|_O_U8TEXT
1741 )))
1742 ERR(":unsupported oflags 0x%04x\n",unsupp);
1743
1744 return wxflags;
1745 }
1746
1747 /*********************************************************************
1748 * _pipe (MSVCRT.@)
1749 */
1750 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
1751 {
1752 int ret = -1;
1753 SECURITY_ATTRIBUTES sa;
1754 HANDLE readHandle, writeHandle;
1755
1756 if (!pfds)
1757 {
1758 *_errno() = EINVAL;
1759 return -1;
1760 }
1761
1762 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1763 sa.bInheritHandle = !(textmode & _O_NOINHERIT);
1764 sa.lpSecurityDescriptor = NULL;
1765 if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1766 {
1767 unsigned int wxflags = split_oflags(textmode);
1768 int fd;
1769
1770 LOCK_FILES();
1771 fd = msvcrt_alloc_fd(readHandle, wxflags);
1772 if (fd != -1)
1773 {
1774 pfds[0] = fd;
1775 fd = msvcrt_alloc_fd(writeHandle, wxflags);
1776 if (fd != -1)
1777 {
1778 pfds[1] = fd;
1779 ret = 0;
1780 }
1781 else
1782 {
1783 _close(pfds[0]);
1784 CloseHandle(writeHandle);
1785 *_errno() = EMFILE;
1786 }
1787 }
1788 else
1789 {
1790 CloseHandle(readHandle);
1791 CloseHandle(writeHandle);
1792 *_errno() = EMFILE;
1793 }
1794 UNLOCK_FILES();
1795 }
1796 else
1797 _dosmaperr(GetLastError());
1798
1799 return ret;
1800 }
1801
1802 static int check_bom(HANDLE h, int oflags, BOOL seek)
1803 {
1804 char bom[sizeof(utf8_bom)];
1805 DWORD r;
1806
1807 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1808
1809 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1810 return oflags;
1811
1812 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1813 oflags |= _O_U8TEXT;
1814 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1815 if (seek && r>2)
1816 SetFilePointer(h, 2, NULL, FILE_BEGIN);
1817 oflags |= _O_U16TEXT;
1818 }else if (seek) {
1819 SetFilePointer(h, 0, NULL, FILE_BEGIN);
1820 }
1821
1822 return oflags;
1823 }
1824
1825 /*********************************************************************
1826 * _wsopen_s (MSVCRT.@)
1827 */
1828 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
1829 {
1830 DWORD access = 0, creation = 0, attrib;
1831 SECURITY_ATTRIBUTES sa;
1832 DWORD sharing, type;
1833 int wxflag;
1834 HANDLE hand;
1835
1836 TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1837 fd, debugstr_w(path), oflags, shflags, pmode);
1838
1839 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
1840
1841 *fd = -1;
1842 wxflag = split_oflags(oflags);
1843 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1844 {
1845 case _O_RDONLY: access |= GENERIC_READ; break;
1846 case _O_WRONLY: access |= GENERIC_WRITE; break;
1847 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
1848 }
1849
1850 if (oflags & _O_CREAT)
1851 {
1852 if(pmode & ~(_S_IREAD | _S_IWRITE))
1853 FIXME(": pmode 0x%04x ignored\n", pmode);
1854 else
1855 WARN(": pmode 0x%04x ignored\n", pmode);
1856
1857 if (oflags & _O_EXCL)
1858 creation = CREATE_NEW;
1859 else if (oflags & _O_TRUNC)
1860 creation = CREATE_ALWAYS;
1861 else
1862 creation = OPEN_ALWAYS;
1863 }
1864 else /* no _O_CREAT */
1865 {
1866 if (oflags & _O_TRUNC)
1867 creation = TRUNCATE_EXISTING;
1868 else
1869 creation = OPEN_EXISTING;
1870 }
1871
1872 switch( shflags )
1873 {
1874 case _SH_DENYRW:
1875 sharing = 0L;
1876 break;
1877 case _SH_DENYWR:
1878 sharing = FILE_SHARE_READ;
1879 break;
1880 case _SH_DENYRD:
1881 sharing = FILE_SHARE_WRITE;
1882 break;
1883 case _SH_DENYNO:
1884 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1885 break;
1886 default:
1887 ERR( "Unhandled shflags 0x%x\n", shflags );
1888 return EINVAL;
1889 }
1890 attrib = FILE_ATTRIBUTE_NORMAL;
1891
1892 if (oflags & _O_TEMPORARY)
1893 {
1894 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1895 access |= DELETE;
1896 sharing |= FILE_SHARE_DELETE;
1897 }
1898
1899 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
1900 sa.lpSecurityDescriptor = NULL;
1901 sa.bInheritHandle = !(oflags & _O_NOINHERIT);
1902
1903 if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1904 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1905 && !(access&GENERIC_READ))
1906 {
1907 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1908 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1909 if (hand != INVALID_HANDLE_VALUE)
1910 {
1911 oflags = check_bom(hand, oflags, FALSE);
1912 CloseHandle(hand);
1913 }
1914 else
1915 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1916 }
1917
1918 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1919 if (hand == INVALID_HANDLE_VALUE) {
1920 WARN(":failed-last error (%d)\n",GetLastError());
1921 _dosmaperr(GetLastError());
1922 return *_errno();
1923 }
1924
1925 if (oflags & (_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1926 {
1927 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1928 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1929 || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1930 {
1931 if (oflags & _O_U8TEXT)
1932 {
1933 DWORD written = 0, tmp;
1934
1935 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1936 sizeof(utf8_bom)-written, &tmp, NULL))
1937 written += tmp;
1938 if (written != sizeof(utf8_bom)) {
1939 WARN("error writing BOM\n");
1940 CloseHandle(hand);
1941 _dosmaperr(GetLastError());
1942 return *_errno();
1943 }
1944 }
1945 else
1946 {
1947 DWORD written = 0, tmp;
1948
1949 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1950 sizeof(utf16_bom)-written, &tmp, NULL))
1951 written += tmp;
1952 if (written != sizeof(utf16_bom))
1953 {
1954 WARN("error writing BOM\n");
1955 CloseHandle(hand);
1956 _dosmaperr(GetLastError());
1957 return *_errno();
1958 }
1959 }
1960 }
1961 else if (access & GENERIC_READ)
1962 oflags = check_bom(hand, oflags, TRUE);
1963 }
1964
1965 type = GetFileType(hand);
1966 if (type == FILE_TYPE_CHAR)
1967 wxflag |= WX_TTY;
1968 else if (type == FILE_TYPE_PIPE)
1969 wxflag |= WX_PIPE;
1970
1971 *fd = msvcrt_alloc_fd(hand, wxflag);
1972 if (*fd == -1)
1973 return *_errno();
1974
1975 if (oflags & _O_WTEXT)
1976 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1977 else if (oflags & _O_U16TEXT)
1978 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16;
1979 else if (oflags & _O_U8TEXT)
1980 get_ioinfo_nolock(*fd)->exflag |= EF_UTF8;
1981
1982 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1983 return 0;
1984 }
1985
1986 /*********************************************************************
1987 * _wsopen (MSVCRT.@)
1988 */
1989 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
1990 {
1991 int pmode;
1992 int fd;
1993
1994 if (oflags & _O_CREAT)
1995 {
1996 __ms_va_list ap;
1997
1998 __ms_va_start(ap, shflags);
1999 pmode = va_arg(ap, int);
2000 __ms_va_end(ap);
2001 }
2002 else
2003 pmode = 0;
2004
2005 _wsopen_s(&fd, path, oflags, shflags, pmode);
2006 return fd;
2007 }
2008
2009 /*********************************************************************
2010 * _sopen_s (MSVCRT.@)
2011 */
2012 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
2013 {
2014 wchar_t *pathW;
2015 int ret;
2016
2017 if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
2018 return EINVAL;
2019
2020 ret = _wsopen_s(fd, pathW, oflags, shflags, pmode);
2021 free(pathW);
2022 return ret;
2023 }
2024
2025 /*********************************************************************
2026 * _sopen (MSVCRT.@)
2027 */
2028 int CDECL _sopen( const char *path, int oflags, int shflags, ... )
2029 {
2030 int pmode;
2031 int fd;
2032
2033 if (oflags & _O_CREAT)
2034 {
2035 va_list ap;
2036
2037 va_start(ap, shflags);
2038 pmode = va_arg(ap, int);
2039 va_end(ap);
2040 }
2041 else
2042 pmode = 0;
2043
2044 _sopen_s(&fd, path, oflags, shflags, pmode);
2045 return fd;
2046 }
2047
2048 /*********************************************************************
2049 * _open (MSVCRT.@)
2050 */
2051 int CDECL _open( const char *path, int flags, ... )
2052 {
2053 va_list ap;
2054
2055 if (flags & _O_CREAT)
2056 {
2057 int pmode;
2058 va_start(ap, flags);
2059 pmode = va_arg(ap, int);
2060 va_end(ap);
2061 return _sopen( path, flags, _SH_DENYNO, pmode );
2062 }
2063 else
2064 return _sopen( path, flags, _SH_DENYNO);
2065 }
2066
2067 /*********************************************************************
2068 * _wopen (MSVCRT.@)
2069 */
2070 int CDECL _wopen(const wchar_t *path,int flags,...)
2071 {
2072 va_list ap;
2073
2074 if (flags & _O_CREAT)
2075 {
2076 int pmode;
2077 va_start(ap, flags);
2078 pmode = va_arg(ap, int);
2079 va_end(ap);
2080 return _wsopen( path, flags, _SH_DENYNO, pmode );
2081 }
2082 else
2083 return _wsopen( path, flags, _SH_DENYNO);
2084 }
2085
2086 /*********************************************************************
2087 * _creat (MSVCRT.@)
2088 */
2089 int CDECL _creat(const char *path, int flags)
2090 {
2091 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2092 return _open(path, usedFlags);
2093 }
2094
2095 /*********************************************************************
2096 * _wcreat (MSVCRT.@)
2097 */
2098 int CDECL _wcreat(const wchar_t *path, int flags)
2099 {
2100 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2101 return _wopen(path, usedFlags);
2102 }
2103
2104 /*********************************************************************
2105 * _open_osfhandle (MSVCRT.@)
2106 */
2107 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2108 {
2109 DWORD flags;
2110 int fd;
2111
2112 /* _O_RDONLY (0) always matches, so set the read flag
2113 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2114 * file, so set the write flag. It also only sets _O_TEXT if it wants
2115 * text - it never sets _O_BINARY.
2116 */
2117 /* don't let split_oflags() decide the mode if no mode is passed */
2118 if (!(oflags & (_O_BINARY | _O_TEXT)))
2119 oflags |= _O_BINARY;
2120
2121 flags = GetFileType((HANDLE)handle);
2122 if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2123 {
2124 _dosmaperr(GetLastError());
2125 return -1;
2126 }
2127
2128 if (flags == FILE_TYPE_CHAR)
2129 flags = WX_TTY;
2130 else if (flags == FILE_TYPE_PIPE)
2131 flags = WX_PIPE;
2132 else
2133 flags = 0;
2134 flags |= split_oflags(oflags);
2135
2136 fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2137 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags);
2138 return fd;
2139 }
2140
2141 /*********************************************************************
2142 * _rmtmp (MSVCRT.@)
2143 */
2144 int CDECL _rmtmp(void)
2145 {
2146 int num_removed = 0, i;
2147 FILE *file;
2148
2149 LOCK_FILES();
2150 for (i = 3; i < MSVCRT_stream_idx; i++) {
2151 file = msvcrt_get_file(i);
2152
2153 if (file->_tmpfname)
2154 {
2155 fclose(file);
2156 num_removed++;
2157 }
2158 }
2159 UNLOCK_FILES();
2160
2161 if (num_removed)
2162 TRACE(":removed (%d) temp files\n",num_removed);
2163 return num_removed;
2164 }
2165
2166 static inline int get_utf8_char_len(char ch)
2167 {
2168 if((ch&0xf8) == 0xf0)
2169 return 4;
2170 else if((ch&0xf0) == 0xe0)
2171 return 3;
2172 else if((ch&0xe0) == 0xc0)
2173 return 2;
2174 return 1;
2175 }
2176
2177 /*********************************************************************
2178 * (internal) read_utf8
2179 */
2180 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2181 {
2182 HANDLE hand = fdinfo->handle;
2183 char min_buf[4], *readbuf, lookahead;
2184 DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2185
2186 /* make the buffer big enough to hold at least one character */
2187 /* read bytes have to fit to output and lookahead buffers */
2188 count /= 2;
2189 readbuf_size = count < 4 ? 4 : count;
2190 if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2191 readbuf_size = 4;
2192 readbuf = min_buf;
2193 }
2194
2195 if(fdinfo->lookahead[0] != '\n') {
2196 readbuf[pos++] = fdinfo->lookahead[0];
2197 fdinfo->lookahead[0] = '\n';
2198
2199 if(fdinfo->lookahead[1] != '\n') {
2200 readbuf[pos++] = fdinfo->lookahead[1];
2201 fdinfo->lookahead[1] = '\n';
2202
2203 if(fdinfo->lookahead[2] != '\n') {
2204 readbuf[pos++] = fdinfo->lookahead[2];
2205 fdinfo->lookahead[2] = '\n';
2206 }
2207 }
2208 }
2209
2210 /* NOTE: this case is broken in native dll, reading
2211 * sometimes fails when small buffer is passed
2212 */
2213 if(count < 4) {
2214 if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2215 if (GetLastError() == ERROR_BROKEN_PIPE) {
2216 fdinfo->wxflag |= WX_ATEOF;
2217 return 0;
2218 }else {
2219 _dosmaperr(GetLastError());
2220 return -1;
2221 }
2222 }else if(!num_read) {
2223 fdinfo->wxflag |= WX_ATEOF;
2224 return 0;
2225 }else {
2226 pos++;
2227 }
2228
2229 char_len = get_utf8_char_len(readbuf[0]);
2230 if(char_len>pos) {
2231 if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2232 pos += num_read;
2233 }
2234
2235 if(readbuf[0] == '\n')
2236 fdinfo->wxflag |= WX_READNL;
2237 else
2238 fdinfo->wxflag &= ~WX_READNL;
2239
2240 if(readbuf[0] == 0x1a) {
2241 fdinfo->wxflag |= WX_ATEOF;
2242 return 0;
2243 }
2244
2245 if(readbuf[0] == '\r') {
2246 if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2247 buf[0] = '\r';
2248 else if(lookahead == '\n')
2249 buf[0] = '\n';
2250 else {
2251 buf[0] = '\r';
2252 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2253 fdinfo->lookahead[0] = lookahead;
2254 else
2255 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2256 }
2257 return 2;
2258 }
2259
2260 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2261 _dosmaperr(GetLastError());
2262 return -1;
2263 }
2264
2265 return num_read*2;
2266 }
2267
2268 if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2269 if(pos) {
2270 num_read = 0;
2271 }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2272 fdinfo->wxflag |= WX_ATEOF;
2273 if (readbuf != min_buf) free(readbuf);
2274 return 0;
2275 }else {
2276 _dosmaperr(GetLastError());
2277 if (readbuf != min_buf) free(readbuf);
2278 return -1;
2279 }
2280 }else if(!pos && !num_read) {
2281 fdinfo->wxflag |= WX_ATEOF;
2282 if (readbuf != min_buf) free(readbuf);
2283 return 0;
2284 }
2285
2286 pos += num_read;
2287 if(readbuf[0] == '\n')
2288 fdinfo->wxflag |= WX_READNL;
2289 else
2290 fdinfo->wxflag &= ~WX_READNL;
2291
2292 /* Find first byte of last character (may be incomplete) */
2293 for(i=pos-1; i>0 && i>pos-4; i--)
2294 if((readbuf[i]&0xc0) != 0x80)
2295 break;
2296 char_len = get_utf8_char_len(readbuf[i]);
2297 if(char_len+i <= pos)
2298 i += char_len;
2299
2300 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2301 if(i < pos)
2302 fdinfo->lookahead[0] = readbuf[i];
2303 if(i+1 < pos)
2304 fdinfo->lookahead[1] = readbuf[i+1];
2305 if(i+2 < pos)
2306 fdinfo->lookahead[2] = readbuf[i+2];
2307 }else if(i < pos) {
2308 SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2309 }
2310 pos = i;
2311
2312 for(i=0, j=0; i<pos; i++) {
2313 if(readbuf[i] == 0x1a) {
2314 fdinfo->wxflag |= WX_ATEOF;
2315 break;
2316 }
2317
2318 /* strip '\r' if followed by '\n' */
2319 if(readbuf[i] == '\r' && i+1==pos) {
2320 if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2321 readbuf[j++] = '\r';
2322 }else if(lookahead == '\n' && j==0) {
2323 readbuf[j++] = '\n';
2324 }else {
2325 if(lookahead != '\n')
2326 readbuf[j++] = '\r';
2327
2328 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2329 fdinfo->lookahead[0] = lookahead;
2330 else
2331 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2332 }
2333 }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2334 readbuf[j++] = readbuf[i];
2335 }
2336 }
2337 pos = j;
2338
2339 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2340 _dosmaperr(GetLastError());
2341 if (readbuf != min_buf) free(readbuf);
2342 return -1;
2343 }
2344
2345 if (readbuf != min_buf) free(readbuf);
2346 return num_read*2;
2347 }
2348
2349 /*********************************************************************
2350 * (internal) read_i
2351 *
2352 * When reading \r as last character in text mode, read() positions
2353 * the file pointer on the \r character while getc() goes on to
2354 * the following \n
2355 */
2356 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2357 {
2358 DWORD num_read, utf16;
2359 char *bufstart = buf;
2360
2361 if (count == 0)
2362 return 0;
2363
2364 if (fdinfo->wxflag & WX_ATEOF) {
2365 TRACE("already at EOF, returning 0\n");
2366 return 0;
2367 }
2368 /* Don't trace small reads, it gets *very* annoying */
2369 if (count > 4)
2370 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2371 if (fdinfo->handle == INVALID_HANDLE_VALUE)
2372 {
2373 *_errno() = EBADF;
2374 return -1;
2375 }
2376
2377 utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2378 if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2379 {
2380 *_errno() = EINVAL;
2381 return -1;
2382 }
2383
2384 if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2385 return read_utf8(fdinfo, buf, count);
2386
2387 if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2388 {
2389 if (fdinfo->lookahead[0] != '\n')
2390 {
2391 bufstart[0] = fdinfo->lookahead[0];
2392 fdinfo->lookahead[0] = '\n';
2393
2394 if (utf16)
2395 {
2396 bufstart[1] = fdinfo->lookahead[1];
2397 fdinfo->lookahead[1] = '\n';
2398 }
2399
2400 if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2401 num_read += 1+utf16;
2402 else
2403 num_read = 1+utf16;
2404 }
2405
2406 if(utf16 && (num_read&1))
2407 {
2408 /* msvcr90 uses uninitialized value from the buffer in this case */
2409 /* msvcrt ignores additional data */
2410 ERR("got odd number of bytes in UTF16 mode\n");
2411 num_read--;
2412 }
2413
2414 if (count != 0 && num_read == 0)
2415 {
2416 fdinfo->wxflag |= WX_ATEOF;
2417 TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2418 }
2419 else if (fdinfo->wxflag & WX_TEXT)
2420 {
2421 DWORD i, j;
2422
2423 if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2424 fdinfo->wxflag |= WX_READNL;
2425 else
2426 fdinfo->wxflag &= ~WX_READNL;
2427
2428 for (i=0, j=0; i<num_read; i+=1+utf16)
2429 {
2430 /* in text mode, a ctrl-z signals EOF */
2431 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2432 {
2433 fdinfo->wxflag |= WX_ATEOF;
2434 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2435 break;
2436 }
2437
2438 /* in text mode, strip \r if followed by \n */
2439 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2440 {
2441 char lookahead[2];
2442 DWORD len;
2443
2444 lookahead[1] = '\n';
2445 if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
2446 {
2447 if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2448 {
2449 bufstart[j++] = '\n';
2450 if(utf16) bufstart[j++] = 0;
2451 }
2452 else
2453 {
2454 if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2455 {
2456 bufstart[j++] = '\r';
2457 if(utf16) bufstart[j++] = 0;
2458 }
2459
2460 if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
2461 {
2462 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
2463 {
2464 bufstart[j++] = '\n';
2465 if (utf16) bufstart[j++] = 0;
2466 }
2467 else
2468 {
2469 fdinfo->lookahead[0] = lookahead[0];
2470 fdinfo->lookahead[1] = lookahead[1];
2471 }
2472 }
2473 else
2474 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2475 }
2476 }
2477 else
2478 {
2479 bufstart[j++] = '\r';
2480 if(utf16) bufstart[j++] = 0;
2481 }
2482 }
2483 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2484 || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2485 {
2486 bufstart[j++] = bufstart[i];
2487 if(utf16) bufstart[j++] = bufstart[i+1];
2488 }
2489 }
2490 num_read = j;
2491 }
2492 }
2493 else
2494 {
2495 if (GetLastError() == ERROR_BROKEN_PIPE)
2496 {
2497 TRACE(":end-of-pipe\n");
2498 fdinfo->wxflag |= WX_ATEOF;
2499 return 0;
2500 }
2501 else
2502 {
2503 TRACE(":failed-last error (%d)\n",GetLastError());
2504 return -1;
2505 }
2506 }
2507
2508 if (count > 4)
2509 TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2510 return num_read;
2511 }
2512
2513 /*********************************************************************
2514 * _read (MSVCRT.@)
2515 */
2516 int CDECL _read(int fd, void *buf, unsigned int count)
2517 {
2518 ioinfo *info = get_ioinfo(fd);
2519 int num_read = read_i(fd, info, buf, count);
2520 release_ioinfo(info);
2521 return num_read;
2522 }
2523
2524 /*********************************************************************
2525 * _setmode (MSVCRT.@)
2526 */
2527 int CDECL _setmode(int fd,int mode)
2528 {
2529 ioinfo *info = get_ioinfo(fd);
2530 int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
2531 if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16)))
2532 ret = _O_WTEXT;
2533
2534 if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
2535 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
2536 *_errno() = EINVAL;
2537 release_ioinfo(info);
2538 return -1;
2539 }
2540
2541 if(mode == _O_BINARY) {
2542 info->wxflag &= ~WX_TEXT;
2543 info->exflag &= ~(EF_UTF8|EF_UTF16);
2544 release_ioinfo(info);
2545 return ret;
2546 }
2547
2548 info->wxflag |= WX_TEXT;
2549 if(mode == _O_TEXT)
2550 info->exflag &= ~(EF_UTF8|EF_UTF16);
2551 else if(mode == _O_U8TEXT)
2552 info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8;
2553 else
2554 info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16;
2555
2556 release_ioinfo(info);
2557 return ret;
2558
2559 }
2560
2561 /*********************************************************************
2562 * _tell (MSVCRT.@)
2563 */
2564 long CDECL _tell(int fd)
2565 {
2566 return _lseek(fd, 0, SEEK_CUR);
2567 }
2568
2569 /*********************************************************************
2570 * _telli64 (MSVCRT.@)
2571 */
2572 __int64 CDECL _telli64(int fd)
2573 {
2574 return _lseeki64(fd, 0, SEEK_CUR);
2575 }
2576
2577 /*********************************************************************
2578 * _tempnam (MSVCRT.@)
2579 */
2580 char * CDECL _tempnam(const char *dir, const char *prefix)
2581 {
2582 char tmpbuf[MAX_PATH];
2583 const char *tmp_dir = getenv("TMP");
2584
2585 if (tmp_dir) dir = tmp_dir;
2586
2587 TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2588 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2589 {
2590 TRACE("got name (%s)\n",tmpbuf);
2591 DeleteFileA(tmpbuf);
2592 return _strdup(tmpbuf);
2593 }
2594 TRACE("failed (%d)\n",GetLastError());
2595 return NULL;
2596 }
2597
2598 /*********************************************************************
2599 * _wtempnam (MSVCRT.@)
2600 */
2601 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
2602 {
2603 wchar_t tmpbuf[MAX_PATH];
2604
2605 TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2606 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2607 {
2608 TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2609 DeleteFileW(tmpbuf);
2610 return _wcsdup(tmpbuf);
2611 }
2612 TRACE("failed (%d)\n",GetLastError());
2613 return NULL;
2614 }
2615
2616 /*********************************************************************
2617 * _umask (MSVCRT.@)
2618 */
2619 int CDECL _umask(int umask)
2620 {
2621 int old_umask = MSVCRT_umask;
2622 TRACE("(%d)\n",umask);
2623 MSVCRT_umask = umask;
2624 return old_umask;
2625 }
2626
2627 /*********************************************************************
2628 * _write (MSVCRT.@)
2629 */
2630 int CDECL _write(int fd, const void* buf, unsigned int count)
2631 {
2632 DWORD num_written;
2633 ioinfo *info = get_ioinfo(fd);
2634 HANDLE hand = info->handle;
2635
2636 /* Don't trace small writes, it gets *very* annoying */
2637 #if 0
2638 if (count > 32)
2639 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2640 #endif
2641 if (hand == INVALID_HANDLE_VALUE)
2642 {
2643 *_errno() = EBADF;
2644 release_ioinfo(info);
2645 return -1;
2646 }
2647
2648 if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2649 {
2650 *_errno() = EINVAL;
2651 release_ioinfo(info);
2652 return -1;
2653 }
2654
2655 /* If appending, go to EOF */
2656 if (info->wxflag & WX_APPEND)
2657 _lseek(fd, 0, FILE_END);
2658
2659 if (!(info->wxflag & WX_TEXT))
2660 {
2661 if (WriteFile(hand, buf, count, &num_written, NULL)
2662 && (num_written == count))
2663 {
2664 release_ioinfo(info);
2665 return num_written;
2666 }
2667 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2668 hand, GetLastError());
2669 *_errno() = ENOSPC;
2670 }
2671 else
2672 {
2673 unsigned int i, j, nr_lf, size;
2674 char *p = NULL;
2675 const char *q;
2676 const char *s = buf, *buf_start = buf;
2677
2678 if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2679 {
2680 /* find number of \n */
2681 for (nr_lf=0, i=0; i<count; i++)
2682 if (s[i] == '\n')
2683 nr_lf++;
2684 if (nr_lf)
2685 {
2686 size = count+nr_lf;
2687 if ((q = p = malloc(size)))
2688 {
2689 for (s = buf, i = 0, j = 0; i < count; i++)
2690 {
2691 if (s[i] == '\n')
2692 p[j++] = '\r';
2693 p[j++] = s[i];
2694 }
2695 }
2696 else
2697 {
2698 FIXME("Malloc failed\n");
2699 nr_lf = 0;
2700 size = count;
2701 q = buf;
2702 }
2703 }
2704 else
2705 {
2706 size = count;
2707 q = buf;
2708 }
2709 }
2710 else if (info->exflag & EF_UTF16)
2711 {
2712 for (nr_lf=0, i=0; i<count; i+=2)
2713 if (s[i]=='\n' && s[i+1]==0)
2714 nr_lf += 2;
2715 if (nr_lf)
2716 {
2717 size = count+nr_lf;
2718 if ((q = p = malloc(size)))
2719 {
2720 for (s=buf, i=0, j=0; i<count; i++)
2721 {
2722 if (s[i]=='\n' && s[i+1]==0)
2723 {
2724 p[j++] = '\r';
2725 p[j++] = 0;
2726 }
2727 p[j++] = s[i++];
2728 p[j++] = s[i];
2729 }
2730 }
2731 else
2732 {
2733 FIXME("Malloc failed\n");
2734 nr_lf = 0;
2735 size = count;
2736 q = buf;
2737 }
2738 }
2739 else
2740 {
2741 size = count;
2742 q = buf;
2743 }
2744 }
2745 else
2746 {
2747 DWORD conv_len;
2748
2749 for(nr_lf=0, i=0; i<count; i+=2)
2750 if (s[i]=='\n' && s[i+1]==0)
2751 nr_lf++;
2752
2753 conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2754 if(!conv_len) {
2755 _dosmaperr(GetLastError());
2756 free(p);
2757 release_ioinfo(info);
2758 return -1;
2759 }
2760
2761 size = conv_len+nr_lf;
2762 if((p = malloc(count+nr_lf*2+size)))
2763 {
2764 for (s=buf, i=0, j=0; i<count; i++)
2765 {
2766 if (s[i]=='\n' && s[i+1]==0)
2767 {
2768 p[j++] = '\r';
2769 p[j++] = 0;
2770 }
2771 p[j++] = s[i++];
2772 p[j++] = s[i];
2773 }
2774 q = p+count+nr_lf*2;
2775 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
2776 p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
2777 }
2778 else
2779 {
2780 FIXME("Malloc failed\n");
2781 nr_lf = 0;
2782 size = count;
2783 q = buf;
2784 }
2785 }
2786
2787 if (!WriteFile(hand, q, size, &num_written, NULL))
2788 num_written = -1;
2789 release_ioinfo(info);
2790 if(p)
2791 free(p);
2792 if (num_written != size)
2793 {
2794 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2795 fd, hand, GetLastError(), num_written);
2796 *_errno() = ENOSPC;
2797 return s - buf_start;
2798 }
2799 return count;
2800 }
2801
2802 release_ioinfo(info);
2803 return -1;
2804 }
2805
2806 /*********************************************************************
2807 * _putw (MSVCRT.@)
2808 */
2809 int CDECL _putw(int val, FILE* file)
2810 {
2811 int len;
2812
2813 _lock_file(file);
2814 len = _write(file->_file, &val, sizeof(val));
2815 if (len == sizeof(val)) {
2816 _unlock_file(file);
2817 return val;
2818 }
2819
2820 file->_flag |= _IOERR;
2821 _unlock_file(file);
2822 return EOF;
2823 }
2824
2825 /*********************************************************************
2826 * fclose (MSVCRT.@)
2827 */
2828 int CDECL fclose(FILE* file)
2829 {
2830 int r, flag;
2831
2832 _lock_file(file);
2833 flag = file->_flag;
2834 free(file->_tmpfname);
2835 file->_tmpfname = NULL;
2836 /* flush stdio buffers */
2837 if(file->_flag & _IOWRT)
2838 fflush(file);
2839 if(file->_flag & _IOMYBUF)
2840 free(file->_base);
2841
2842 r=_close(file->_file);
2843
2844 file->_flag = 0;
2845 _unlock_file(file);
2846 if(file<_iob || file>=_iob+_IOB_ENTRIES)
2847 DeleteCriticalSection(&((file_crit*)file)->crit);
2848
2849 if(file == msvcrt_get_file(MSVCRT_stream_idx-1)) {
2850 while(MSVCRT_stream_idx>3 && !file->_flag) {
2851 MSVCRT_stream_idx--;
2852 file = msvcrt_get_file(MSVCRT_stream_idx-1);
2853 }
2854 }
2855
2856 return ((r == -1) || (flag & _IOERR) ? EOF : 0);
2857 }
2858
2859 /*********************************************************************
2860 * feof (MSVCRT.@)
2861 */
2862 int CDECL feof(FILE* file)
2863 {
2864 return file->_flag & _IOEOF;
2865 }
2866
2867 /*********************************************************************
2868 * ferror (MSVCRT.@)
2869 */
2870 int CDECL ferror(FILE* file)
2871 {
2872 return file->_flag & _IOERR;
2873 }
2874
2875 /*********************************************************************
2876 * _filbuf (MSVCRT.@)
2877 */
2878 int CDECL _filbuf(FILE* file)
2879 {
2880 unsigned char c;
2881 _lock_file(file);
2882
2883 if(file->_flag & _IOSTRG) {
2884 _unlock_file(file);
2885 return EOF;
2886 }
2887
2888 /* Allocate buffer if needed */
2889 if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
2890 msvcrt_alloc_buffer(file);
2891
2892 if(!(file->_flag & _IOREAD)) {
2893 if(file->_flag & _IORW)
2894 file->_flag |= _IOREAD;
2895 else {
2896 _unlock_file(file);
2897 return EOF;
2898 }
2899 }
2900
2901 if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
2902 int r;
2903 if ((r = _read(file->_file,&c,1)) != 1) {
2904 file->_flag |= (r == 0) ? _IOEOF : _IOERR;
2905 _unlock_file(file);
2906 return EOF;
2907 }
2908
2909 _unlock_file(file);
2910 return c;
2911 } else {
2912 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
2913 if(file->_cnt<=0) {
2914 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2915 file->_cnt = 0;
2916 _unlock_file(file);
2917 return EOF;
2918 }
2919
2920 file->_cnt--;
2921 file->_ptr = file->_base+1;
2922 c = *(unsigned char *)file->_base;
2923 _unlock_file(file);
2924 return c;
2925 }
2926 }
2927
2928 /*********************************************************************
2929 * fgetc (MSVCRT.@)
2930 */
2931 int CDECL fgetc(FILE* file)
2932 {
2933 unsigned char *i;
2934 unsigned int j;
2935
2936 _lock_file(file);
2937 if (file->_cnt>0) {
2938 file->_cnt--;
2939 i = (unsigned char *)file->_ptr++;
2940 j = *i;
2941 } else
2942 j = _filbuf(file);
2943
2944 _unlock_file(file);
2945 return j;
2946 }
2947
2948 /*********************************************************************
2949 * _fgetchar (MSVCRT.@)
2950 */
2951 int CDECL _fgetchar(void)
2952 {
2953 return fgetc(stdin);
2954 }
2955
2956 /*********************************************************************
2957 * fgets (MSVCRT.@)
2958 */
2959 char * CDECL fgets(char *s, int size, FILE* file)
2960 {
2961 int cc = EOF;
2962 char * buf_start = s;
2963
2964 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2965 file,file->_file,s,size);
2966
2967 _lock_file(file);
2968
2969 while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n')
2970 {
2971 *s++ = (char)cc;
2972 size --;
2973 }
2974 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
2975 {
2976 TRACE(":nothing read\n");
2977 _unlock_file(file);
2978 return NULL;
2979 }
2980 if ((cc != EOF) && (size > 1))
2981 *s++ = cc;
2982 *s = '\0';
2983 TRACE(":got %s\n", debugstr_a(buf_start));
2984 _unlock_file(file);
2985 return buf_start;
2986 }
2987
2988 /*********************************************************************
2989 * fgetwc (MSVCRT.@)
2990 */
2991 wint_t CDECL fgetwc(FILE* file)
2992 {
2993 wint_t ret;
2994 int ch;
2995
2996 _lock_file(file);
2997
2998 if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
2999 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3000 char *p;
3001
3002 for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
3003 ch = fgetc(file);
3004 if(ch == EOF) {
3005 ret = WEOF;
3006 break;
3007 }
3008 *p = (char)ch;
3009 }
3010 }else {
3011 char mbs[MB_LEN_MAX];
3012 int len = 0;
3013
3014 ch = fgetc(file);
3015 if(ch != EOF) {
3016 mbs[0] = (char)ch;
3017 if(isleadbyte((unsigned char)mbs[0])) {
3018 ch = fgetc(file);
3019 if(ch != EOF) {
3020 mbs[1] = (char)ch;
3021 len = 2;
3022 }
3023 }else {
3024 len = 1;
3025 }
3026 }
3027
3028 if(!len || mbtowc(&ret, mbs, len)==-1)
3029 ret = WEOF;
3030 }
3031
3032 _unlock_file(file);
3033 return ret;
3034 }
3035
3036 /*********************************************************************
3037 * _getw (MSVCRT.@)
3038 */
3039 int CDECL _getw(FILE* file)
3040 {
3041 char *ch;
3042 int i, k;
3043 unsigned int j;
3044 ch = (char *)&i;
3045
3046 _lock_file(file);
3047 for (j=0; j<sizeof(int); j++) {
3048 k = fgetc(file);
3049 if (k == EOF) {
3050 file->_flag |= _IOEOF;
3051 _unlock_file(file);
3052 return EOF;
3053 }
3054 ch[j] = k;
3055 }
3056
3057 _unlock_file(file);
3058 return i;
3059 }
3060
3061 /*********************************************************************
3062 * getwc (MSVCRT.@)
3063 */
3064 wint_t CDECL getwc(FILE* file)
3065 {
3066 return fgetwc(file);
3067 }
3068
3069 /*********************************************************************
3070 * _fgetwchar (MSVCRT.@)
3071 */
3072 wint_t CDECL _fgetwchar(void)
3073 {
3074 return fgetwc(stdin);
3075 }
3076
3077 /*********************************************************************
3078 * getwchar (MSVCRT.@)
3079 */
3080 wint_t CDECL getwchar(void)
3081 {
3082 return _fgetwchar();
3083 }
3084
3085 /*********************************************************************
3086 * fgetws (MSVCRT.@)
3087 */
3088 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
3089 {
3090 int cc = WEOF;
3091 wchar_t * buf_start = s;
3092
3093 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3094 file,file->_file,s,size);
3095
3096 _lock_file(file);
3097
3098 while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n')
3099 {
3100 *s++ = (char)cc;
3101 size --;
3102 }
3103 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3104 {
3105 TRACE(":nothing read\n");
3106 _unlock_file(file);
3107 return NULL;
3108 }
3109 if ((cc != WEOF) && (size > 1))
3110 *s++ = cc;
3111 *s = 0;
3112 TRACE(":got %s\n", debugstr_w(buf_start));
3113 _unlock_file(file);
3114 return buf_start;
3115 }
3116
3117 /*********************************************************************
3118 * fwrite (MSVCRT.@)
3119 */
3120 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
3121 {
3122 size_t wrcnt=size * nmemb;
3123 int written = 0;
3124 if (size == 0)
3125 return 0;
3126
3127 _lock_file(file);
3128
3129 while(wrcnt) {
3130 #ifndef __REACTOS__
3131 if(file->_cnt < 0) {
3132 WARN("negative file->_cnt value in %p\n", file);
3133 file->_flag |= MSVCRT__IOERR;
3134 break;
3135 } else
3136 #endif
3137 if(file->_cnt) {
3138 int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3139 memcpy(file->_ptr, ptr, pcnt);
3140 file->_cnt -= pcnt;
3141 file->_ptr += pcnt;
3142 written += pcnt;
3143 wrcnt -= pcnt;
3144 ptr = (const char*)ptr + pcnt;
3145 } else if((file->_flag & _IONBF)
3146 || ((file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= file->_bufsiz)
3147 || (!(file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
3148 size_t pcnt;
3149 int bufsiz;
3150
3151 if(file->_flag & _IONBF)
3152 bufsiz = 1;
3153 else if(!(file->_flag & (_IOMYBUF | _USERBUF)))
3154 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
3155 else
3156 bufsiz = file->_bufsiz;
3157
3158 pcnt = (wrcnt / bufsiz) * bufsiz;
3159
3160 if(msvcrt_flush_buffer(file) == EOF)
3161 break;
3162
3163 if(_write(file->_file, ptr, pcnt) <= 0) {
3164 file->_flag |= _IOERR;
3165 break;
3166 }
3167 written += pcnt;
3168 wrcnt -= pcnt;
3169 ptr = (const char*)ptr + pcnt;
3170 } else {
3171 if(_flsbuf(*(const char*)ptr, file) == EOF)
3172 break;
3173 written++;
3174 wrcnt--;
3175 ptr = (const char*)ptr + 1;
3176 }
3177 }
3178
3179 _unlock_file(file);
3180 return written / size;
3181 }
3182
3183 /*********************************************************************
3184 * fputwc (MSVCRT.@)
3185 * FORKED for ReactOS, don't sync with Wine!
3186 * References:
3187 * - http://jira.reactos.org/browse/CORE-6495
3188 * - http://bugs.winehq.org/show_bug.cgi?id=8598
3189 */
3190 wint_t CDECL fputwc(wchar_t c, FILE* stream)
3191 {
3192 /* If this is a real file stream (and not some temporary one for
3193 sprintf-like functions), check whether it is opened in text mode.
3194 In this case, we have to perform an implicit conversion to ANSI. */
3195 if (!(stream->_flag & _IOSTRG) && get_ioinfo_nolock(stream->_file)->wxflag & WX_TEXT)
3196 {
3197 /* Convert to multibyte in text mode */
3198 char mbc[MB_LEN_MAX];
3199 int mb_return;
3200
3201 mb_return = wctomb(mbc, c);
3202
3203 if(mb_return == -1)
3204 return WEOF;
3205
3206 /* Output all characters */
3207 if (fwrite(mbc, mb_return, 1, stream) != 1)
3208 return WEOF;
3209 }
3210 else
3211 {
3212 if (fwrite(&c, sizeof(c), 1, stream) != 1)
3213 return WEOF;
3214 }
3215
3216 return c;
3217 }
3218
3219 /*********************************************************************
3220 * _fputwchar (MSVCRT.@)
3221 */
3222 wint_t CDECL _fputwchar(wint_t wc)
3223 {
3224 return fputwc(wc, stdout);
3225 }
3226
3227 /*********************************************************************
3228 * _wfsopen (MSVCRT.@)
3229 */
3230 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
3231 {
3232 FILE* file;
3233 int open_flags, stream_flags, fd;
3234
3235 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3236
3237 /* map mode string to open() flags. "man fopen" for possibilities. */
3238 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3239 return NULL;
3240
3241 LOCK_FILES();
3242 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
3243 if (fd < 0)
3244 file = NULL;
3245 else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3246 != -1)
3247 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3248 else if (file)
3249 {
3250 file->_flag = 0;
3251 file = NULL;
3252 }
3253
3254 TRACE(":got (%p)\n",file);
3255 if (fd >= 0 && !file)
3256 _close(fd);
3257 UNLOCK_FILES();
3258 return file;
3259 }
3260
3261 /*********************************************************************
3262 * _fsopen (MSVCRT.@)
3263 */
3264 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
3265 {
3266 FILE *ret;
3267 wchar_t *pathW = NULL, *modeW = NULL;
3268
3269 if (path && !(pathW = msvcrt_wstrdupa(path))) {
3270 _invalid_parameter(NULL, NULL, NULL, 0, 0);
3271 *_errno() = EINVAL;
3272 return NULL;
3273 }
3274 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3275 {
3276 free(pathW);
3277 _invalid_parameter(NULL, NULL, NULL, 0, 0);
3278 *_errno() = EINVAL;
3279 return NULL;
3280 }
3281
3282 ret = _wfsopen(pathW, modeW, share);
3283
3284 free(pathW);
3285 free(modeW);
3286 return ret;
3287 }
3288
3289 /*********************************************************************
3290 * fopen (MSVCRT.@)
3291 */
3292 FILE * CDECL fopen(const char *path, const char *mode)
3293 {
3294 return _fsopen( path, mode, _SH_DENYNO );
3295 }
3296
3297 /*********************************************************************
3298 * fopen_s (MSVCRT.@)
3299 */
3300 int CDECL fopen_s(FILE** pFile,
3301 const char *filename, const char *mode)
3302 {
3303 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
3304 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
3305 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
3306
3307 *pFile = fopen(filename, mode);
3308
3309 if(!*pFile)
3310 return *_errno();
3311 return 0;
3312 }
3313
3314 /*********************************************************************
3315 * _wfopen (MSVCRT.@)
3316 */
3317 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
3318 {
3319 return _wfsopen( path, mode, _SH_DENYNO );
3320 }
3321
3322 /*********************************************************************
3323 * _wfopen_s (MSVCRT.@)
3324 */
3325 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
3326 const wchar_t *mode)
3327 {
3328 if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
3329 !MSVCRT_CHECK_PMT(mode != NULL)) {
3330 *_errno() = EINVAL;
3331 return EINVAL;
3332 }
3333
3334 *pFile = _wfopen(filename, mode);
3335
3336 if(!*pFile)
3337 return *_errno();
3338 return 0;
3339 }
3340
3341 /* fputc calls _flsbuf which calls fputc */
3342 int CDECL _flsbuf(int c, FILE* file);
3343
3344 /*********************************************************************
3345 * fputc (MSVCRT.@)
3346 */
3347 int CDECL fputc(int c, FILE* file)
3348 {
3349 int res;
3350
3351 _lock_file(file);
3352 if(file->_cnt>0) {
3353 *file->_ptr++=c;
3354 file->_cnt--;
3355 if (c == '\n')
3356 {
3357 res = msvcrt_flush_buffer(file);
3358 _unlock_file(file);
3359 return res ? res : c;
3360 }
3361 else {
3362 _unlock_file(file);
3363 return c & 0xff;
3364 }
3365 } else {
3366 res = _flsbuf(c, file);
3367 _unlock_file(file);
3368 return res;
3369 }
3370 }
3371
3372 /*********************************************************************
3373 * _fputchar (MSVCRT.@)
3374 */
3375 int CDECL _fputchar(int c)
3376 {
3377 return fputc(c, stdout);
3378 }
3379
3380 /*********************************************************************
3381 * fread (MSVCRT.@)
3382 */
3383 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
3384 {
3385 size_t rcnt=size * nmemb;
3386 size_t read=0;
3387 size_t pread=0;
3388
3389 if(!rcnt)
3390 return 0;
3391
3392 _lock_file(file);
3393
3394 /* first buffered data */
3395 if(file->_cnt>0) {
3396 int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
3397 memcpy(ptr, file->_ptr, pcnt);
3398 file->_cnt -= pcnt;
3399 file->_ptr += pcnt;
3400 read += pcnt ;
3401 rcnt -= pcnt ;
3402 ptr = (char*)ptr + pcnt;
3403 } else if(!(file->_flag & _IOREAD )) {
3404 if(file->_flag & _IORW) {
3405 file->_flag |= _IOREAD;
3406 } else {
3407 _unlock_file(file);
3408 return 0;
3409 }
3410 }
3411
3412 if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
3413 msvcrt_alloc_buffer(file);
3414
3415 while(rcnt>0)
3416 {
3417 int i;
3418 if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) {
3419 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
3420 file->_ptr = file->_base;
3421 i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
3422 /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
3423 if (i > 0 && i < file->_cnt) {
3424 get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF;
3425 file->_flag &= ~_IOEOF;
3426 }
3427 if (i > 0) {
3428 memcpy(ptr, file->_ptr, i);
3429 file->_cnt -= i;
3430 file->_ptr += i;
3431 }
3432 } else if (rcnt > INT_MAX) {
3433 i = _read(file->_file, ptr, INT_MAX);
3434 } else if (rcnt < BUFSIZ) {
3435 i = _read(file->_file, ptr, rcnt);
3436 } else {
3437 i = _read(file->_file, ptr, rcnt - BUFSIZ/2);
3438 }
3439 pread += i;
3440 rcnt -= i;
3441 ptr = (char *)ptr+i;
3442 /* expose feof condition in the flags
3443 * MFC tests file->_flag for feof, and doesn't call feof())
3444 */
3445 if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF)
3446 file->_flag |= _IOEOF;
3447 else if (i == -1)
3448 {
3449 file->_flag |= _IOERR;
3450 pread = 0;
3451 rcnt = 0;
3452 }
3453 if (i < 1) break;
3454 }
3455 read+=pread;
3456 _unlock_file(file);
3457 return read / size;
3458 }
3459
3460 /*********************************************************************
3461 * _wfreopen (MSVCRT.@)
3462 *
3463 */
3464 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
3465 {
3466 int open_flags, stream_flags, fd;
3467
3468 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
3469
3470 LOCK_FILES();
3471 if (!file || ((fd = file->_file) < 0) || fd > fdend)
3472 file = NULL;
3473 else
3474 {
3475 fclose(file);
3476 /* map mode string to open() flags. "man fopen" for possibilities. */
3477 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3478 file = NULL;
3479 else
3480 {
3481 fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE);
3482 if (fd < 0)
3483 file = NULL;
3484 else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
3485 {
3486 file->_flag = 0;
3487 WARN(":failed-last error (%d)\n",GetLastError());
3488 _dosmaperr(GetLastError());
3489 file = NULL;
3490 }
3491 }
3492 }
3493 UNLOCK_FILES();
3494 return file;
3495 }
3496
3497 /*********************************************************************
3498 * freopen (MSVCRT.@)
3499 *
3500 */
3501 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
3502 {
3503 FILE *ret;
3504 wchar_t *pathW = NULL, *modeW = NULL;
3505
3506 if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3507 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3508 {
3509 free(pathW);
3510 return NULL;
3511 }
3512
3513 ret = _wfreopen(pathW, modeW, file);
3514
3515 free(pathW);
3516 free(modeW);
3517 return ret;
3518 }
3519
3520 /*********************************************************************
3521 * fsetpos (MSVCRT.@)
3522 */
3523 int CDECL fsetpos(FILE* file, const fpos_t *pos)
3524 {
3525 int ret;
3526
3527 _lock_file(file);
3528 /* Note that all this has been lifted 'as is' from fseek */
3529 if(file->_flag & _IOWRT)
3530 msvcrt_flush_buffer(file);
3531
3532 /* Discard buffered input */
3533 file->_cnt = 0;
3534 file->_ptr = file->_base;
3535
3536 /* Reset direction of i/o */
3537 if(file->_flag & _IORW) {
3538 file->_flag &= ~(_IOREAD|_IOWRT);
3539 }
3540
3541 ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3542 _unlock_file(file);
3543 return ret;
3544 }
3545
3546 /*********************************************************************
3547 * _ftelli64 (MSVCRT.@)
3548 */
3549 __int64 CDECL _ftelli64(FILE* file)
3550 {
3551 __int64 pos;
3552
3553 _lock_file(file);
3554 pos = _telli64(file->_file);
3555 if(pos == -1) {
3556 _unlock_file(file);
3557 return -1;
3558 }
3559 if(file->_flag & (_IOMYBUF | _USERBUF)) {
3560 if(file->_flag & _IOWRT) {
3561 pos += file->_ptr - file->_base;
3562
3563 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3564 char *p;
3565
3566 for(p=file->_base; p<file->_ptr; p++)
3567 if(*p == '\n')
3568 pos++;
3569 }
3570 } else if(!file->_cnt) { /* nothing to do */
3571 } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
3572 int i;
3573
3574 pos -= file->_cnt;
3575 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3576 for(i=0; i<file->_cnt; i++)
3577 if(file->_ptr[i] == '\n')
3578 pos--;
3579 }
3580 } else {
3581 char *p;
3582
3583 if(_lseeki64(file->_file, pos, SEEK_SET) != pos) {
3584 _unlock_file(file);
3585 return -1;
3586 }
3587
3588 pos -= file->_bufsiz;
3589 pos += file->_ptr - file->_base;
3590
3591 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3592 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL)
3593 pos--;
3594
3595 for(p=file->_base; p<file->_ptr; p++)
3596 if(*p == '\n')
3597 pos++;
3598 }
3599 }
3600 }
3601
3602 _unlock_file(file);
3603 return pos;
3604 }
3605
3606 /*********************************************************************
3607 * ftell (MSVCRT.@)
3608 */
3609 LONG CDECL ftell(FILE* file)
3610 {
3611 return (LONG)_ftelli64(file);
3612 }
3613
3614 /*********************************************************************
3615 * fgetpos (MSVCRT.@)
3616 */
3617 int CDECL fgetpos(FILE* file, fpos_t *pos)
3618 {
3619 *pos = _ftelli64(file);
3620 if(*pos == -1)
3621 return -1;
3622 return 0;
3623 }
3624
3625 /*********************************************************************
3626 * fputs (MSVCRT.@)
3627 */
3628 int CDECL fputs(const char *s, FILE* file)
3629 {
3630 size_t len = strlen(s);
3631 int ret;
3632
3633 _lock_file(file);
3634 ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF;
3635 _unlock_file(file);
3636 return ret;
3637 }
3638
3639 /*********************************************************************
3640 * fputws (MSVCRT.@)
3641 */
3642 int CDECL fputws(const wchar_t *s, FILE* file)
3643 {
3644 size_t i, len = strlenW(s);
3645 BOOL tmp_buf;
3646 int ret;
3647
3648 _lock_file(file);
3649 if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3650 ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
3651 _unlock_file(file);
3652 return ret;
3653 }
3654
3655 tmp_buf = add_std_buffer(file);
3656 for (i=0; i<len; i++) {
3657 if(fputwc(s[i], file) == WEOF) {
3658 if(tmp_buf) remove_std_buffer(file);
3659 _unlock_file(file);
3660 return WEOF;
3661 }
3662 }
3663
3664 if(tmp_buf) remove_std_buffer(file);
3665 _unlock_file(file);
3666 return 0;
3667 }
3668
3669 /*********************************************************************
3670 * getchar (MSVCRT.@)
3671 */
3672 int CDECL getchar(void)
3673 {
3674 return fgetc(stdin);
3675 }
3676
3677 /*********************************************************************
3678 * getc (MSVCRT.@)
3679 */
3680 int CDECL getc(FILE* file)
3681 {
3682 return fgetc(file);
3683 }
3684
3685 /*********************************************************************
3686 * gets (MSVCRT.@)
3687 */
3688 char * CDECL gets(char *buf)
3689 {
3690 int cc;
3691 char * buf_start = buf;
3692
3693 _lock_file(stdin);
3694 for(cc = fgetc(stdin); cc != EOF && cc != '\n';
3695 cc = fgetc(stdin))
3696 if(cc != '\r') *buf++ = (char)cc;
3697
3698 *buf = '\0';
3699
3700 TRACE("got '%s'\n", buf_start);
3701 _unlock_file(stdin);
3702 return buf_start;
3703 }
3704
3705 /*********************************************************************
3706 * _getws (MSVCRT.@)
3707 */
3708 wchar_t* CDECL _getws(wchar_t* buf)
3709 {
3710 wint_t cc;
3711 wchar_t* ws = buf;
3712
3713 _lock_file(stdin);
3714 for (cc = fgetwc(stdin); cc != WEOF && cc != '\n';
3715 cc = fgetwc(stdin))
3716 {
3717 if (cc != '\r')
3718 *buf++ = (wchar_t)cc;
3719 }
3720 *buf = '\0';
3721
3722 TRACE("got %s\n", debugstr_w(ws));
3723 _unlock_file(stdin);
3724 return ws;
3725 }
3726
3727 /*********************************************************************
3728 * putc (MSVCRT.@)
3729 */
3730 int CDECL putc(int c, FILE* file)
3731 {
3732 return fputc(c, file);
3733 }
3734
3735 /*********************************************************************
3736 * putchar (MSVCRT.@)
3737 */
3738 int CDECL putchar(int c)
3739 {
3740 return fputc(c, stdout);
3741 }
3742
3743 /*********************************************************************
3744 * _putwch (MSVCRT.@)
3745 */
3746 wint_t CDECL _putwch(wchar_t c)
3747 {
3748 return fputwc(c, stdout);
3749 }
3750
3751 /*********************************************************************
3752 * puts (MSVCRT.@)
3753 */
3754 int CDECL puts(const char *s)
3755 {
3756 size_t len = strlen(s);
3757 int ret;
3758
3759 _lock_file(stdout);
3760 if(fwrite(s, sizeof(*s), len, stdout) != len) {
3761 _unlock_file(stdout);
3762 return EOF;
3763 }
3764
3765 ret = fwrite("\n",1,1,stdout) == 1 ? 0 : EOF;
3766 _unlock_file(stdout);
3767 return ret;
3768 }
3769
3770 /*********************************************************************
3771 * _putws (MSVCRT.@)
3772 */
3773 int CDECL _putws(const wchar_t *s)
3774 {
3775 static const wchar_t nl = '\n';
3776 size_t len = strlenW(s);
3777 int ret;
3778
3779 _lock_file(stdout);
3780 if(fwrite(s, sizeof(*s), len, stdout) != len) {
3781 _unlock_file(stdout);
3782 return EOF;
3783 }
3784
3785 ret = fwrite(&nl,sizeof(nl),1,stdout) == 1 ? 0 : EOF;
3786 _unlock_file(stdout);
3787 return ret;
3788 }
3789
3790 /*********************************************************************
3791 * remove (MSVCRT.@)
3792 */
3793 int CDECL remove(const char *path)
3794 {
3795 TRACE("(%s)\n",path);
3796 if (DeleteFileA(path))
3797 return 0;
3798 TRACE(":failed (%d)\n",GetLastError());
3799 _dosmaperr(GetLastError());
3800 return -1;
3801 }
3802
3803 /*********************************************************************
3804 * _wremove (MSVCRT.@)
3805 */
3806 int CDECL _wremove(const wchar_t *path)
3807 {
3808 TRACE("(%s)\n",debugstr_w(path));
3809 if (DeleteFileW(path))
3810 return 0;
3811 TRACE(":failed (%d)\n",GetLastError());
3812 _dosmaperr(GetLastError());
3813 return -1;
3814 }
3815
3816 /*********************************************************************
3817 * rename (MSVCRT.@)
3818 */
3819 int CDECL rename(const char *oldpath,const char *newpath)
3820 {
3821 TRACE(":from %s to %s\n",oldpath,newpath);
3822 if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3823 return 0;
3824 TRACE(":failed (%d)\n",GetLastError());
3825 _dosmaperr(GetLastError());
3826 return -1;
3827 }
3828
3829 /*********************************************************************
3830 * _wrename (MSVCRT.@)
3831 */
3832 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
3833 {
3834 TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
3835 if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3836 return 0;
3837 TRACE(":failed (%d)\n",GetLastError());
3838 _dosmaperr(GetLastError());
3839 return -1;
3840 }
3841
3842 /*********************************************************************
3843 * setvbuf (MSVCRT.@)
3844 */
3845 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
3846 {
3847 if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
3848 if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1;
3849 if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1;
3850
3851 _lock_file(file);
3852
3853 fflush(file);
3854 if(file->_flag & _IOMYBUF)
3855 free(file->_base);
3856 file->_flag &= ~(_IONBF | _IOMYBUF | _USERBUF);
3857 file->_cnt = 0;
3858
3859 if(mode == _IONBF) {
3860 file->_flag |= _IONBF;
3861 file->_base = file->_ptr = (char*)&file->_charbuf;
3862 file->_bufsiz = 2;
3863 }else if(buf) {
3864 file->_base = file->_ptr = buf;
3865 file->_flag |= _USERBUF;
3866 file->_bufsiz = size;
3867 }else {
3868 file->_base = file->_ptr = malloc(size);
3869 if(!file->_base) {
3870 file->_bufsiz = 0;
3871 _unlock_file(file);
3872 return -1;
3873 }
3874
3875 file->_flag |= _IOMYBUF;
3876 file->_bufsiz = size;
3877 }
3878 _unlock_file(file);
3879 return 0;
3880 }
3881
3882 /*********************************************************************
3883 * setbuf (MSVCRT.@)
3884 */
3885 void CDECL setbuf(FILE* file, char *buf)
3886 {
3887 setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3888 }
3889
3890 /*********************************************************************
3891 * tmpnam (MSVCRT.@)
3892 */
3893 char * CDECL tmpnam(char *s)
3894 {
3895 char tmpstr[16];
3896 char *p;
3897 int count, size;
3898
3899 if (!s) {
3900 thread_data_t *data = msvcrt_get_thread_data();
3901
3902 if(!data->tmpnam_buffer)
3903 data->tmpnam_buffer = malloc(MAX_PATH);
3904
3905 s = data->tmpnam_buffer;
3906 }
3907
3908 msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
3909 p = s + sprintf(s, "\\s%s.", tmpstr);
3910 for (count = 0; count < TMP_MAX; count++)
3911 {
3912 size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr);
3913 memcpy(p, tmpstr, size);
3914 p[size] = '\0';
3915 if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
3916 GetLastError() == ERROR_FILE_NOT_FOUND)
3917 break;
3918 }
3919 return s;
3920 }
3921
3922 /*********************************************************************
3923 * _wtmpnam (MSVCRT.@)
3924 */
3925 wchar_t * CDECL _wtmpnam(wchar_t *s)
3926 {
3927 static const wchar_t format[] = {'\\','s','%','s','.',0};
3928 wchar_t tmpstr[16];
3929 wchar_t *p;
3930 int count, size;
3931 if (!s) {
3932 thread_data_t *data = msvcrt_get_thread_data();
3933
3934 if(!data->wtmpnam_buffer)
3935 data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
3936
3937 s = data->wtmpnam_buffer;
3938 }
3939
3940 msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
3941 p = s + _snwprintf(s, MAX_PATH, format, tmpstr);
3942 for (count = 0; count < TMP_MAX; count++)
3943 {
3944 size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr);
3945 memcpy(p, tmpstr, size*sizeof(wchar_t));
3946 p[size] = '\0';
3947 if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
3948 GetLastError() == ERROR_FILE_NOT_FOUND)
3949 break;
3950 }
3951 return s;
3952 }
3953
3954 /*********************************************************************
3955 * tmpfile (MSVCRT.@)
3956 */
3957 FILE* CDECL tmpfile(void)
3958 {
3959 char *filename = tmpnam(NULL);
3960 int fd;
3961 FILE* file = NULL;
3962
3963 LOCK_FILES();
3964 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
3965 _S_IREAD | _S_IWRITE);
3966 if (fd != -1 && (file = msvcrt_alloc_fp()))
3967 {
3968 if (msvcrt_init_fp(file, fd, _IORW) == -1)
3969 {
3970 file->_flag = 0;
3971 file = NULL;
3972 }
3973 else file->_tmpfname = _strdup(filename);
3974 }
3975
3976 if(fd != -1 && !file)
3977 _close(fd);
3978 UNLOCK_FILES();
3979 return file;
3980 }
3981
3982 /*********************************************************************
3983 * ungetc (MSVCRT.@)
3984 */
3985 int CDECL ungetc(int c, FILE * file)
3986 {
3987 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3988
3989 if (c == EOF || !(file->_flag&_IOREAD ||
3990 (file->_flag&_IORW && !(file->_flag&_IOWRT))))
3991 return EOF;
3992
3993 _lock_file(file);
3994 if((!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
3995 && msvcrt_alloc_buffer(file))
3996 || (!file->_cnt && file->_ptr==file->_base))
3997 file->_ptr++;
3998
3999 if(file->_ptr>file->_base) {
4000 file->_ptr--;
4001 if(file->_flag & _IOSTRG) {
4002 if(*file->_ptr != c) {
4003 file->_ptr++;
4004 _unlock_file(file);
4005 return EOF;
4006 }
4007 }else {
4008 *file->_ptr = c;
4009 }
4010 file->_cnt++;
4011 clearerr(file);
4012 file->_flag |= _IOREAD;
4013 _unlock_file(file);
4014 return c;
4015 }
4016
4017 _unlock_file(file);
4018 return EOF;
4019 }
4020
4021 /*********************************************************************
4022 * ungetwc (MSVCRT.@)
4023 */
4024 wint_t CDECL ungetwc(wint_t wc, FILE * file)
4025 {
4026 wchar_t mwc = wc;
4027
4028 if (wc == WEOF)
4029 return WEOF;
4030
4031 _lock_file(file);
4032
4033 if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
4034 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
4035 unsigned char * pp = (unsigned char *)&mwc;
4036 int i;
4037
4038 for(i=sizeof(wchar_t)-1;i>=0;i--) {
4039 if(pp[i] != ungetc(pp[i],file)) {
4040 _unlock_file(file);
4041 return WEOF;
4042 }
4043 }
4044 }else {
4045 char mbs[MB_LEN_MAX];
4046 int len;
4047
4048 len = wctomb(mbs, mwc);
4049 if(len == -1) {
4050 _unlock_file(file);
4051 return WEOF;
4052 }
4053
4054 for(len--; len>=0; len--) {
4055 if(mbs[len] != ungetc(mbs[len], file)) {
4056 _unlock_file(file);
4057 return WEOF;
4058 }
4059 }
4060 }
4061
4062 _unlock_file(file);
4063 return mwc;
4064 }
4065
4066
4067
4068 /*********************************************************************
4069 * _getmaxstdio (MSVCRT.@)
4070 */
4071 int CDECL _getmaxstdio(void)
4072 {
4073 return MSVCRT_max_streams;
4074 }
4075
4076 /*********************************************************************
4077 * _setmaxstdio (MSVCRT.@)
4078 */
4079 int CDECL _setmaxstdio(int newmax)
4080 {
4081 TRACE("%d\n", newmax);
4082
4083 if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
4084 return -1;
4085
4086 MSVCRT_max_streams = newmax;
4087 return MSVCRT_max_streams;
4088 }