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