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