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