2 * CRTDLL file functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * Implementation Notes:
10 * Mapping is performed between FILE*, fd and HANDLE's. This allows us to
11 * implement all calls using the Win32 API, support remapping fd's to
12 * FILES and do some other tricks as well (like closeall, _get_osfhandle).
13 * For mix and matching with the host libc, processes can use the Win32 HANDLE
14 * to get a real unix fd from the wineserver. Or we could do this once
15 * on create, and provide a function to return it quickly (store it
16 * in the mapping table). Note that If you actuall _do_ this, you should
17 * call rewind() before using any other crt functions on the file. To avoid
18 * the confusion I got when reading the API docs, fd is always refered
19 * to as a file descriptor here. In the API docs its called a file handle
20 * which is confusing with Win32 HANDLES.
21 * M$ CRT includes inline versions of some of these functions (like feof()).
22 * These inlines check/modify bitfields in the FILE structure, so we set
23 * _flags/_file/_cnt in the FILE* to be binary compatible with the win dll.
24 * lcc defines _IOAPPEND as one of the flags for a FILE*, but testing shows
25 * that M$ CRT never sets it. So we keep the flag in our mapping table but
26 * mask it out when we populate a FILE* with it. Then when we write we seek
27 * to EOF if _IOAPPEND is set for the underlying fd.
30 * Not MT safe. Need locking around file access and allocation for this.
31 * NT has no effective limit on files - neither should we. This will be fixed
32 * with dynamic allocation of the file mapping array.
33 * Buffering is handled differently. Have to investigate a) how much control
34 * we have over buffering in win32, and b) if we care ;-)
44 DEFAULT_DEBUG_CHANNEL(crtdll
);
46 /* FIXME: Make this dynamic */
47 #define CRTDLL_MAX_FILES 257
49 HANDLE __CRTDLL_handles
[CRTDLL_MAX_FILES
];
50 CRTDLL_FILE
* __CRTDLL_files
[CRTDLL_MAX_FILES
];
51 INT __CRTDLL_flags
[CRTDLL_MAX_FILES
];
52 LPSTR __CRTDLL_tempfiles
[CRTDLL_MAX_FILES
];
53 CRTDLL_FILE __CRTDLL_iob
[3];
55 static int __CRTDLL_fdstart
= 3; /* first unallocated fd */
56 static int __CRTDLL_fdend
= 3; /* highest allocated fd */
58 /* INTERNAL: process umask */
59 static INT __CRTDLL_umask
= 0;
61 /* INTERNAL: Static buffer for temp file name */
62 static char CRTDLL_tmpname
[MAX_PATH
];
64 /* file extentions recognised as executables */
65 static const unsigned int EXE
= 'e' << 16 | 'x' << 8 | 'e';
66 static const unsigned int BAT
= 'b' << 16 | 'a' << 8 | 't';
67 static const unsigned int CMD
= 'c' << 16 | 'm' << 8 | 'd';
68 static const unsigned int COM
= 'c' << 16 | 'o' << 8 | 'm';
70 /* for stat mode, permissions apply to all,owner and group */
71 #define CRTDLL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
72 #define CRTDLL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
73 #define CRTDLL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
76 /* INTERNAL: Get the HANDLE for a fd */
77 static HANDLE
__CRTDLL__fdtoh(INT fd
);
78 static HANDLE
__CRTDLL__fdtoh(INT fd
)
80 if (fd
< 0 || fd
>= __CRTDLL_fdend
||
81 __CRTDLL_handles
[fd
] == INVALID_HANDLE_VALUE
)
83 WARN(":fd (%d) - no handle!\n",fd
);
86 return INVALID_HANDLE_VALUE
;
88 return __CRTDLL_handles
[fd
];
92 /* INTERNAL: free a file entry fd */
93 static void __CRTDLL__free_fd(INT fd
);
94 static void __CRTDLL__free_fd(INT fd
)
96 __CRTDLL_handles
[fd
] = INVALID_HANDLE_VALUE
;
97 __CRTDLL_files
[fd
] = 0;
98 __CRTDLL_flags
[fd
] = 0;
99 TRACE(":fd (%d) freed\n",fd
);
101 return; /* dont use 0,1,2 for user files */
102 if (fd
== __CRTDLL_fdend
- 1)
104 if (fd
< __CRTDLL_fdstart
)
105 __CRTDLL_fdstart
= fd
;
109 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
110 static INT
__CRTDLL__alloc_fd(HANDLE hand
, INT flag
);
111 static INT
__CRTDLL__alloc_fd(HANDLE hand
, INT flag
)
113 INT fd
= __CRTDLL_fdstart
;
115 TRACE(":handle (%d) allocating fd (%d)\n",hand
,fd
);
116 if (fd
>= CRTDLL_MAX_FILES
)
118 WARN(":files exhausted!\n");
121 __CRTDLL_handles
[fd
] = hand
;
122 __CRTDLL_flags
[fd
] = flag
;
124 /* locate next free slot */
125 if (fd
== __CRTDLL_fdend
)
126 __CRTDLL_fdstart
= ++__CRTDLL_fdend
;
128 while(__CRTDLL_fdstart
< __CRTDLL_fdend
&&
129 __CRTDLL_handles
[__CRTDLL_fdstart
] != INVALID_HANDLE_VALUE
)
136 /* INTERNAL: Allocate a FILE* for an fd slot
137 * This is done lazily to avoid memory wastage for low level open/write
138 * usage when a FILE* is not requested (but may be later).
140 static CRTDLL_FILE
* __CRTDLL__alloc_fp(INT fd
);
141 static CRTDLL_FILE
* __CRTDLL__alloc_fp(INT fd
)
143 TRACE(":fd (%d) allocating FILE*\n",fd
);
144 if (fd
< 0 || fd
>= __CRTDLL_fdend
||
145 __CRTDLL_handles
[fd
] == INVALID_HANDLE_VALUE
)
147 WARN(":invalid fd %d\n",fd
);
149 CRTDLL_errno
= EBADF
;
152 if (!__CRTDLL_files
[fd
])
154 if ((__CRTDLL_files
[fd
] = CRTDLL_calloc(sizeof(CRTDLL_FILE
),1)))
156 __CRTDLL_files
[fd
]->_file
= fd
;
157 __CRTDLL_files
[fd
]->_flag
= __CRTDLL_flags
[fd
];
158 __CRTDLL_files
[fd
]->_flag
&= ~_IOAPPEND
; /* mask out, see above */
161 TRACE(":got FILE* (%p)\n",__CRTDLL_files
[fd
]);
162 return __CRTDLL_files
[fd
];
166 /* INTERNAL: Set up stdin, stderr and stdout */
167 VOID
__CRTDLL__init_io(VOID
)
170 memset(__CRTDLL_iob
,0,3*sizeof(CRTDLL_FILE
));
171 __CRTDLL_handles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
172 __CRTDLL_flags
[0] = __CRTDLL_iob
[0]._flag
= _IOREAD
;
173 __CRTDLL_handles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
174 __CRTDLL_flags
[1] = __CRTDLL_iob
[1]._flag
= _IOWRT
;
175 __CRTDLL_handles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
176 __CRTDLL_flags
[2] = __CRTDLL_iob
[2]._flag
= _IOWRT
;
178 TRACE(":handles (%d)(%d)(%d)\n",__CRTDLL_handles
[0],
179 __CRTDLL_handles
[1],__CRTDLL_handles
[2]);
181 for (i
= 0; i
< 3; i
++)
183 /* FILE structs for stdin/out/err are static and never deleted */
184 __CRTDLL_files
[i
] = &__CRTDLL_iob
[i
];
185 __CRTDLL_iob
[i
]._file
= i
;
186 __CRTDLL_tempfiles
[i
] = NULL
;
191 /*********************************************************************
192 * _access (CRTDLL.37)
194 INT __cdecl
CRTDLL__access(LPCSTR filename
, INT mode
)
196 DWORD attr
= GetFileAttributesA(filename
);
198 if (attr
== 0xffffffff)
202 /* FIXME: Should GetFileAttributesA() return this? */
203 __CRTDLL__set_errno(ERROR_INVALID_DATA
);
206 __CRTDLL__set_errno(GetLastError());
209 if ((attr
& FILE_ATTRIBUTE_READONLY
) && (mode
& W_OK
))
211 __CRTDLL__set_errno(ERROR_ACCESS_DENIED
);
214 TRACE(":file %s, mode (%d) ok\n",filename
,mode
);
219 /*********************************************************************
220 * _chmod (CRTDLL.054)
222 * Change a files permissions.
224 INT __cdecl
CRTDLL__chmod(LPCSTR path
, INT flags
)
226 DWORD oldFlags
= GetFileAttributesA(path
);
228 if (oldFlags
!= 0x0FFFFFFFF)
230 DWORD newFlags
= (flags
& _S_IWRITE
)? oldFlags
& ~FILE_ATTRIBUTE_READONLY
:
231 oldFlags
| FILE_ATTRIBUTE_READONLY
;
233 if (newFlags
== oldFlags
|| SetFileAttributesA( path
, newFlags
))
236 __CRTDLL__set_errno(GetLastError());
241 /*********************************************************************
244 * Close an open file descriptor.
246 INT __cdecl
CRTDLL__close(INT fd
)
248 HANDLE hand
= __CRTDLL__fdtoh(fd
);
250 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
251 if (hand
== INVALID_HANDLE_VALUE
)
254 /* Dont free std FILE*'s, they are not dynamic */
255 if (fd
> 2 && __CRTDLL_files
[fd
])
256 CRTDLL_free(__CRTDLL_files
[fd
]);
258 __CRTDLL__free_fd(fd
);
260 if (!CloseHandle(hand
))
262 WARN(":failed-last error (%ld)\n",GetLastError());
263 __CRTDLL__set_errno(GetLastError());
266 if (__CRTDLL_tempfiles
[fd
])
268 TRACE("deleting temporary file '%s'\n",__CRTDLL_tempfiles
[fd
]);
269 CRTDLL__unlink(__CRTDLL_tempfiles
[fd
]);
270 CRTDLL_free(__CRTDLL_tempfiles
[fd
]);
271 __CRTDLL_tempfiles
[fd
] = NULL
;
279 /*********************************************************************
280 * _commit (CRTDLL.58)
282 * Ensure all file operations have been flushed to the drive.
284 INT __cdecl
CRTDLL__commit(INT fd
)
286 HANDLE hand
= __CRTDLL__fdtoh(fd
);
288 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
289 if (hand
== INVALID_HANDLE_VALUE
)
292 if (!FlushFileBuffers(hand
))
294 if (GetLastError() == ERROR_INVALID_HANDLE
)
296 /* FlushFileBuffers fails for console handles
297 * so we ignore this error.
301 TRACE(":failed-last error (%ld)\n",GetLastError());
302 __CRTDLL__set_errno(GetLastError());
310 /*********************************************************************
311 * _creat (CRTDLL.066)
313 * Open a file, creating it if it is not present.
315 INT __cdecl
CRTDLL__creat(LPCSTR path
, INT flags
)
317 INT usedFlags
= (flags
& _O_TEXT
)| _O_CREAT
| _O_WRONLY
| _O_TRUNC
;
318 return CRTDLL__open(path
, usedFlags
);
322 /*********************************************************************
325 * Determine if the file pointer is at the end of a file.
328 * Care for large files
330 INT __cdecl
CRTDLL__eof( INT fd
)
333 HANDLE hand
= __CRTDLL__fdtoh(fd
);
335 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
337 if (hand
== INVALID_HANDLE_VALUE
)
340 /* If we have a FILE* for this file, the EOF flag
341 * will be set by the read()/write() functions.
343 if (__CRTDLL_files
[fd
])
344 return __CRTDLL_files
[fd
]->_flag
& _IOEOF
;
346 /* Otherwise we do it the hard way */
347 curpos
= SetFilePointer( hand
, 0, NULL
, SEEK_CUR
);
348 endpos
= SetFilePointer( hand
, 0, NULL
, FILE_END
);
350 if (curpos
== endpos
)
353 SetFilePointer( hand
, curpos
, 0, FILE_BEGIN
);
358 /*********************************************************************
359 * _fcloseall (CRTDLL.089)
361 * Close all open files except stdin/stdout/stderr.
363 INT __cdecl
CRTDLL__fcloseall(VOID
)
365 int num_closed
= 0, i
= 3;
367 while(i
< __CRTDLL_fdend
)
368 if (__CRTDLL_handles
[i
] != INVALID_HANDLE_VALUE
)
375 TRACE(":closed (%d) handles\n",num_closed
);
380 /*********************************************************************
381 * _fdopen (CRTDLL.091)
383 * Get a FILE* from a low level file descriptor.
385 CRTDLL_FILE
* __cdecl
CRTDLL__fdopen(INT fd
, LPCSTR mode
)
387 CRTDLL_FILE
* file
= __CRTDLL__alloc_fp(fd
);
389 TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd
,mode
,file
);
397 /*********************************************************************
398 * _fgetchar (CRTDLL.092)
400 INT __cdecl
CRTDLL__fgetchar( VOID
)
402 return CRTDLL_fgetc(CRTDLL_stdin
);
406 /*********************************************************************
407 * _filbuf (CRTDLL.094)
410 * The macro version of getc calls this function whenever FILE->_cnt
411 * becomes negative. We ensure that _cnt is always 0 after any read
412 * so this function is always called. Our implementation simply calls
413 * fgetc as all the underlying buffering is handled by Wines
414 * implementation of the Win32 file I/O calls.
416 INT __cdecl
CRTDLL__filbuf(CRTDLL_FILE
* file
)
418 return CRTDLL_fgetc(file
);
421 /*********************************************************************
422 * _filelength (CRTDLL.097)
424 * Get the length of an open file.
426 LONG __cdecl
CRTDLL__filelength(INT fd
)
428 LONG curPos
= CRTDLL__lseek(fd
, 0, SEEK_CUR
);
431 LONG endPos
= CRTDLL__lseek(fd
, 0, SEEK_END
);
434 if (endPos
!= curPos
)
435 CRTDLL__lseek(fd
, curPos
, SEEK_SET
);
443 /*********************************************************************
444 * _fileno (CRTDLL.097)
446 * Get the file descriptor from a FILE*.
449 * This returns the CRTDLL fd, _not_ the underlying *nix fd.
451 INT __cdecl
CRTDLL__fileno(CRTDLL_FILE
* file
)
453 TRACE(":FILE* (%p) fd (%d)\n",file
,file
->_file
);
458 /*********************************************************************
459 * _flsbuf (CRTDLL.102)
462 * The macro version of putc calls this function whenever FILE->_cnt
463 * becomes negative. We ensure that _cnt is always 0 after any write
464 * so this function is always called. Our implementation simply calls
465 * fputc as all the underlying buffering is handled by Wines
466 * implementation of the Win32 file I/O calls.
468 INT __cdecl
CRTDLL__flsbuf(INT c
, CRTDLL_FILE
* file
)
470 return CRTDLL_fputc(c
,file
);
474 /*********************************************************************
475 * _flushall (CRTDLL.103)
477 * Flush all open files.
479 INT __cdecl
CRTDLL__flushall(VOID
)
481 int num_flushed
= 0, i
= 3;
483 while(i
< __CRTDLL_fdend
)
484 if (__CRTDLL_handles
[i
] != INVALID_HANDLE_VALUE
)
486 if (CRTDLL__commit(i
) == -1)
487 if (__CRTDLL_files
[i
])
488 __CRTDLL_files
[i
]->_flag
|= _IOERR
;
492 TRACE(":flushed (%d) handles\n",num_flushed
);
497 /*********************************************************************
498 * _fputchar (CRTDLL.108)
500 * Put a character to a file.
502 INT __cdecl
CRTDLL__fputchar(INT c
)
504 return CRTDLL_fputc(c
, CRTDLL_stdout
);
508 /*********************************************************************
509 * _fsopen (CRTDLL.110)
511 * Open a FILE* with sharing.
513 CRTDLL_FILE
* __cdecl
CRTDLL__fsopen(LPCSTR path
, LPCSTR mode
, INT share
)
515 FIXME(":(%s,%s,%d),ignoring share mode!\n",path
,mode
,share
);
516 return CRTDLL_fopen(path
,mode
);
520 /*********************************************************************
521 * _fstat (CRTDLL.111)
523 * Get information about an open file.
525 int __cdecl
CRTDLL__fstat(int fd
, struct _stat
* buf
)
528 BY_HANDLE_FILE_INFORMATION hfi
;
529 HANDLE hand
= __CRTDLL__fdtoh(fd
);
531 TRACE(":fd (%d) stat (%p)\n",fd
,buf
);
532 if (hand
== INVALID_HANDLE_VALUE
)
537 WARN(":failed-NULL buf\n");
538 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER
);
542 memset(&hfi
, 0, sizeof(hfi
));
543 memset(buf
, 0, sizeof(struct _stat
));
544 if (!GetFileInformationByHandle(hand
, &hfi
))
546 WARN(":failed-last error (%ld)\n",GetLastError());
547 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER
);
550 FIXME(":dwFileAttributes = %d, mode set to 0",hfi
.dwFileAttributes
);
551 buf
->st_nlink
= hfi
.nNumberOfLinks
;
552 buf
->st_size
= hfi
.nFileSizeLow
;
553 RtlTimeToSecondsSince1970( &hfi
.ftLastAccessTime
, &dw
);
555 RtlTimeToSecondsSince1970( &hfi
.ftLastWriteTime
, &dw
);
556 buf
->st_mtime
= buf
->st_ctime
= dw
;
561 /*********************************************************************
562 * _futime (CRTDLL.115)
564 * Set the file access/modification times on an open file.
566 INT __cdecl
CRTDLL__futime(INT fd
, struct _utimbuf
*t
)
568 HANDLE hand
= __CRTDLL__fdtoh(fd
);
574 CRTDLL_time(&currTime
);
575 RtlSecondsSince1970ToTime( currTime
, &at
);
576 memcpy( &wt
, &at
, sizeof(wt
) );
580 RtlSecondsSince1970ToTime( t
->actime
, &at
);
581 if (t
->actime
== t
->modtime
)
582 memcpy( &wt
, &at
, sizeof(wt
) );
584 RtlSecondsSince1970ToTime( t
->modtime
, &wt
);
587 if (!SetFileTime( hand
, NULL
, &at
, &wt
))
589 __CRTDLL__set_errno(GetLastError());
596 /*********************************************************************
597 * _get_osfhandle (CRTDLL.117)
599 * Return a Win32 HANDLE from a file descriptor.
602 * fd [in] A valid file descriptor
605 * Success: A Win32 HANDLE
607 * Failure: INVALID_HANDLE_VALUE.
610 HANDLE
CRTDLL__get_osfhandle(INT fd
)
612 HANDLE hand
= __CRTDLL__fdtoh(fd
);
613 HANDLE newhand
= hand
;
614 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
616 if (hand
!= INVALID_HANDLE_VALUE
)
618 /* FIXME: I'm not convinced that I should be copying the
619 * handle here - it may be leaked if the app doesn't
620 * close it (and the API docs dont say that it should)
621 * Not duplicating it means that it can't be inherited
622 * and so lcc's wedit doesn't cope when it passes it to
623 * child processes. I've an idea that it should either
624 * be copied by CreateProcess, or marked as inheritable
625 * when initialised, or maybe both? JG 21-9-00.
627 DuplicateHandle(GetCurrentProcess(),hand
,GetCurrentProcess(),
628 &newhand
,0,TRUE
,DUPLICATE_SAME_ACCESS
);
634 /*********************************************************************
637 * Read an integter from a FILE*.
639 INT __cdecl
CRTDLL__getw( CRTDLL_FILE
* file
)
642 if (CRTDLL__read(file
->_file
, &i
, sizeof(INT
)) != 1)
648 /*********************************************************************
649 * _isatty (CRTDLL.137)
651 * Return non zero if fd is a character device (e.g console).
653 INT __cdecl
CRTDLL__isatty(INT fd
)
655 HANDLE hand
= __CRTDLL__fdtoh(fd
);
657 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
658 if (hand
== INVALID_HANDLE_VALUE
)
661 return GetFileType(fd
) == FILE_TYPE_CHAR
? 1 : 0;
665 /*********************************************************************
666 * _lseek (CRTDLL.179)
668 * Move the file pointer within a file.
670 LONG __cdecl
CRTDLL__lseek( INT fd
, LONG offset
, INT whence
)
673 HANDLE hand
= __CRTDLL__fdtoh(fd
);
675 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
676 if (hand
== INVALID_HANDLE_VALUE
)
679 if (whence
< 0 || whence
> 2)
681 CRTDLL_errno
= EINVAL
;
685 TRACE(":fd (%d) to 0x%08lx pos %s\n",
686 fd
,offset
,(whence
==SEEK_SET
)?"SEEK_SET":
687 (whence
==SEEK_CUR
)?"SEEK_CUR":
688 (whence
==SEEK_END
)?"SEEK_END":"UNKNOWN");
690 if ((ret
= SetFilePointer( hand
, offset
, NULL
, whence
)) != 0xffffffff)
692 if ( __CRTDLL_files
[fd
])
693 __CRTDLL_files
[fd
]->_flag
&= ~_IOEOF
;
694 /* FIXME: What if we seek _to_ EOF - is EOF set? */
697 TRACE(":error-last error (%ld)\n",GetLastError());
698 if ( __CRTDLL_files
[fd
])
699 switch(GetLastError())
701 case ERROR_NEGATIVE_SEEK
:
702 case ERROR_SEEK_ON_DEVICE
:
703 __CRTDLL__set_errno(GetLastError());
704 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
712 /*********************************************************************
713 * _mktemp (CRTDLL.239)
715 * Create a temporary file name.
717 LPSTR __cdecl
CRTDLL__mktemp(LPSTR pattern
)
720 LPSTR retVal
= pattern
;
725 numX
= (*pattern
++ == 'X')? numX
+ 1 : 0;
729 id
= GetCurrentProcessId();
733 INT tempNum
= id
/ 10;
734 *pattern
-- = id
- (tempNum
* 10) + '0';
740 if (GetFileAttributesA( retVal
) == 0xFFFFFFFF &&
741 GetLastError() == ERROR_FILE_NOT_FOUND
)
744 } while(letter
!= '|');
748 /*********************************************************************
752 INT __cdecl
CRTDLL__open(LPCSTR path
,INT flags
)
754 DWORD access
= 0, creation
= 0;
758 TRACE(":file (%s) mode 0x%04x\n",path
,flags
);
760 switch(flags
& (_O_RDONLY
| _O_WRONLY
| _O_RDWR
))
763 access
|= GENERIC_READ
;
767 access
|= GENERIC_WRITE
;
771 access
|= GENERIC_WRITE
| GENERIC_READ
;
776 if (flags
& _O_CREAT
)
779 creation
= CREATE_NEW
;
780 else if (flags
& _O_TRUNC
)
781 creation
= CREATE_ALWAYS
;
783 creation
= OPEN_ALWAYS
;
785 else /* no _O_CREAT */
787 if (flags
& _O_TRUNC
)
788 creation
= TRUNCATE_EXISTING
;
790 creation
= OPEN_EXISTING
;
792 if (flags
& _O_APPEND
)
796 flags
|= _O_BINARY
; /* FIXME: Default to text */
800 /* Dont warn when writing */
801 if (ioflag
& GENERIC_READ
)
802 FIXME(":TEXT node not implemented\n");
806 if (flags
& ~(_O_BINARY
|_O_TEXT
|_O_APPEND
|_O_TRUNC
|_O_EXCL
807 |_O_CREAT
|_O_RDWR
|_O_TEMPORARY
))
808 TRACE(":unsupported flags 0x%04x\n",flags
);
810 hand
= CreateFileA( path
, access
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
811 NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, -1);
813 if (hand
== INVALID_HANDLE_VALUE
)
815 WARN(":failed-last error (%ld)\n",GetLastError());
816 __CRTDLL__set_errno(GetLastError());
820 fd
= __CRTDLL__alloc_fd(hand
, ioflag
);
822 TRACE(":fd (%d) handle (%d)\n",fd
, hand
);
826 if (flags
& _O_TEMPORARY
)
827 __CRTDLL_tempfiles
[fd
] = CRTDLL__strdup(path
);
828 if (ioflag
& _IOAPPEND
)
829 CRTDLL__lseek(fd
, 0, FILE_END
);
836 /*********************************************************************
837 * _open_osfhandle (CRTDLL.240)
839 * Create a file descriptor for a file HANDLE.
841 INT __cdecl
CRTDLL__open_osfhandle(HANDLE hand
, INT flags
)
843 INT fd
= __CRTDLL__alloc_fd(hand
,flags
);
844 TRACE(":handle (%d) fd (%d)\n",hand
,fd
);
849 /*********************************************************************
852 * Write an int to a FILE*.
854 INT __cdecl
CRTDLL__putw(INT val
, CRTDLL_FILE
* file
)
856 return CRTDLL__write(file
->_file
, &val
, sizeof(val
)) == 1? val
: EOF
;
860 /*********************************************************************
861 * _rmtmp (CRTDLL.256)
863 * Remove all temporary files created by tmpfile().
865 INT __cdecl
CRTDLL__rmtmp(void)
867 int num_removed
= 0, i
= 3;
869 while(i
< __CRTDLL_fdend
)
870 if (__CRTDLL_tempfiles
[i
])
877 TRACE(":removed (%d) temp files\n",num_removed
);
882 /*********************************************************************
885 * Read data from a file.
887 INT __cdecl
CRTDLL__read(INT fd
, LPVOID buf
, UINT count
)
890 HANDLE hand
= __CRTDLL__fdtoh(fd
);
892 /* Dont trace small reads, it gets *very* annoying */
894 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd
,hand
,buf
,count
);
895 if (hand
== INVALID_HANDLE_VALUE
)
898 /* Set _cnt to 0 so optimised binaries will call our implementation
899 * of putc/getc. See _filbuf/_flsbuf comments.
901 if (__CRTDLL_files
[fd
])
902 __CRTDLL_files
[fd
]->_cnt
= 0;
904 if (ReadFile(hand
, buf
, count
, &num_read
, NULL
))
906 if (num_read
!= count
&& __CRTDLL_files
[fd
])
909 __CRTDLL_files
[fd
]->_flag
|= _IOEOF
;
913 TRACE(":failed-last error (%ld)\n",GetLastError());
914 if ( __CRTDLL_files
[fd
])
915 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
920 /*********************************************************************
921 * _setmode (CRTDLL.265)
923 * FIXME: At present we ignore the request to translate CR/LF to LF.
925 * We always translate when we read with fgets, we never do with fread
928 INT __cdecl
CRTDLL__setmode(INT fd
,INT mode
)
931 FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd
,mode
);
936 /*********************************************************************
939 INT __cdecl
CRTDLL__stat(const char* path
, struct _stat
* buf
)
942 WIN32_FILE_ATTRIBUTE_DATA hfi
;
943 unsigned short mode
= CRTDLL_S_IREAD
;
946 TRACE(":file (%s) buf(%p)\n",path
,buf
);
948 if (!GetFileAttributesExA( path
, GetFileExInfoStandard
, &hfi
))
950 TRACE("failed-last error (%ld)\n",GetLastError());
951 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND
);
955 memset(buf
,0,sizeof(struct _stat
));
957 /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */
959 buf
->st_dev
= buf
->st_rdev
= toupper(*path
- 'A'); /* drive num */
961 buf
->st_dev
= buf
->st_rdev
= CRTDLL__getdrive() - 1;
965 /* Dir, or regular file? */
966 if ((hfi
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ||
967 (path
[plen
-1] == '\\'))
968 mode
|= (_S_IFDIR
| CRTDLL_S_IEXEC
);
973 if (plen
> 6 && path
[plen
-4] == '.') /* shortest exe: "\x.exe" */
975 unsigned int ext
= tolower(path
[plen
-1]) | (tolower(path
[plen
-2]) << 8)
976 | (tolower(path
[plen
-3]) << 16);
977 if (ext
== EXE
|| ext
== BAT
|| ext
== CMD
|| ext
== COM
)
978 mode
|= CRTDLL_S_IEXEC
;
982 if (!(hfi
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
983 mode
|= CRTDLL_S_IWRITE
;
987 buf
->st_size
= hfi
.nFileSizeLow
;
988 RtlTimeToSecondsSince1970( &hfi
.ftLastAccessTime
, &dw
);
990 RtlTimeToSecondsSince1970( &hfi
.ftLastWriteTime
, &dw
);
991 buf
->st_mtime
= buf
->st_ctime
= dw
;
992 TRACE("\n%d %d %d %d %d %d\n", buf
->st_mode
,buf
->st_nlink
,buf
->st_size
,
993 buf
->st_atime
,buf
->st_mtime
, buf
->st_ctime
);
998 /*********************************************************************
1001 * Get current file position.
1003 LONG __cdecl
CRTDLL__tell(INT fd
)
1005 return CRTDLL__lseek(fd
, 0, SEEK_CUR
);
1009 /*********************************************************************
1010 * _tempnam (CRTDLL.305)
1013 LPSTR __cdecl
CRTDLL__tempnam(LPCSTR dir
, LPCSTR prefix
)
1015 char tmpbuf
[MAX_PATH
];
1017 TRACE("dir (%s) prefix (%s)\n",dir
,prefix
);
1018 if (GetTempFileNameA(dir
,prefix
,0,tmpbuf
))
1020 TRACE("got name (%s)\n",tmpbuf
);
1021 return CRTDLL__strdup(tmpbuf
);
1023 TRACE("failed-last error (%ld)\n",GetLastError());
1028 /*********************************************************************
1029 * _umask (CRTDLL.310)
1031 * Set the process-wide umask.
1033 INT __cdecl
CRTDLL__umask(INT umask
)
1035 INT old_umask
= __CRTDLL_umask
;
1036 TRACE("umask (%d)\n",umask
);
1037 __CRTDLL_umask
= umask
;
1042 /*********************************************************************
1043 * _utime (CRTDLL.314)
1045 * Set the file access/modification times on a file.
1047 INT __cdecl
CRTDLL__utime(LPCSTR path
, struct _utimbuf
*t
)
1049 INT fd
= CRTDLL__open( path
, _O_WRONLY
| _O_BINARY
);
1053 INT retVal
= CRTDLL__futime(fd
, t
);
1061 /*********************************************************************
1062 * _unlink (CRTDLL.315)
1066 INT __cdecl
CRTDLL__unlink(LPCSTR path
)
1068 TRACE("path (%s)\n",path
);
1069 if(DeleteFileA( path
))
1072 TRACE("failed-last error (%ld)\n",GetLastError());
1073 __CRTDLL__set_errno(GetLastError());
1078 /*********************************************************************
1079 * _write (CRTDLL.332)
1081 * Write data to a file.
1083 UINT __cdecl
CRTDLL__write(INT fd
, LPCVOID buf
, UINT count
)
1086 HANDLE hand
= __CRTDLL__fdtoh(fd
);
1088 /* Dont trace small writes, it gets *very* annoying */
1090 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd
,hand
,buf
,count
);
1091 if (hand
== INVALID_HANDLE_VALUE
)
1094 /* If appending, go to EOF */
1095 if (__CRTDLL_flags
[fd
] & _IOAPPEND
)
1096 CRTDLL__lseek(fd
, 0, FILE_END
);
1098 /* Set _cnt to 0 so optimised binaries will call our implementation
1099 * of putc/getc. See _filbuf/_flsbuf comments.
1101 if (__CRTDLL_files
[fd
])
1102 __CRTDLL_files
[fd
]->_cnt
= 0;
1104 if (WriteFile(hand
, buf
, count
, &num_written
, NULL
)
1105 && (num_written
== count
))
1108 TRACE(":failed-last error (%ld)\n",GetLastError());
1109 if ( __CRTDLL_files
[fd
])
1110 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
1116 /*********************************************************************
1117 * clearerr (CRTDLL.349)
1119 * Clear a FILE's error indicator.
1121 VOID __cdecl
CRTDLL_clearerr(CRTDLL_FILE
* file
)
1123 TRACE(":file (%p) fd (%d)\n",file
,file
->_file
);
1124 file
->_flag
&= ~(_IOERR
| _IOEOF
);
1128 /*********************************************************************
1129 * fclose (CRTDLL.362)
1131 * Close an open file.
1133 INT __cdecl
CRTDLL_fclose( CRTDLL_FILE
* file
)
1135 return CRTDLL__close(file
->_file
);
1139 /*********************************************************************
1142 * Check the eof indicator on a file.
1144 INT __cdecl
CRTDLL_feof( CRTDLL_FILE
* file
)
1146 return file
->_flag
& _IOEOF
;
1150 /*********************************************************************
1151 * ferror (CRTDLL.361)
1153 * Check the error indicator on a file.
1155 INT __cdecl
CRTDLL_ferror( CRTDLL_FILE
* file
)
1157 return file
->_flag
& _IOERR
;
1161 /*********************************************************************
1162 * fflush (CRTDLL.362)
1164 INT __cdecl
CRTDLL_fflush( CRTDLL_FILE
* file
)
1166 return CRTDLL__commit(file
->_file
);
1170 /*********************************************************************
1171 * fgetc (CRTDLL.363)
1173 INT __cdecl
CRTDLL_fgetc( CRTDLL_FILE
* file
)
1176 if (CRTDLL__read(file
->_file
,&c
,1) != 1)
1182 /*********************************************************************
1183 * fgetpos (CRTDLL.364)
1185 INT __cdecl
CRTDLL_fgetpos( CRTDLL_FILE
* file
, CRTDLL_fpos_t
*pos
)
1187 *pos
= CRTDLL__tell(file
->_file
);
1188 return (*pos
== -1? -1 : 0);
1192 /*********************************************************************
1193 * fgets (CRTDLL.365)
1195 CHAR
* __cdecl
CRTDLL_fgets(LPSTR s
, INT size
, CRTDLL_FILE
* file
)
1198 LPSTR buf_start
= s
;
1200 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1201 file
,file
->_file
,s
,size
);
1203 /* BAD, for the whole WINE process blocks... just done this way to test
1204 * windows95's ftp.exe.
1205 * JG - Is this true now we use ReadFile() on stdin too?
1207 for(cc
= CRTDLL_fgetc(file
); cc
!= EOF
&& cc
!= '\n';
1208 cc
= CRTDLL_fgetc(file
))
1211 if (--size
<= 0) break;
1214 if ((cc
== EOF
) && (s
== buf_start
)) /* If nothing read, return 0*/
1216 TRACE(":nothing read\n");
1223 TRACE(":got '%s'\n", buf_start
);
1228 /*********************************************************************
1229 * fputs (CRTDLL.375)
1231 INT __cdecl
CRTDLL_fputs( LPCSTR s
, CRTDLL_FILE
* file
)
1233 return CRTDLL_fwrite(s
,strlen(s
),1,file
);
1237 /*********************************************************************
1238 * fprintf (CRTDLL.370)
1240 INT __cdecl
CRTDLL_fprintf( CRTDLL_FILE
* file
, LPCSTR format
, ... )
1245 va_start( valist
, format
);
1246 res
= CRTDLL_vfprintf( file
, format
, valist
);
1252 /*********************************************************************
1253 * fopen (CRTDLL.372)
1257 CRTDLL_FILE
* __cdecl
CRTDLL_fopen(LPCSTR path
, LPCSTR mode
)
1260 INT flags
= 0, plus
= 0, fd
;
1261 const char* search
= mode
;
1263 TRACE(":path (%s) mode (%s)\n",path
,mode
);
1266 if (*search
++ == '+')
1269 /* map mode string to open() flags. "man fopen" for possibilities. */
1273 flags
= (plus
? _O_RDWR
: _O_RDONLY
);
1276 flags
= _O_CREAT
| _O_TRUNC
| (plus
? _O_RDWR
: _O_WRONLY
);
1279 flags
= _O_CREAT
| _O_APPEND
| (plus
? _O_RDWR
: _O_WRONLY
);
1294 flags
&= ~_O_BINARY
;
1299 FIXME(":unknown flag %c not supported\n",mode
[-1]);
1302 fd
= CRTDLL__open(path
, flags
);
1307 file
= __CRTDLL__alloc_fp(fd
);
1308 TRACE(":get file (%p)\n",file
);
1316 /*********************************************************************
1317 * fputc (CRTDLL.374)
1319 INT __cdecl
CRTDLL_fputc( INT c
, CRTDLL_FILE
* file
)
1321 return CRTDLL__write(file
->_file
, &c
, 1) == 1? c
: EOF
;
1325 /*********************************************************************
1326 * fread (CRTDLL.377)
1328 DWORD __cdecl
CRTDLL_fread(LPVOID ptr
, INT size
, INT nmemb
, CRTDLL_FILE
* file
)
1330 DWORD read
= CRTDLL__read(file
->_file
,ptr
, size
* nmemb
);
1337 /*********************************************************************
1338 * freopen (CRTDLL.379)
1341 CRTDLL_FILE
* __cdecl
CRTDLL_freopen(LPCSTR path
, LPCSTR mode
,CRTDLL_FILE
* file
)
1343 CRTDLL_FILE
* newfile
;
1346 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path
,mode
,file
,file
->_file
);
1347 if (!file
|| ((fd
= file
->_file
) < 0) || fd
> __CRTDLL_fdend
)
1352 FIXME(":reopen on user file not implemented!\n");
1353 __CRTDLL__set_errno(ERROR_CALL_NOT_IMPLEMENTED
);
1357 /* first, create the new file */
1358 if ((newfile
= CRTDLL_fopen(path
,mode
)) == NULL
)
1361 if (fd
< 3 && SetStdHandle(fd
== 0 ? STD_INPUT_HANDLE
:
1362 (fd
== 1? STD_OUTPUT_HANDLE
: STD_ERROR_HANDLE
),
1363 __CRTDLL_handles
[newfile
->_file
]))
1365 /* Redirecting std handle to file , copy over.. */
1366 __CRTDLL_handles
[fd
] = __CRTDLL_handles
[newfile
->_file
];
1367 __CRTDLL_flags
[fd
] = __CRTDLL_flags
[newfile
->_file
];
1368 memcpy(&__CRTDLL_iob
[fd
], newfile
, sizeof (CRTDLL_FILE
));
1369 __CRTDLL_iob
[fd
]._file
= fd
;
1370 /* And free up the resources allocated by fopen, but
1371 * not the HANDLE we copied. */
1372 CRTDLL_free(__CRTDLL_files
[fd
]);
1373 __CRTDLL__free_fd(newfile
->_file
);
1374 return &__CRTDLL_iob
[fd
];
1377 WARN(":failed-last error (%ld)\n",GetLastError());
1378 CRTDLL_fclose(newfile
);
1379 __CRTDLL__set_errno(GetLastError());
1384 /*********************************************************************
1385 * fsetpos (CRTDLL.380)
1387 INT __cdecl
CRTDLL_fsetpos( CRTDLL_FILE
* file
, CRTDLL_fpos_t
*pos
)
1389 return CRTDLL__lseek(file
->_file
,*pos
,SEEK_SET
);
1393 /*********************************************************************
1394 * fscanf (CRTDLL.381)
1396 INT __cdecl
CRTDLL_fscanf( CRTDLL_FILE
* file
, LPSTR format
, ... )
1401 if (!*format
) return 0;
1402 WARN("%p (\"%s\"): semi-stub\n", file
, format
);
1403 nch
= CRTDLL_fgetc(file
);
1404 va_start(ap
, format
);
1406 if (*format
== ' ') {
1407 /* skip whitespace */
1408 while ((nch
!=EOF
) && isspace(nch
))
1409 nch
= CRTDLL_fgetc(file
);
1411 else if (*format
== '%') {
1415 case 'd': { /* read an integer */
1416 int*val
= va_arg(ap
, int*);
1418 /* skip initial whitespace */
1419 while ((nch
!=EOF
) && isspace(nch
))
1420 nch
= CRTDLL_fgetc(file
);
1421 /* get sign and first digit */
1423 nch
= CRTDLL_fgetc(file
);
1432 nch
= CRTDLL_fgetc(file
);
1433 /* read until no more digits */
1434 while ((nch
!=EOF
) && isdigit(nch
)) {
1435 cur
= cur
*10 + (nch
- '0');
1436 nch
= CRTDLL_fgetc(file
);
1442 case 'f': { /* read a float */
1443 float*val
= va_arg(ap
, float*);
1445 /* skip initial whitespace */
1446 while ((nch
!=EOF
) && isspace(nch
))
1447 nch
= CRTDLL_fgetc(file
);
1448 /* get sign and first digit */
1450 nch
= CRTDLL_fgetc(file
);
1459 /* read until no more digits */
1460 while ((nch
!=EOF
) && isdigit(nch
)) {
1461 cur
= cur
*10 + (nch
- '0');
1462 nch
= CRTDLL_fgetc(file
);
1465 /* handle decimals */
1467 nch
= CRTDLL_fgetc(file
);
1468 while ((nch
!=EOF
) && isdigit(nch
)) {
1470 cur
+= dec
* (nch
- '0');
1471 nch
= CRTDLL_fgetc(file
);
1478 case 's': { /* read a word */
1479 char*str
= va_arg(ap
, char*);
1481 /* skip initial whitespace */
1482 while ((nch
!=EOF
) && isspace(nch
))
1483 nch
= CRTDLL_fgetc(file
);
1484 /* read until whitespace */
1485 while ((nch
!=EOF
) && !isspace(nch
)) {
1486 *sptr
++ = nch
; st
++;
1487 nch
= CRTDLL_fgetc(file
);
1491 TRACE("read word: %s\n", str
);
1494 default: FIXME("unhandled: %%%c\n", *format
);
1500 /* check for character match */
1502 nch
= CRTDLL_fgetc(file
);
1509 WARN("need ungetch\n");
1511 TRACE("returning %d\n", rd
);
1516 /*********************************************************************
1517 * fseek (CRTDLL.382)
1519 LONG __cdecl
CRTDLL_fseek( CRTDLL_FILE
* file
, LONG offset
, INT whence
)
1521 return CRTDLL__lseek(file
->_file
,offset
,whence
);
1525 /*********************************************************************
1526 * ftell (CRTDLL.381)
1528 LONG __cdecl
CRTDLL_ftell( CRTDLL_FILE
* file
)
1530 return CRTDLL__tell(file
->_file
);
1534 /*********************************************************************
1535 * fwrite (CRTDLL.383)
1537 UINT __cdecl
CRTDLL_fwrite( LPCVOID ptr
, INT size
, INT nmemb
, CRTDLL_FILE
* file
)
1539 UINT written
= CRTDLL__write(file
->_file
, ptr
, size
* nmemb
);
1542 return written
/ size
;
1546 /*********************************************************************
1547 * getchar (CRTDLL.386)
1549 INT __cdecl
CRTDLL_getchar( VOID
)
1551 return CRTDLL_fgetc(CRTDLL_stdin
);
1555 /*********************************************************************
1558 INT __cdecl
CRTDLL_getc( CRTDLL_FILE
* file
)
1560 return CRTDLL_fgetc( file
);
1564 /*********************************************************************
1567 LPSTR __cdecl
CRTDLL_gets(LPSTR buf
)
1570 LPSTR buf_start
= buf
;
1572 /* BAD, for the whole WINE process blocks... just done this way to test
1573 * windows95's ftp.exe.
1574 * JG 19/9/00: Is this still true, now we are using ReadFile?
1576 for(cc
= CRTDLL_fgetc(CRTDLL_stdin
); cc
!= EOF
&& cc
!= '\n';
1577 cc
= CRTDLL_fgetc(CRTDLL_stdin
))
1578 if(cc
!= '\r') *buf
++ = (char)cc
;
1582 TRACE("got '%s'\n", buf_start
);
1587 /*********************************************************************
1590 INT __cdecl
CRTDLL_putc( INT c
, CRTDLL_FILE
* file
)
1592 return CRTDLL_fputc( c
, file
);
1596 /*********************************************************************
1597 * putchar (CRTDLL.442)
1599 void __cdecl
CRTDLL_putchar( INT c
)
1601 CRTDLL_fputc(c
, CRTDLL_stdout
);
1605 /*********************************************************************
1608 INT __cdecl
CRTDLL_puts(LPCSTR s
)
1610 return CRTDLL_fputs(s
, CRTDLL_stdout
);
1614 /*********************************************************************
1615 * rewind (CRTDLL.447)
1617 * Set the file pointer to the start of a file and clear any error
1620 VOID __cdecl
CRTDLL_rewind(CRTDLL_FILE
* file
)
1622 TRACE(":file (%p) fd (%d)\n",file
,file
->_file
);
1623 CRTDLL__lseek(file
->_file
,0,SEEK_SET
);
1624 file
->_flag
&= ~(_IOEOF
| _IOERR
);
1628 /*********************************************************************
1629 * remove (CRTDLL.448)
1631 INT __cdecl
CRTDLL_remove(LPCSTR path
)
1633 TRACE(":path (%s)\n",path
);
1634 if (DeleteFileA(path
))
1636 TRACE(":failed-last error (%ld)\n",GetLastError());
1637 __CRTDLL__set_errno(GetLastError());
1642 /*********************************************************************
1643 * rename (CRTDLL.449)
1645 INT __cdecl
CRTDLL_rename(LPCSTR oldpath
,LPCSTR newpath
)
1647 TRACE(":from %s to %s\n",oldpath
,newpath
);
1648 if (MoveFileExA( oldpath
, newpath
, MOVEFILE_REPLACE_EXISTING
))
1650 TRACE(":failed-last error (%ld)\n",GetLastError());
1651 __CRTDLL__set_errno(GetLastError());
1656 /*********************************************************************
1657 * setbuf (CRTDLL.452)
1659 INT __cdecl
CRTDLL_setbuf(CRTDLL_FILE
* file
, LPSTR buf
)
1661 TRACE(":file (%p) fd (%d) buf (%p)\n", file
, file
->_file
,buf
);
1663 WARN(":user buffer will not be used!\n");
1664 /* FIXME: no buffering for now */
1669 /*********************************************************************
1670 * tmpfile (CRTDLL.486)
1672 * Create and return a temporary file.
1674 CRTDLL_FILE
* __cdecl
CRTDLL_tmpfile(void)
1676 LPSTR filename
= CRTDLL_tmpnam(NULL
);
1677 int fd
= CRTDLL__open(filename
, _O_CREAT
| _O_BINARY
|
1678 _O_RDWR
| _O_TEMPORARY
);
1681 return __CRTDLL__alloc_fp(fd
);
1687 /*********************************************************************
1688 * tmpnam (CRTDLL.490)
1690 * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1693 LPSTR __cdecl
CRTDLL_tmpnam(LPSTR s
)
1695 char tmpbuf
[MAX_PATH
];
1696 char* prefix
= "TMP";
1697 if (!GetTempPathA(MAX_PATH
,tmpbuf
) ||
1698 !GetTempFileNameA(tmpbuf
,prefix
,0,CRTDLL_tmpname
))
1700 TRACE(":failed-last error (%ld)\n",GetLastError());
1703 TRACE(":got tmpnam %s\n",CRTDLL_tmpname
);
1709 /*********************************************************************
1710 * vfprintf (CRTDLL.494)
1712 * Write formatted output to a file.
1715 /* we have avoided libc stdio.h so far, lets not start now */
1716 extern int vsprintf(void *, const void *, va_list);
1718 /********************************************************************/
1720 INT __cdecl
CRTDLL_vfprintf( CRTDLL_FILE
* file
, LPCSTR format
, va_list args
)
1722 /* FIXME: We should parse the format string, calculate the maximum,
1723 * length of each arg, malloc a buffer, print to it, and fwrite that.
1724 * Yes this sucks, but not as much as crashing 1/2 way through an
1725 * app writing to a file :-(
1728 TRACE(":file (%p) fd (%d) fmt (%s)\n",file
,file
->_file
,format
);
1730 vsprintf( buffer
, format
, args
);
1731 return CRTDLL_fwrite( buffer
, 1, strlen(buffer
), file
);