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