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