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