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