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