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