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