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