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