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