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