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