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