2 * msvcrt.dll file functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "wine/unicode.h"
32 #include "msvcrt/direct.h"
33 #include "msvcrt/fcntl.h"
34 #include "msvcrt/io.h"
35 #include "msvcrt/stdio.h"
36 #include "msvcrt/stdlib.h"
37 #include "msvcrt/string.h"
38 #include "msvcrt/sys/stat.h"
39 #include "msvcrt/sys/utime.h"
40 #include "msvcrt/time.h"
41 #include "msvcrt/share.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
47 /* for stat mode, permissions apply to all,owner and group */
48 #define MSVCRT_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
49 #define MSVCRT_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
50 #define MSVCRT_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
52 /* _access() bit flags FIXME: incomplete */
53 #define MSVCRT_W_OK 0x02
56 /* FIXME: Make this dynamic */
57 #define MSVCRT_MAX_FILES 257
59 HANDLE MSVCRT_handles[MSVCRT_MAX_FILES];
60 MSVCRT_FILE* MSVCRT_files[MSVCRT_MAX_FILES];
61 int MSVCRT_flags[MSVCRT_MAX_FILES];
62 char *MSVCRT_tempfiles[MSVCRT_MAX_FILES];
63 MSVCRT_FILE MSVCRT__iob[3];
64 #define MSVCRT_stdin (MSVCRT__iob+STDIN_FILENO)
65 #define MSVCRT_stdout (MSVCRT__iob+STDOUT_FILENO)
66 #define MSVCRT_stderr (MSVCRT__iob+STDERR_FILENO)
68 static int MSVCRT_fdstart = 3; /* first unallocated fd */
69 static int MSVCRT_fdend = 3; /* highest allocated fd */
71 /* INTERNAL: process umask */
72 static int MSVCRT_umask = 0;
74 /* INTERNAL: Static buffer for temp file name */
75 static char MSVCRT_tmpname[MAX_PATH];
77 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
78 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
79 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
80 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
82 #define TOUL(x) (ULONGLONG)((WCHAR)L##x)
83 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
84 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
85 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
86 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
88 extern CRITICAL_SECTION MSVCRT_file_cs;
89 #define LOCK_FILES EnterCriticalSection(&MSVCRT_file_cs)
90 #define UNLOCK_FILES LeaveCriticalSection(&MSVCRT_file_cs)
93 /* INTERNAL: Get the HANDLE for a fd */
94 static HANDLE msvcrt_fdtoh(int fd)
96 if (fd < 0 || fd >= MSVCRT_fdend ||
97 MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
99 WARN(":fd (%d) - no handle!\n",fd);
100 SET_THREAD_VAR(doserrno,0);
101 SET_THREAD_VAR(errno,MSVCRT_EBADF);
102 return INVALID_HANDLE_VALUE;
104 return MSVCRT_handles[fd];
107 /* INTERNAL: free a file entry fd */
108 static void msvcrt_free_fd(int fd)
110 MSVCRT_handles[fd] = INVALID_HANDLE_VALUE;
111 MSVCRT_files[fd] = 0;
112 MSVCRT_flags[fd] = 0;
113 TRACE(":fd (%d) freed\n",fd);
115 return; /* dont use 0,1,2 for user files */
116 if (fd == MSVCRT_fdend - 1)
118 if (fd < MSVCRT_fdstart)
122 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
123 static int msvcrt_alloc_fd(HANDLE hand, int flag)
125 int fd = MSVCRT_fdstart;
127 TRACE(":handle (%d) allocating fd (%d)\n",hand,fd);
128 if (fd >= MSVCRT_MAX_FILES)
130 WARN(":files exhausted!\n");
133 MSVCRT_handles[fd] = hand;
134 MSVCRT_flags[fd] = flag;
136 /* locate next free slot */
137 if (fd == MSVCRT_fdend)
138 MSVCRT_fdstart = ++MSVCRT_fdend;
140 while(MSVCRT_fdstart < MSVCRT_fdend &&
141 MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE)
147 /* INTERNAL: Allocate a FILE* for an fd slot
148 * This is done lazily to avoid memory wastage for low level open/write
149 * usage when a FILE* is not requested (but may be later).
151 static MSVCRT_FILE* msvcrt_alloc_fp(int fd)
153 TRACE(":fd (%d) allocating FILE*\n",fd);
154 if (fd < 0 || fd >= MSVCRT_fdend ||
155 MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
157 WARN(":invalid fd %d\n",fd);
158 SET_THREAD_VAR(doserrno,0);
159 SET_THREAD_VAR(errno,MSVCRT_EBADF);
162 if (!MSVCRT_files[fd])
164 if ((MSVCRT_files[fd] = MSVCRT_calloc(sizeof(MSVCRT_FILE),1)))
166 MSVCRT_files[fd]->_file = fd;
167 MSVCRT_files[fd]->_flag = MSVCRT_flags[fd];
168 MSVCRT_files[fd]->_flag &= ~MSVCRT__IOAPPEND; /* mask out, see above */
171 TRACE(":got FILE* (%p)\n",MSVCRT_files[fd]);
172 return MSVCRT_files[fd];
176 /* INTERNAL: Set up stdin, stderr and stdout */
177 void msvcrt_init_io(void)
180 memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
181 MSVCRT_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
182 MSVCRT_flags[0] = MSVCRT__iob[0]._flag = MSVCRT__IOREAD;
183 MSVCRT_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
184 MSVCRT_flags[1] = MSVCRT__iob[1]._flag = MSVCRT__IOWRT;
185 MSVCRT_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
186 MSVCRT_flags[2] = MSVCRT__iob[2]._flag = MSVCRT__IOWRT;
188 TRACE(":handles (%d)(%d)(%d)\n",MSVCRT_handles[0],
189 MSVCRT_handles[1],MSVCRT_handles[2]);
191 for (i = 0; i < 3; i++)
193 /* FILE structs for stdin/out/err are static and never deleted */
194 MSVCRT_files[i] = &MSVCRT__iob[i];
195 MSVCRT__iob[i]._file = i;
196 MSVCRT_tempfiles[i] = NULL;
200 /*********************************************************************
203 MSVCRT_FILE *__p__iob(void)
205 return &MSVCRT__iob[0];
208 /*********************************************************************
211 int _access(const char *filename, int mode)
213 DWORD attr = GetFileAttributesA(filename);
215 TRACE("(%s,%d) %ld\n",filename,mode,attr);
217 if (!filename || attr == 0xffffffff)
219 MSVCRT__set_errno(GetLastError());
222 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
224 MSVCRT__set_errno(ERROR_ACCESS_DENIED);
230 /*********************************************************************
231 * _waccess (MSVCRT.@)
233 int _waccess(const WCHAR *filename, int mode)
235 DWORD attr = GetFileAttributesW(filename);
237 TRACE("(%s,%d) %ld\n",debugstr_w(filename),mode,attr);
239 if (!filename || attr == 0xffffffff)
241 MSVCRT__set_errno(GetLastError());
244 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
246 MSVCRT__set_errno(ERROR_ACCESS_DENIED);
252 /*********************************************************************
255 int _chmod(const char *path, int flags)
257 DWORD oldFlags = GetFileAttributesA(path);
259 if (oldFlags != 0x0FFFFFFFF)
261 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
262 oldFlags | FILE_ATTRIBUTE_READONLY;
264 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
267 MSVCRT__set_errno(GetLastError());
271 /*********************************************************************
274 int _wchmod(const WCHAR *path, int flags)
276 DWORD oldFlags = GetFileAttributesW(path);
278 if (oldFlags != 0x0FFFFFFFF)
280 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
281 oldFlags | FILE_ATTRIBUTE_READONLY;
283 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
286 MSVCRT__set_errno(GetLastError());
290 /*********************************************************************
293 int _unlink(const char *path)
295 TRACE("(%s)\n",path);
296 if(DeleteFileA(path))
298 TRACE("failed (%ld)\n",GetLastError());
299 MSVCRT__set_errno(GetLastError());
303 /*********************************************************************
304 * _wunlink (MSVCRT.@)
306 int _wunlink(const WCHAR *path)
308 TRACE("(%s)\n",debugstr_w(path));
309 if(DeleteFileW(path))
311 TRACE("failed (%ld)\n",GetLastError());
312 MSVCRT__set_errno(GetLastError());
316 /*********************************************************************
321 HANDLE hand = msvcrt_fdtoh(fd);
323 TRACE(":fd (%d) handle (%d)\n",fd,hand);
324 if (hand == INVALID_HANDLE_VALUE)
327 /* Dont free std FILE*'s, they are not dynamic */
328 if (fd > 2 && MSVCRT_files[fd])
329 MSVCRT_free(MSVCRT_files[fd]);
333 if (!CloseHandle(hand))
335 WARN(":failed-last error (%ld)\n",GetLastError());
336 MSVCRT__set_errno(GetLastError());
339 if (MSVCRT_tempfiles[fd])
341 TRACE("deleting temporary file '%s'\n",MSVCRT_tempfiles[fd]);
342 _unlink(MSVCRT_tempfiles[fd]);
343 MSVCRT_free(MSVCRT_tempfiles[fd]);
344 MSVCRT_tempfiles[fd] = NULL;
351 /*********************************************************************
356 HANDLE hand = msvcrt_fdtoh(fd);
358 TRACE(":fd (%d) handle (%d)\n",fd,hand);
359 if (hand == INVALID_HANDLE_VALUE)
362 if (!FlushFileBuffers(hand))
364 if (GetLastError() == ERROR_INVALID_HANDLE)
366 /* FlushFileBuffers fails for console handles
367 * so we ignore this error.
371 TRACE(":failed-last error (%ld)\n",GetLastError());
372 MSVCRT__set_errno(GetLastError());
379 /*********************************************************************
385 HANDLE hand = msvcrt_fdtoh(fd);
387 TRACE(":fd (%d) handle (%d)\n",fd,hand);
389 if (hand == INVALID_HANDLE_VALUE)
392 /* If we have a FILE* for this file, the EOF flag
393 * will be set by the read()/write() functions.
395 if (MSVCRT_files[fd])
396 return MSVCRT_files[fd]->_flag & MSVCRT__IOEOF;
398 /* Otherwise we do it the hard way */
399 curpos = SetFilePointer(hand, 0, NULL, SEEK_CUR);
400 endpos = SetFilePointer(hand, 0, NULL, FILE_END);
402 if (curpos == endpos)
405 SetFilePointer(hand, curpos, 0, FILE_BEGIN);
409 /*********************************************************************
410 * _fcloseall (MSVCRT.@)
414 int num_closed = 0, i;
416 for (i = 3; i < MSVCRT_fdend; i++)
417 if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
423 TRACE(":closed (%d) handles\n",num_closed);
427 /*********************************************************************
430 LONG _lseek(int fd, LONG offset, int whence)
433 HANDLE hand = msvcrt_fdtoh(fd);
435 TRACE(":fd (%d) handle (%d)\n",fd,hand);
436 if (hand == INVALID_HANDLE_VALUE)
439 if (whence < 0 || whence > 2)
441 SET_THREAD_VAR(errno,MSVCRT_EINVAL);
445 TRACE(":fd (%d) to 0x%08lx pos %s\n",
446 fd,offset,(whence==SEEK_SET)?"SEEK_SET":
447 (whence==SEEK_CUR)?"SEEK_CUR":
448 (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
450 if ((ret = SetFilePointer(hand, offset, NULL, whence)) != 0xffffffff)
452 if (MSVCRT_files[fd])
453 MSVCRT_files[fd]->_flag &= ~MSVCRT__IOEOF;
454 /* FIXME: What if we seek _to_ EOF - is EOF set? */
457 TRACE(":error-last error (%ld)\n",GetLastError());
458 if (MSVCRT_files[fd])
459 switch(GetLastError())
461 case ERROR_NEGATIVE_SEEK:
462 case ERROR_SEEK_ON_DEVICE:
463 MSVCRT__set_errno(GetLastError());
464 MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
472 /*********************************************************************
475 void MSVCRT_rewind(MSVCRT_FILE* file)
477 TRACE(":file (%p) fd (%d)\n",file,file->_file);
478 _lseek(file->_file,0,SEEK_SET);
479 file->_flag &= ~(MSVCRT__IOEOF | MSVCRT__IOERR);
482 /*********************************************************************
485 MSVCRT_FILE* _fdopen(int fd, const char *mode)
487 MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
489 TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file);
496 /*********************************************************************
497 * _wfdopen (MSVCRT.@)
499 MSVCRT_FILE* _wfdopen(int fd, const WCHAR *mode)
501 MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
503 TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,debugstr_w(mode),file);
510 /*********************************************************************
511 * _filelength (MSVCRT.@)
513 LONG _filelength(int fd)
515 LONG curPos = _lseek(fd, 0, SEEK_CUR);
518 LONG endPos = _lseek(fd, 0, SEEK_END);
521 if (endPos != curPos)
522 _lseek(fd, curPos, SEEK_SET);
529 /*********************************************************************
532 int _fileno(MSVCRT_FILE* file)
534 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
538 /*********************************************************************
539 * _flushall (MSVCRT.@)
543 int num_flushed = 0, i = 3;
545 while(i < MSVCRT_fdend)
546 if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
548 if (_commit(i) == -1)
550 MSVCRT_files[i]->_flag |= MSVCRT__IOERR;
554 TRACE(":flushed (%d) handles\n",num_flushed);
558 /*********************************************************************
561 int _fstat(int fd, struct _stat* buf)
564 BY_HANDLE_FILE_INFORMATION hfi;
565 HANDLE hand = msvcrt_fdtoh(fd);
567 TRACE(":fd (%d) stat (%p)\n",fd,buf);
568 if (hand == INVALID_HANDLE_VALUE)
573 WARN(":failed-NULL buf\n");
574 MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
578 memset(&hfi, 0, sizeof(hfi));
579 memset(buf, 0, sizeof(struct _stat));
580 if (!GetFileInformationByHandle(hand, &hfi))
582 WARN(":failed-last error (%ld)\n",GetLastError());
583 MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
586 FIXME(":dwFileAttributes = %ld, mode set to 0\n",hfi.dwFileAttributes);
587 buf->st_nlink = hfi.nNumberOfLinks;
588 buf->st_size = hfi.nFileSizeLow;
589 RtlTimeToSecondsSince1970(&hfi.ftLastAccessTime, &dw);
591 RtlTimeToSecondsSince1970(&hfi.ftLastWriteTime, &dw);
592 buf->st_mtime = buf->st_ctime = dw;
596 /*********************************************************************
599 int _futime(int fd, struct _utimbuf *t)
601 HANDLE hand = msvcrt_fdtoh(fd);
606 MSVCRT_time_t currTime;
607 MSVCRT_time(&currTime);
608 RtlSecondsSince1970ToTime(currTime, &at);
609 memcpy(&wt, &at, sizeof(wt));
613 RtlSecondsSince1970ToTime(t->actime, &at);
614 if (t->actime == t->modtime)
615 memcpy(&wt, &at, sizeof(wt));
617 RtlSecondsSince1970ToTime(t->modtime, &wt);
620 if (!SetFileTime(hand, NULL, &at, &wt))
622 MSVCRT__set_errno(GetLastError());
628 /*********************************************************************
629 * _get_osfhandle (MSVCRT.@)
631 long _get_osfhandle(int fd)
633 HANDLE hand = msvcrt_fdtoh(fd);
634 HANDLE newhand = hand;
635 TRACE(":fd (%d) handle (%d)\n",fd,hand);
637 if (hand != INVALID_HANDLE_VALUE)
639 /* FIXME: I'm not convinced that I should be copying the
640 * handle here - it may be leaked if the app doesn't
641 * close it (and the API docs dont say that it should)
642 * Not duplicating it means that it can't be inherited
643 * and so lcc's wedit doesn't cope when it passes it to
644 * child processes. I've an idea that it should either
645 * be copied by CreateProcess, or marked as inheritable
646 * when initialised, or maybe both? JG 21-9-00.
648 DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(),
649 &newhand,0,TRUE,DUPLICATE_SAME_ACCESS);
654 /*********************************************************************
659 HANDLE hand = msvcrt_fdtoh(fd);
661 TRACE(":fd (%d) handle (%d)\n",fd,hand);
662 if (hand == INVALID_HANDLE_VALUE)
665 return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
668 /*********************************************************************
671 char *_mktemp(char *pattern)
674 char *retVal = pattern;
679 numX = (*pattern++ == 'X')? numX + 1 : 0;
683 id = GetCurrentProcessId();
687 int tempNum = id / 10;
688 *pattern-- = id - (tempNum * 10) + '0';
694 if (GetFileAttributesA(retVal) == 0xFFFFFFFF &&
695 GetLastError() == ERROR_FILE_NOT_FOUND)
698 } while(letter != '|');
702 /*********************************************************************
703 * _wmktemp (MSVCRT.@)
705 WCHAR *_wmktemp(WCHAR *pattern)
708 WCHAR *retVal = pattern;
710 WCHAR letter = (WCHAR)L'a';
713 numX = (*pattern++ == (WCHAR)L'X')? numX + 1 : 0;
717 id = GetCurrentProcessId();
721 int tempNum = id / 10;
722 *pattern-- = id - (tempNum * 10) + (WCHAR)L'0';
728 if (GetFileAttributesW(retVal) == 0xFFFFFFFF &&
729 GetLastError() == ERROR_FILE_NOT_FOUND)
732 } while(letter != (WCHAR)L'|');
736 /*********************************************************************
739 int MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
743 DWORD access = 0, creation = 0;
747 SECURITY_ATTRIBUTES sa;
750 TRACE(":file (%s) oflags: 0x%04x shflags: 0x%04x\n",
751 path, oflags, shflags);
753 switch(oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
756 access |= GENERIC_READ;
757 ioflag |= MSVCRT__IOREAD;
760 access |= GENERIC_WRITE;
761 ioflag |= MSVCRT__IOWRT;
764 access |= GENERIC_WRITE | GENERIC_READ;
765 ioflag |= MSVCRT__IORW;
769 if (oflags & _O_CREAT)
771 va_start(ap, shflags);
772 pmode = va_arg(ap, int);
775 FIXME(": pmode 0x%04x ignored\n", pmode);
777 if (oflags & _O_EXCL)
778 creation = CREATE_NEW;
779 else if (oflags & _O_TRUNC)
780 creation = CREATE_ALWAYS;
782 creation = OPEN_ALWAYS;
784 else /* no _O_CREAT */
786 if (oflags & _O_TRUNC)
787 creation = TRUNCATE_EXISTING;
789 creation = OPEN_EXISTING;
791 if (oflags & _O_APPEND)
792 ioflag |= MSVCRT__IOAPPEND;
795 oflags |= _O_BINARY; /* FIXME: Default to text */
797 if (oflags & _O_TEXT)
799 /* Dont warn when writing */
800 if (ioflag & GENERIC_READ)
801 FIXME(":TEXT node not implemented\n");
811 sharing = FILE_SHARE_READ;
814 sharing = FILE_SHARE_WRITE;
817 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
820 ERR( "Unhandled shflags 0x%x\n", shflags );
824 if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL
825 |_O_CREAT|_O_RDWR|_O_TEMPORARY|_O_NOINHERIT))
826 TRACE(":unsupported oflags 0x%04x\n",oflags);
828 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
829 sa.lpSecurityDescriptor = NULL;
830 sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
832 hand = CreateFileA(path, access, sharing,
833 &sa, creation, FILE_ATTRIBUTE_NORMAL, 0);
835 if (hand == INVALID_HANDLE_VALUE) {
836 WARN(":failed-last error (%ld)\n",GetLastError());
837 MSVCRT__set_errno(GetLastError());
841 fd = msvcrt_alloc_fd(hand, ioflag);
843 TRACE(":fd (%d) handle (%d)\n",fd, hand);
847 if (oflags & _O_TEMPORARY)
848 MSVCRT_tempfiles[fd] = _strdup(path);
849 if (ioflag & MSVCRT__IOAPPEND)
850 _lseek(fd, 0, FILE_END);
856 /*********************************************************************
859 int MSVCRT__wsopen( const WCHAR* path, int oflags, int shflags, ... )
861 const unsigned int len = strlenW(path);
862 char *patha = MSVCRT_calloc(len + 1,1);
866 va_start(ap, shflags);
867 pmode = va_arg(ap, int);
870 if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
872 int retval = MSVCRT__sopen(patha,oflags,shflags,pmode);
877 MSVCRT__set_errno(GetLastError());
881 /*********************************************************************
884 int _open( const char *path, int flags, ... )
890 pmode = va_arg(ap, int);
893 return MSVCRT__sopen( path, flags, _SH_DENYNO, pmode );
896 /*********************************************************************
899 int _wopen(const WCHAR *path,int flags,...)
901 const unsigned int len = strlenW(path);
902 char *patha = MSVCRT_calloc(len + 1,1);
907 pmode = va_arg(ap, int);
910 if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
912 int retval = _open(patha,flags,pmode);
917 MSVCRT__set_errno(GetLastError());
921 /*********************************************************************
924 int _creat(const char *path, int flags)
926 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
927 return _open(path, usedFlags);
930 /*********************************************************************
933 int _wcreat(const WCHAR *path, int flags)
935 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
936 return _wopen(path, usedFlags);
939 /*********************************************************************
940 * _open_osfhandle (MSVCRT.@)
942 int _open_osfhandle(long hand, int flags)
944 int fd = msvcrt_alloc_fd(hand,flags);
945 TRACE(":handle (%ld) fd (%d)\n",hand,fd);
949 /*********************************************************************
954 int num_removed = 0, i;
956 for (i = 3; i < MSVCRT_fdend; i++)
957 if (MSVCRT_tempfiles[i])
964 TRACE(":removed (%d) temp files\n",num_removed);
968 /*********************************************************************
971 int _read(int fd, void *buf, unsigned int count)
974 HANDLE hand = msvcrt_fdtoh(fd);
976 /* Dont trace small reads, it gets *very* annoying */
978 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
979 if (hand == INVALID_HANDLE_VALUE)
982 /* Set _cnt to 0 so optimised binaries will call our implementation
983 * of putc/getc. See _filbuf/_flsbuf comments.
985 if (MSVCRT_files[fd])
986 MSVCRT_files[fd]->_cnt = 0;
988 if (ReadFile(hand, buf, count, &num_read, NULL))
990 if (num_read != count && MSVCRT_files[fd])
993 MSVCRT_files[fd]->_flag |= MSVCRT__IOEOF;
997 TRACE(":failed-last error (%ld)\n",GetLastError());
998 if (MSVCRT_files[fd])
999 MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1003 /*********************************************************************
1006 int _getw(MSVCRT_FILE* file)
1009 if (_read(file->_file, &i, sizeof(int)) != 1)
1014 /*********************************************************************
1015 * _setmode (MSVCRT.@)
1017 int _setmode(int fd,int mode)
1020 FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode);
1024 /*********************************************************************
1027 int _stat(const char* path, struct _stat * buf)
1030 WIN32_FILE_ATTRIBUTE_DATA hfi;
1031 unsigned short mode = MSVCRT_S_IREAD;
1034 TRACE(":file (%s) buf(%p)\n",path,buf);
1036 if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
1038 TRACE("failed (%ld)\n",GetLastError());
1039 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1043 memset(buf,0,sizeof(struct _stat));
1045 /* FIXME: rdev isnt drive num,despite what the docs say-what is it?
1046 Bon 011120: This FIXME seems incorrect
1047 Also a letter as first char isn't enough to be classify
1050 if (isalpha(*path)&& (*(path+1)==':'))
1051 buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
1053 buf->st_dev = buf->st_rdev = _getdrive() - 1;
1055 plen = strlen(path);
1057 /* Dir, or regular file? */
1058 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1059 (path[plen-1] == '\\'))
1060 mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1065 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
1067 unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
1068 (tolower(path[plen-3]) << 16);
1069 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
1070 mode |= MSVCRT_S_IEXEC;
1074 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1075 mode |= MSVCRT_S_IWRITE;
1077 buf->st_mode = mode;
1079 buf->st_size = hfi.nFileSizeLow;
1080 RtlTimeToSecondsSince1970(&hfi.ftLastAccessTime, &dw);
1082 RtlTimeToSecondsSince1970(&hfi.ftLastWriteTime, &dw);
1083 buf->st_mtime = buf->st_ctime = dw;
1084 TRACE("\n%d %d %d %ld %ld %ld\n", buf->st_mode,buf->st_nlink,buf->st_size,
1085 buf->st_atime,buf->st_mtime, buf->st_ctime);
1089 /*********************************************************************
1092 int _wstat(const WCHAR* path, struct _stat * buf)
1095 WIN32_FILE_ATTRIBUTE_DATA hfi;
1096 unsigned short mode = MSVCRT_S_IREAD;
1099 TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
1101 if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
1103 TRACE("failed (%ld)\n",GetLastError());
1104 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1108 memset(buf,0,sizeof(struct _stat));
1110 /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
1111 if (MSVCRT_iswalpha(*path))
1112 buf->st_dev = buf->st_rdev = toupperW(*path - (WCHAR)L'A'); /* drive num */
1114 buf->st_dev = buf->st_rdev = _getdrive() - 1;
1116 plen = strlenW(path);
1118 /* Dir, or regular file? */
1119 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1120 (path[plen-1] == (WCHAR)L'\\'))
1121 mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1126 if (plen > 6 && path[plen-4] == (WCHAR)L'.') /* shortest exe: "\x.exe" */
1128 ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
1129 ((ULONGLONG)tolowerW(path[plen-3]) << 32);
1130 if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
1131 mode |= MSVCRT_S_IEXEC;
1135 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1136 mode |= MSVCRT_S_IWRITE;
1138 buf->st_mode = mode;
1140 buf->st_size = hfi.nFileSizeLow;
1141 RtlTimeToSecondsSince1970(&hfi.ftLastAccessTime, &dw);
1143 RtlTimeToSecondsSince1970(&hfi.ftLastWriteTime, &dw);
1144 buf->st_mtime = buf->st_ctime = dw;
1145 TRACE("\n%d %d %d %ld %ld %ld\n", buf->st_mode,buf->st_nlink,buf->st_size,
1146 buf->st_atime,buf->st_mtime, buf->st_ctime);
1150 /*********************************************************************
1155 return _lseek(fd, 0, SEEK_CUR);
1158 /*********************************************************************
1159 * _tempnam (MSVCRT.@)
1161 char *_tempnam(const char *dir, const char *prefix)
1163 char tmpbuf[MAX_PATH];
1165 TRACE("dir (%s) prefix (%s)\n",dir,prefix);
1166 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
1168 TRACE("got name (%s)\n",tmpbuf);
1169 return _strdup(tmpbuf);
1171 TRACE("failed (%ld)\n",GetLastError());
1175 /*********************************************************************
1176 * _wtempnam (MSVCRT.@)
1178 WCHAR *_wtempnam(const WCHAR *dir, const WCHAR *prefix)
1180 WCHAR tmpbuf[MAX_PATH];
1182 TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
1183 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
1185 TRACE("got name (%s)\n",debugstr_w(tmpbuf));
1186 return _wcsdup(tmpbuf);
1188 TRACE("failed (%ld)\n",GetLastError());
1192 /*********************************************************************
1195 int _umask(int umask)
1197 int old_umask = MSVCRT_umask;
1198 TRACE("(%d)\n",umask);
1199 MSVCRT_umask = umask;
1203 /*********************************************************************
1206 int _utime(const char* path, struct _utimbuf *t)
1208 int fd = _open(path, _O_WRONLY | _O_BINARY);
1212 int retVal = _futime(fd, t);
1219 /*********************************************************************
1220 * _wutime (MSVCRT.@)
1222 int _wutime(const WCHAR* path, struct _utimbuf *t)
1224 int fd = _wopen(path, _O_WRONLY | _O_BINARY);
1228 int retVal = _futime(fd, t);
1235 /*********************************************************************
1238 int _write(int fd, const void* buf, unsigned int count)
1241 HANDLE hand = msvcrt_fdtoh(fd);
1243 /* Dont trace small writes, it gets *very* annoying */
1245 // TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
1246 if (hand == INVALID_HANDLE_VALUE)
1249 /* If appending, go to EOF */
1250 if (MSVCRT_flags[fd] & MSVCRT__IOAPPEND)
1251 _lseek(fd, 0, FILE_END);
1253 /* Set _cnt to 0 so optimised binaries will call our implementation
1256 if (MSVCRT_files[fd])
1257 MSVCRT_files[fd]->_cnt = 0;
1259 if (WriteFile(hand, buf, count, &num_written, NULL)
1260 && (num_written == count))
1263 TRACE(":failed-last error (%ld)\n",GetLastError());
1264 if (MSVCRT_files[fd])
1265 MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1270 /*********************************************************************
1273 int _putw(int val, MSVCRT_FILE* file)
1275 return _write(file->_file, &val, sizeof(val)) == 1? val : MSVCRT_EOF;
1278 /*********************************************************************
1279 * clearerr (MSVCRT.@)
1281 void MSVCRT_clearerr(MSVCRT_FILE* file)
1283 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1284 file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
1287 /*********************************************************************
1290 int MSVCRT_fclose(MSVCRT_FILE* file)
1293 r=_close(file->_file);
1294 return ((r==MSVCRT_EOF) || (file->_flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
1297 /*********************************************************************
1300 int MSVCRT_feof(MSVCRT_FILE* file)
1302 return file->_flag & MSVCRT__IOEOF;
1305 /*********************************************************************
1308 int MSVCRT_ferror(MSVCRT_FILE* file)
1310 return file->_flag & MSVCRT__IOERR;
1313 /*********************************************************************
1316 int MSVCRT_fflush(MSVCRT_FILE* file)
1318 return _commit(file->_file);
1321 /*********************************************************************
1324 int MSVCRT_fgetc(MSVCRT_FILE* file)
1327 if (_read(file->_file,&c,1) != 1)
1332 /*********************************************************************
1333 * _fgetchar (MSVCRT.@)
1337 return MSVCRT_fgetc(MSVCRT_stdin);
1340 /*********************************************************************
1341 * _filbuf (MSVCRT.@)
1343 int _filbuf(MSVCRT_FILE* file)
1345 return MSVCRT_fgetc(file);
1348 /*********************************************************************
1349 * fgetpos (MSVCRT.@)
1351 int MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
1353 *pos = _tell(file->_file);
1354 return (*pos == -1? -1 : 0);
1357 /*********************************************************************
1360 char *MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
1363 char * buf_start = s;
1365 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1366 file,file->_file,s,size);
1368 /* BAD, for the whole WINE process blocks... just done this way to test
1369 * windows95's ftp.exe.
1370 * JG - Is this true now we use ReadFile() on stdin too?
1372 for(cc = MSVCRT_fgetc(file); cc != MSVCRT_EOF && cc != '\n';
1373 cc = MSVCRT_fgetc(file))
1376 if (--size <= 0) break;
1379 if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
1381 TRACE(":nothing read\n");
1388 TRACE(":got '%s'\n", buf_start);
1392 /*********************************************************************
1395 MSVCRT_wint_t MSVCRT_fgetwc(MSVCRT_FILE* file)
1398 if (_read(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1403 /*********************************************************************
1406 MSVCRT_wint_t MSVCRT_getwc(MSVCRT_FILE* file)
1408 return MSVCRT_fgetwc(file);
1411 /*********************************************************************
1412 * _fgetwchar (MSVCRT.@)
1414 MSVCRT_wint_t _fgetwchar(void)
1416 return MSVCRT_fgetwc(MSVCRT_stdin);
1419 /*********************************************************************
1420 * getwchar (MSVCRT.@)
1422 MSVCRT_wint_t MSVCRT_getwchar(void)
1424 return _fgetwchar();
1427 /*********************************************************************
1430 MSVCRT_wint_t MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
1432 if (_write(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1437 /*********************************************************************
1438 * _fputwchar (MSVCRT.@)
1440 MSVCRT_wint_t _fputwchar(MSVCRT_wint_t wc)
1442 return MSVCRT_fputwc(wc, MSVCRT_stdout);
1445 /*********************************************************************
1448 MSVCRT_FILE* MSVCRT_fopen(const char *path, const char *mode)
1451 int flags = 0, plus = 0, fd;
1452 const char* search = mode;
1454 TRACE("(%s,%s)\n",path,mode);
1457 if (*search++ == '+')
1460 /* map mode string to open() flags. "man fopen" for possibilities. */
1464 flags = (plus ? _O_RDWR : _O_RDONLY);
1467 flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1470 flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1485 flags &= ~_O_BINARY;
1490 FIXME(":unknown flag %c not supported\n",mode[-1]);
1493 fd = _open(path, flags);
1498 file = msvcrt_alloc_fp(fd);
1499 TRACE(":got (%p)\n",file);
1506 /*********************************************************************
1507 * _wfopen (MSVCRT.@)
1509 MSVCRT_FILE *_wfopen(const WCHAR *path, const WCHAR *mode)
1511 const unsigned int plen = strlenW(path), mlen = strlenW(mode);
1512 char *patha = MSVCRT_calloc(plen + 1, 1);
1513 char *modea = MSVCRT_calloc(mlen + 1, 1);
1515 TRACE("(%s,%s)\n",debugstr_w(path),debugstr_w(mode));
1517 if (patha && modea &&
1518 WideCharToMultiByte(CP_ACP,0,path,plen,patha,plen,NULL,NULL) &&
1519 WideCharToMultiByte(CP_ACP,0,mode,mlen,modea,mlen,NULL,NULL))
1521 MSVCRT_FILE *retval = MSVCRT_fopen(patha,modea);
1527 MSVCRT__set_errno(GetLastError());
1531 /*********************************************************************
1532 * _fsopen (MSVCRT.@)
1534 MSVCRT_FILE* _fsopen(const char *path, const char *mode, int share)
1536 FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share);
1537 return MSVCRT_fopen(path,mode);
1540 /*********************************************************************
1541 * _wfsopen (MSVCRT.@)
1543 MSVCRT_FILE* _wfsopen(const WCHAR *path, const WCHAR *mode, int share)
1545 FIXME(":(%s,%s,%d),ignoring share mode!\n",
1546 debugstr_w(path),debugstr_w(mode),share);
1547 return _wfopen(path,mode);
1550 /*********************************************************************
1553 int MSVCRT_fputc(int c, MSVCRT_FILE* file)
1555 return _write(file->_file, &c, 1) == 1? c : MSVCRT_EOF;
1558 /*********************************************************************
1559 * _flsbuf (MSVCRT.@)
1561 int _flsbuf(int c, MSVCRT_FILE* file)
1563 return MSVCRT_fputc(c,file);
1566 /*********************************************************************
1567 * _fputchar (MSVCRT.@)
1569 int _fputchar(int c)
1571 return MSVCRT_fputc(c, MSVCRT_stdout);
1574 /*********************************************************************
1577 MSVCRT_size_t MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
1579 int read = _read(file->_file,ptr, size * nmemb);
1585 /*********************************************************************
1586 * freopen (MSVCRT.@)
1589 MSVCRT_FILE* MSVCRT_freopen(const char *path, const char *mode,MSVCRT_FILE* file)
1591 MSVCRT_FILE* newfile;
1594 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file);
1595 if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
1600 FIXME(":reopen on user file not implemented!\n");
1601 MSVCRT__set_errno(ERROR_CALL_NOT_IMPLEMENTED);
1605 /* first, create the new file */
1606 if ((newfile = MSVCRT_fopen(path,mode)) == NULL)
1609 if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE :
1610 (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE),
1611 MSVCRT_handles[newfile->_file]))
1613 /* Redirecting std handle to file , copy over.. */
1614 MSVCRT_handles[fd] = MSVCRT_handles[newfile->_file];
1615 MSVCRT_flags[fd] = MSVCRT_flags[newfile->_file];
1616 memcpy(&MSVCRT__iob[fd], newfile, sizeof (MSVCRT_FILE));
1617 MSVCRT__iob[fd]._file = fd;
1618 /* And free up the resources allocated by fopen, but
1619 * not the HANDLE we copied. */
1620 MSVCRT_free(MSVCRT_files[fd]);
1621 msvcrt_free_fd(newfile->_file);
1622 return &MSVCRT__iob[fd];
1625 WARN(":failed-last error (%ld)\n",GetLastError());
1626 MSVCRT_fclose(newfile);
1627 MSVCRT__set_errno(GetLastError());
1631 /*********************************************************************
1632 * fsetpos (MSVCRT.@)
1634 int MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
1636 return _lseek(file->_file,*pos,SEEK_SET);
1639 /* helper function for fscanf. Returns the value of character c in the
1640 * given base, or -1 if the given character is not a digit of the base.
1642 static int char2digit(char c, int base) {
1643 if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0');
1644 if (base<=10) return -1;
1645 if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10);
1646 if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10);
1650 /*********************************************************************
1652 * Implemented based on
1653 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp
1654 * Extended by C. Scott Ananian <cananian@alumni.princeton.edu> to handle
1655 * more types of format spec.
1657 int MSVCRT_fscanf(MSVCRT_FILE* file, const char *format, ...)
1659 /* NOTE: If you extend this function, extend MSVCRT__cscanf in console.c too */
1663 if (!*format) return 0;
1664 WARN("%p (\"%s\"): semi-stub\n", file, format);
1665 nch = MSVCRT_fgetc(file);
1666 va_start(ap, format);
1668 /* a whitespace character in the format string causes scanf to read,
1669 * but not store, all consecutive white-space characters in the input
1670 * up to the next non-white-space character. One white space character
1671 * in the input matches any number (including zero) and combination of
1672 * white-space characters in the input. */
1673 if (isspace(*format)) {
1674 /* skip whitespace */
1675 while ((nch!=MSVCRT_EOF) && isspace(nch))
1676 nch = MSVCRT_fgetc(file);
1678 /* a format specification causes scanf to read and convert characters
1679 * in the input into values of a specified type. The value is assigned
1680 * to an argument in the argument list. Format specifications have
1681 * the form %[*][width][{h | l | I64 | L}]type */
1682 /* FIXME: unimplemented: h/l/I64/L modifiers and some type specs. */
1683 else if (*format == '%') {
1684 int st = 0; int suppress = 0; int width = 0;
1685 int base, number_signed;
1687 /* look for leading asterisk, which means 'suppress assignment of
1693 /* look for width specification */
1694 while (isdigit(*format)) {
1696 width+=*format++ - '0';
1698 if (width==0) width=-1; /* no width spec seen */
1700 case '%': /* read a percent symbol */
1701 if (nch!='%') break;
1702 nch = MSVCRT_fgetc(file);
1705 case 'X': /* hexadecimal integer. */
1706 base = 16; number_signed = 0;
1708 case 'o': /* octal integer */
1709 base = 8; number_signed = 0;
1711 case 'u': /* unsigned decimal integer */
1712 base = 10; number_signed = 0;
1714 case 'd': /* signed decimal integer */
1715 base = 10; number_signed = 1;
1717 case 'i': /* generic integer */
1718 base = 0; number_signed = 1;
1720 /* read an integer */
1721 int*val = suppress ? NULL : va_arg(ap, int*);
1722 int cur = 0; int negative = 0; int seendigit=0;
1723 /* skip initial whitespace */
1724 while ((nch!=MSVCRT_EOF) && isspace(nch))
1725 nch = MSVCRT_fgetc(file);
1727 if (number_signed && (nch == '-' || nch == '+')) {
1728 negative = (nch=='-');
1729 nch = MSVCRT_fgetc(file);
1730 if (width>0) width--;
1732 /* look for leading indication of base */
1733 if (width!=0 && nch == '0') {
1734 nch = MSVCRT_fgetc(file);
1735 if (width>0) width--;
1737 if (width!=0 && (nch=='x' || nch=='X')) {
1741 nch = MSVCRT_fgetc(file);
1742 if (width>0) width--;
1750 /* throw away leading zeros */
1751 while (width!=0 && nch=='0') {
1752 nch = MSVCRT_fgetc(file);
1753 if (width>0) width--;
1756 /* get first digit. Keep working copy negative, as the
1757 * range of negative numbers in two's complement notation
1758 * is one larger than the range of positive numbers. */
1759 if (width!=0 && char2digit(nch, base)!=-1) {
1760 cur = -char2digit(nch, base);
1761 nch = MSVCRT_fgetc(file);
1762 if (width>0) width--;
1765 /* read until no more digits */
1766 while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
1767 cur = cur*base + char2digit(nch, base);
1768 nch = MSVCRT_fgetc(file);
1769 if (width>0) width--;
1772 /* negate parsed number if non-negative */
1773 if (!negative) cur=-cur;
1775 if (!seendigit) break; /* not a valid number */
1777 if (!suppress) *val = cur;
1784 case 'G': { /* read a float */
1785 float*val = suppress ? NULL : va_arg(ap, float*);
1788 /* skip initial whitespace */
1789 while ((nch!=MSVCRT_EOF) && isspace(nch))
1790 nch = MSVCRT_fgetc(file);
1792 if (nch == '-' || nch == '+') {
1793 negative = (nch=='-');
1794 if (width>0) width--;
1795 if (width==0) break;
1796 nch = MSVCRT_fgetc(file);
1798 /* get first digit. */
1799 if (!isdigit(nch)) break;
1800 cur = (nch - '0') * (negative ? -1 : 1);
1801 nch = MSVCRT_fgetc(file);
1802 if (width>0) width--;
1803 /* read until no more digits */
1804 while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
1805 cur = cur*10 + (nch - '0');
1806 nch = MSVCRT_fgetc(file);
1807 if (width>0) width--;
1809 /* handle decimals */
1810 if (width!=0 && nch == '.') {
1812 nch = MSVCRT_fgetc(file);
1813 if (width>0) width--;
1814 while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
1816 cur += dec * (nch - '0');
1817 nch = MSVCRT_fgetc(file);
1818 if (width>0) width--;
1821 /* handle exponent */
1822 if (width!=0 && (nch == 'e' || nch == 'E')) {
1823 int exponent = 0, negexp = 0;
1825 nch = MSVCRT_fgetc(file);
1826 if (width>0) width--;
1827 /* possible sign on the exponent */
1828 if (width!=0 && (nch=='+' || nch=='-')) {
1829 negexp = (nch=='-');
1830 nch = MSVCRT_fgetc(file);
1831 if (width>0) width--;
1833 /* exponent digits */
1834 while (width!=0 && (nch!=MSVCRT_EOF) && isdigit(nch)) {
1836 exponent += (nch - '0');
1837 nch = MSVCRT_fgetc(file);
1838 if (width>0) width--;
1840 /* update 'cur' with this exponent. */
1841 expcnt = negexp ? .1 : 10;
1842 while (exponent!=0) {
1846 expcnt=expcnt*expcnt;
1850 if (!suppress) *val = cur;
1853 case 's': { /* read a word */
1854 char*str = suppress ? NULL : va_arg(ap, char*);
1856 /* skip initial whitespace */
1857 while ((nch!=MSVCRT_EOF) && isspace(nch))
1858 nch = MSVCRT_fgetc(file);
1859 /* read until whitespace */
1860 while (width!=0 && (nch!=MSVCRT_EOF) && !isspace(nch)) {
1861 if (!suppress) *sptr++ = nch;
1863 nch = MSVCRT_fgetc(file);
1864 if (width>0) width--;
1867 if (!suppress) *sptr = 0;
1868 TRACE("read word: %s\n", str);
1871 default: FIXME("unhandled: %%%c\n", *format);
1872 /* From spec: "if a percent sign is followed by a character
1873 * that has no meaning as a format-control character, that
1874 * character and the following characters are treated as
1875 * an ordinary sequence of characters, that is, a sequence
1876 * of characters that must match the input. For example,
1877 * to specify that a percent-sign character is to be input,
1879 * LEAVING AS-IS because we catch bugs better that way. */
1881 if (st && !suppress) rd++;
1884 /* a non-white-space character causes scanf to read, but not store,
1885 * a matching non-white-space character. */
1887 /* check for character match */
1889 nch = MSVCRT_fgetc(file);
1894 if (nch!=MSVCRT_EOF) {
1895 FIXME("need ungetch\n");
1898 TRACE("returning %d\n", rd);
1902 /*********************************************************************
1905 int MSVCRT_fseek(MSVCRT_FILE* file, long offset, int whence)
1907 return _lseek(file->_file,offset,whence);
1910 /*********************************************************************
1913 LONG MSVCRT_ftell(MSVCRT_FILE* file)
1915 return _tell(file->_file);
1918 /*********************************************************************
1921 MSVCRT_size_t MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
1923 int written = _write(file->_file, ptr, size * nmemb);
1926 return written / size;
1929 /*********************************************************************
1932 int MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
1934 return MSVCRT_fwrite(s,strlen(s),1,file) == 1 ? 0 : MSVCRT_EOF;
1937 /*********************************************************************
1940 int MSVCRT_fputws(const WCHAR *s, MSVCRT_FILE* file)
1942 return MSVCRT_fwrite(s,strlenW(s),1,file) == 1 ? 0 : MSVCRT_EOF;
1945 /*********************************************************************
1946 * getchar (MSVCRT.@)
1948 int MSVCRT_getchar(void)
1950 return MSVCRT_fgetc(MSVCRT_stdin);
1953 /*********************************************************************
1956 int MSVCRT_getc(MSVCRT_FILE* file)
1958 return MSVCRT_fgetc(file);
1961 /*********************************************************************
1964 char *MSVCRT_gets(char *buf)
1967 char * buf_start = buf;
1969 /* BAD, for the whole WINE process blocks... just done this way to test
1970 * windows95's ftp.exe.
1971 * JG 19/9/00: Is this still true, now we are using ReadFile?
1973 for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
1974 cc = MSVCRT_fgetc(MSVCRT_stdin))
1975 if(cc != '\r') *buf++ = (char)cc;
1979 TRACE("got '%s'\n", buf_start);
1983 /*********************************************************************
1986 int MSVCRT_putc(int c, MSVCRT_FILE* file)
1988 return MSVCRT_fputc(c, file);
1991 /*********************************************************************
1992 * putchar (MSVCRT.@)
1994 int MSVCRT_putchar(int c)
1996 return MSVCRT_fputc(c, MSVCRT_stdout);
1999 /*********************************************************************
2002 int MSVCRT_puts(const char *s)
2004 int retval = MSVCRT_EOF;
2005 if (MSVCRT_fwrite(s,strlen(s),1,MSVCRT_stdout) == 1)
2006 return MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2010 /*********************************************************************
2013 int _putws(const WCHAR *s)
2015 static const WCHAR nl = (WCHAR)L'\n';
2016 if (MSVCRT_fwrite(s,strlenW(s),1,MSVCRT_stdout) == 1)
2017 return MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2021 /*********************************************************************
2024 int MSVCRT_remove(const char *path)
2026 TRACE("(%s)\n",path);
2027 if (DeleteFileA(path))
2029 TRACE(":failed (%ld)\n",GetLastError());
2030 MSVCRT__set_errno(GetLastError());
2034 /*********************************************************************
2035 * _wremove (MSVCRT.@)
2037 int _wremove(const WCHAR *path)
2039 TRACE("(%s)\n",debugstr_w(path));
2040 if (DeleteFileW(path))
2042 TRACE(":failed (%ld)\n",GetLastError());
2043 MSVCRT__set_errno(GetLastError());
2047 /*********************************************************************
2050 int MSVCRT_scanf(const char *format, ...)
2055 va_start(valist, format);
2056 res = MSVCRT_fscanf(MSVCRT_stdin, format, valist);
2061 /*********************************************************************
2064 int MSVCRT_rename(const char *oldpath,const char *newpath)
2066 TRACE(":from %s to %s\n",oldpath,newpath);
2067 if (MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
2069 TRACE(":failed (%ld)\n",GetLastError());
2070 MSVCRT__set_errno(GetLastError());
2074 /*********************************************************************
2075 * _wrename (MSVCRT.@)
2077 int _wrename(const WCHAR *oldpath,const WCHAR *newpath)
2079 TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
2080 if (MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
2082 TRACE(":failed (%ld)\n",GetLastError());
2083 MSVCRT__set_errno(GetLastError());
2087 /*********************************************************************
2088 * setvbuf (MSVCRT.@)
2090 int MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
2092 FIXME("(%p,%p,%d,%d)stub\n",file, buf, mode, size);
2096 /*********************************************************************
2099 void MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
2101 MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, BUFSIZ);
2104 /*********************************************************************
2107 char *MSVCRT_tmpnam(char *s)
2109 char tmpbuf[MAX_PATH];
2110 char* prefix = "TMP";
2111 if (!GetTempPathA(MAX_PATH,tmpbuf) ||
2112 !GetTempFileNameA(tmpbuf,prefix,0,MSVCRT_tmpname))
2114 TRACE(":failed-last error (%ld)\n",GetLastError());
2117 TRACE(":got tmpnam %s\n",MSVCRT_tmpname);
2122 /*********************************************************************
2123 * tmpfile (MSVCRT.@)
2125 MSVCRT_FILE* MSVCRT_tmpfile(void)
2127 char *filename = MSVCRT_tmpnam(NULL);
2129 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY);
2131 return msvcrt_alloc_fp(fd);
2135 /*********************************************************************
2136 * vfprintf (MSVCRT.@)
2138 int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
2140 char buf[2048], *mem = buf;
2141 int written, resize = sizeof(buf), retval;
2142 /* There are two conventions for vsnprintf failing:
2143 * Return -1 if we truncated, or
2144 * Return the number of bytes that would have been written
2145 * The code below handles both cases
2147 while ((written = vsnprintf(mem, resize, format, valist)) == -1 ||
2150 resize = (written == -1 ? resize * 2 : written + 1);
2153 if (!(mem = (char *)MSVCRT_malloc(resize)))
2156 retval = MSVCRT_fwrite(mem, 1, written, file);
2162 /*********************************************************************
2163 * vfwprintf (MSVCRT.@)
2165 int MSVCRT_vfwprintf(MSVCRT_FILE* file, const WCHAR *format, va_list valist)
2167 WCHAR buf[2048], *mem = buf;
2168 int written, resize = sizeof(buf) / sizeof(WCHAR), retval;
2169 /* See vfprintf comments */
2170 while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
2173 resize = (written == -1 ? resize * 2 : written + sizeof(WCHAR));
2176 if (!(mem = (WCHAR *)MSVCRT_malloc(resize)))
2179 retval = MSVCRT_fwrite(mem, 1, written * sizeof (WCHAR), file);
2185 /*********************************************************************
2186 * vprintf (MSVCRT.@)
2188 int MSVCRT_vprintf(const char *format, va_list valist)
2190 return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
2193 /*********************************************************************
2194 * vwprintf (MSVCRT.@)
2196 int MSVCRT_vwprintf(const WCHAR *format, va_list valist)
2198 return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
2201 /*********************************************************************
2202 * fprintf (MSVCRT.@)
2204 int MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
2208 va_start(valist, format);
2209 res = MSVCRT_vfprintf(file, format, valist);
2214 /*********************************************************************
2215 * fwprintf (MSVCRT.@)
2217 int MSVCRT_fwprintf(MSVCRT_FILE* file, const WCHAR *format, ...)
2221 va_start(valist, format);
2222 res = MSVCRT_vfwprintf(file, format, valist);
2227 /*********************************************************************
2230 int MSVCRT_printf(const char *format, ...)
2234 va_start(valist, format);
2235 res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
2240 /*********************************************************************
2241 * wprintf (MSVCRT.@)
2243 int MSVCRT_wprintf(const WCHAR *format, ...)
2247 va_start(valist, format);
2248 res = MSVCRT_vwprintf(format, valist);