From 1db20bfd33f9c1486a1a662c2f78f45d00caf24b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 10 Jan 2001 23:59:25 +0000 Subject: [PATCH] - Migrate CRTDLL to MSVCRT. - Many fixes and a load of new functions. --- DEVELOPERS-HINTS | 2 + Make.rules.in | 1 + configure | 2 + configure.in | 1 + dlls/Makefile.in | 6 + dlls/msvcrt/.cvsignore | 2 + dlls/msvcrt/Makefile.in | 36 + dlls/msvcrt/console.c | 370 ++++++++ dlls/msvcrt/cpp.c | 341 +++++++ dlls/msvcrt/ctype.c | 250 +++++ dlls/msvcrt/data.c | 217 +++++ dlls/msvcrt/dir.c | 780 ++++++++++++++++ dlls/msvcrt/environ.c | 68 ++ dlls/msvcrt/errno.c | 119 +++ dlls/msvcrt/except.c | 147 +++ dlls/msvcrt/exit.c | 181 ++++ dlls/msvcrt/file.c | 1692 ++++++++++++++++++++++++++++++++++ dlls/msvcrt/heap.c | 250 +++++ dlls/msvcrt/locale.c | 528 +++++++++++ dlls/msvcrt/main.c | 173 ++++ dlls/msvcrt/math.c | 729 +++++++++++++++ dlls/msvcrt/mbcs.c | 495 ++++++++++ dlls/msvcrt/misc.c | 85 ++ dlls/msvcrt/ms_errno.h | 42 + dlls/msvcrt/msvcrt.h | 43 + dlls/msvcrt/msvcrt.spec | 767 +++++++++++++++ dlls/msvcrt/process.c | 235 +++++ dlls/msvcrt/string.c | 154 ++++ dlls/msvcrt/thread.c | 34 + dlls/msvcrt/time.c | 99 ++ dlls/msvcrt/wcs.c | 245 +++++ documentation/samples/config | 1 + loader/loadorder.c | 1 + 33 files changed, 8096 insertions(+) create mode 100644 dlls/msvcrt/.cvsignore create mode 100644 dlls/msvcrt/Makefile.in create mode 100644 dlls/msvcrt/console.c create mode 100644 dlls/msvcrt/cpp.c create mode 100644 dlls/msvcrt/ctype.c create mode 100644 dlls/msvcrt/data.c create mode 100644 dlls/msvcrt/dir.c create mode 100644 dlls/msvcrt/environ.c create mode 100644 dlls/msvcrt/errno.c create mode 100644 dlls/msvcrt/except.c create mode 100644 dlls/msvcrt/exit.c create mode 100644 dlls/msvcrt/file.c create mode 100644 dlls/msvcrt/heap.c create mode 100644 dlls/msvcrt/locale.c create mode 100644 dlls/msvcrt/main.c create mode 100644 dlls/msvcrt/math.c create mode 100644 dlls/msvcrt/mbcs.c create mode 100644 dlls/msvcrt/misc.c create mode 100644 dlls/msvcrt/ms_errno.h create mode 100644 dlls/msvcrt/msvcrt.h create mode 100644 dlls/msvcrt/msvcrt.spec create mode 100644 dlls/msvcrt/process.c create mode 100644 dlls/msvcrt/string.c create mode 100644 dlls/msvcrt/thread.c create mode 100644 dlls/msvcrt/time.c create mode 100644 dlls/msvcrt/wcs.c diff --git a/DEVELOPERS-HINTS b/DEVELOPERS-HINTS index c3795576def..c9614c4bc84 100644 --- a/DEVELOPERS-HINTS +++ b/DEVELOPERS-HINTS @@ -45,6 +45,7 @@ Other DLLs: avifil32/ - COM object to play AVI files comctl32/ - common controls commdlg/ - common dialog boxes (both 16 & 32 bit) + crtdll/ - Old C runtime library dplayx/ - DirectX dplayx dsound/ - DirectX dsound imagehlp/ - PE (Portable Executable) Image Helper lib @@ -55,6 +56,7 @@ Other DLLs: msacm/ - audio compression manager (multimedia) (16 bit) msacm32/ - audio compression manager (multimedia) (32 bit) msnet/ + msvcrt/ - C runtime library msvideo/ - 16 bit video manager ole32/ - 32 bit OLE 2.0 librairies oleaut32/ - 32 bit OLE 2.0 automation diff --git a/Make.rules.in b/Make.rules.in index a2f72518a5d..66b5ff999a0 100644 --- a/Make.rules.in +++ b/Make.rules.in @@ -129,6 +129,7 @@ DLLS = \ msacm.drv \ msacm32 \ msnet32 \ + msvcrt \ msvfw32 \ odbc32 \ ole32 \ diff --git a/configure b/configure index d7fe6f9f376..becf9a71b15 100755 --- a/configure +++ b/configure @@ -7000,6 +7000,7 @@ dlls/lzexpand/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msnet32/Makefile +dlls/msvcrt/Makefile dlls/msvideo/Makefile dlls/ntdll/Makefile dlls/odbc32/Makefile @@ -7241,6 +7242,7 @@ dlls/lzexpand/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msnet32/Makefile +dlls/msvcrt/Makefile dlls/msvideo/Makefile dlls/ntdll/Makefile dlls/odbc32/Makefile diff --git a/configure.in b/configure.in index 5108460bfb9..34275482e1c 100644 --- a/configure.in +++ b/configure.in @@ -1200,6 +1200,7 @@ dlls/lzexpand/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msnet32/Makefile +dlls/msvcrt/Makefile dlls/msvideo/Makefile dlls/ntdll/Makefile dlls/odbc32/Makefile diff --git a/dlls/Makefile.in b/dlls/Makefile.in index 381d8a79a89..15daa42e727 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -32,6 +32,7 @@ DLLFILES = \ mpr/libmpr.@LIBEXT@ \ msacm/libmsacm32.@LIBEXT@ \ msnet32/libmsnet32.@LIBEXT@ \ + msvcrt/libmsvcrt.@LIBEXT@ \ msvideo/libmsvfw32.@LIBEXT@ \ ntdll/libntdll.@LIBEXT@ \ odbc32/libodbc32.@LIBEXT@ \ @@ -145,6 +146,7 @@ SUBDIRS = \ mpr \ msacm \ msnet32 \ + msvcrt \ msvideo \ ntdll \ odbc32 \ @@ -283,6 +285,9 @@ libmsacm32.@LIBEXT@ libmsacm.@LIBEXT@: msacm/libmsacm32.@LIBEXT@ libmsnet32.@LIBEXT@: msnet32/libmsnet32.@LIBEXT@ $(RM) $@ && $(LN_S) msnet32/libmsnet32.@LIBEXT@ $@ +libmsvcrt.@LIBEXT@: msvcrt/libmsvcrt.@LIBEXT@ + $(RM) $@ && $(LN_S) msvcrt/libmsvcrt.@LIBEXT@ $@ + libmsvfw32.@LIBEXT@ libmsvideo.@LIBEXT@: msvideo/libmsvfw32.@LIBEXT@ $(RM) $@ && $(LN_S) msvideo/libmsvfw32.@LIBEXT@ $@ @@ -418,6 +423,7 @@ lzexpand/liblz32.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ mpr/libmpr.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ msacm/libmsacm32.@LIBEXT@: libwinmm.@LIBEXT@ libuser32.@LIBEXT@ libadvapi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ msnet32/libmsnet32.@LIBEXT@: libntdll.@LIBEXT@ +msvcrt/libmsvcrt.@LIBEXT@: libkernel32.@LIBEXT@ libntdll.@LIBEXT@ msvideo/libmsvfw32.@LIBEXT@: libwinmm.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ odbc32/libodbc32.@LIBEXT@: libntdll.@LIBEXT@ ole32/libole32.@LIBEXT@: libadvapi32.@LIBEXT@ libuser32.@LIBEXT@ libgdi32.@LIBEXT@ librpcrt4.@LIBEXT@ libkernel32.@LIBEXT@ libntdll.@LIBEXT@ diff --git a/dlls/msvcrt/.cvsignore b/dlls/msvcrt/.cvsignore new file mode 100644 index 00000000000..ac6bca3055c --- /dev/null +++ b/dlls/msvcrt/.cvsignore @@ -0,0 +1,2 @@ +Makefile +msvcrt.spec.c diff --git a/dlls/msvcrt/Makefile.in b/dlls/msvcrt/Makefile.in new file mode 100644 index 00000000000..5eee50b67ae --- /dev/null +++ b/dlls/msvcrt/Makefile.in @@ -0,0 +1,36 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = msvcrt +EXTRALIBS = $(LIBUNICODE) + +LDDLLFLAGS = @LDDLLFLAGS@ +SYMBOLFILE = $(MODULE).tmp.o + +C_SRCS = \ + console.c \ + cpp.c \ + ctype.c \ + data.c \ + dir.c \ + environ.c \ + errno.c \ + except.c \ + exit.c \ + file.c \ + heap.c \ + locale.c \ + main.c \ + math.c \ + mbcs.c \ + misc.c \ + process.c \ + string.c \ + thread.c \ + time.c \ + wcs.c + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/dlls/msvcrt/console.c b/dlls/msvcrt/console.c new file mode 100644 index 00000000000..cd30deade24 --- /dev/null +++ b/dlls/msvcrt/console.c @@ -0,0 +1,370 @@ +/* + * msvcrt.dll console functions + * + * Copyright 2000 Jon Griffiths + * + * Note: init and free don't need MT locking since they are called at DLL + * (de)attachment time, which is syncronised for us + */ +#include "msvcrt.h" +#include "wincon.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* MT */ +extern CRITICAL_SECTION MSVCRT_console_cs; +#define LOCK_CONSOLE EnterCriticalSection(&MSVCRT_console_cs) +#define UNLOCK_CONSOLE LeaveCriticalSection(&MSVCRT_console_cs) + +static HANDLE MSVCRT_console_in = INVALID_HANDLE_VALUE; +static HANDLE MSVCRT_console_out= INVALID_HANDLE_VALUE; +static int __MSVCRT_console_buffer = MSVCRT_EOF; + +/* INTERNAL: Initialise console handles */ +void MSVCRT_init_console(void) +{ + TRACE(":Opening console handles\n"); + + MSVCRT_console_in = GetStdHandle(STD_INPUT_HANDLE); + + /* FIXME: Should be initialised with: + * CreateFileA("CONIN$", GENERIC_READ, FILE_SHARE_READ, + * NULL, OPEN_EXISTING, 0, (HANDLE)NULL); + */ + + MSVCRT_console_out= CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, (HANDLE)NULL); + + if ((MSVCRT_console_in == INVALID_HANDLE_VALUE) || + (MSVCRT_console_out== INVALID_HANDLE_VALUE)) + WARN(":Console handle Initialisation FAILED!\n"); +} + +/* INTERNAL: Free console handles */ +void MSVCRT_free_console(void) +{ + TRACE(":Closing console handles\n"); + CloseHandle(MSVCRT_console_in); + CloseHandle(MSVCRT_console_out); +} + +/********************************************************************* + * _cputs (MSVCRT.@) + */ +int __cdecl MSVCRT__cputs(const char * str) +{ + DWORD count; + int retval = MSVCRT_EOF; + + LOCK_CONSOLE; + if (WriteConsoleA(MSVCRT_console_out, str, strlen(str), &count, NULL) + && count == 1) + retval = 0; + UNLOCK_CONSOLE; + return retval; +} + +/********************************************************************* + * _getch (MSVCRT.@) + */ +int __cdecl MSVCRT__getch(void) +{ + int retval = MSVCRT_EOF; + + LOCK_CONSOLE; + if (__MSVCRT_console_buffer != MSVCRT_EOF) + { + retval = __MSVCRT_console_buffer; + __MSVCRT_console_buffer = MSVCRT_EOF; + } + else + { + INPUT_RECORD ir; + DWORD count; + DWORD mode = 0; + + GetConsoleMode(MSVCRT_console_in, &mode); + if(mode) + SetConsoleMode(MSVCRT_console_in, 0); + + do { + if (ReadConsoleInputA(MSVCRT_console_in, &ir, 1, &count)) + { + /* Only interested in ASCII chars */ + if (ir.EventType == KEY_EVENT && + ir.Event.KeyEvent.bKeyDown && + ir.Event.KeyEvent.uChar.AsciiChar) + { + retval = ir.Event.KeyEvent.uChar.AsciiChar; + break; + } + } + else + break; + } while(1); + if (mode) + SetConsoleMode(MSVCRT_console_in, mode); + } + UNLOCK_CONSOLE; + return retval; +} + +/********************************************************************* + * _putch (MSVCRT.@) + */ +int __cdecl MSVCRT__putch(int c) +{ + int retval = MSVCRT_EOF; + DWORD count; + LOCK_CONSOLE; + if (WriteConsoleA(MSVCRT_console_out, &c, 1, &count, NULL) && count == 1) + retval = c; + UNLOCK_CONSOLE; + return retval; +} + +/********************************************************************* + * _getche (MSVCRT.@) + */ +int __cdecl MSVCRT__getche(void) +{ + int retval; + LOCK_CONSOLE; + retval = MSVCRT__getch(); + if (retval != MSVCRT_EOF) + retval = MSVCRT__putch(retval); + UNLOCK_CONSOLE; + return retval; +} + +/********************************************************************* + * _cgets (MSVCRT.@) + */ +char *__cdecl MSVCRT__cgets(char *str) +{ + char *buf = str + 2; + int c; + str[1] = 0; /* Length */ + /* FIXME: No editing of string supported */ + LOCK_CONSOLE; + do + { + if (str[1] >= str[0] || (str[1]++, c = MSVCRT__getche()) == MSVCRT_EOF || c == '\n') + break; + *buf++ = c & 0xff; + } while (1); + UNLOCK_CONSOLE; + *buf = '\0'; + return str + 2; +} + +/********************************************************************* + * _ungetch (MSVCRT.@) + */ +int __cdecl MSVCRT__ungetch(int c) +{ + int retval = MSVCRT_EOF; + LOCK_CONSOLE; + if (c != MSVCRT_EOF && __MSVCRT_console_buffer == MSVCRT_EOF) + retval = __MSVCRT_console_buffer = c; + UNLOCK_CONSOLE; + return retval; +} + +/********************************************************************* + * _cscanf (MSVCRT.@) + */ +int __cdecl MSVCRT__cscanf( const char * format, ... ) +{ + /* NOTE: If you extend this function, extend MSVCRT_fscanf in file.c too */ + int rd = 0; + int nch; + va_list ap; + if (!*format) return 0; + WARN("\"%s\": semi-stub\n", format); + va_start(ap, format); + LOCK_CONSOLE; + nch = MSVCRT__getch(); + while (*format) { + if (*format == ' ') { + /* skip whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT__getch(); + } + else if (*format == '%') { + int st = 0; + format++; + switch(*format) { + case 'd': { /* read an integer */ + int*val = va_arg(ap, int*); + int cur = 0; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT__getch(); + /* get sign and first digit */ + if (nch == '-') { + nch = MSVCRT__getch(); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + nch = MSVCRT__getch(); + /* read until no more digits */ + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = MSVCRT__getch(); + } + st = 1; + *val = cur; + } + break; + case 'f': { /* read a float */ + float*val = va_arg(ap, float*); + float cur = 0; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT__getch(); + /* get sign and first digit */ + if (nch == '-') { + nch = MSVCRT__getch(); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + /* read until no more digits */ + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = MSVCRT__getch(); + } + if (nch == '.') { + /* handle decimals */ + float dec = 1; + nch = MSVCRT__getch(); + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + dec /= 10; + cur += dec * (nch - '0'); + nch = MSVCRT__getch(); + } + } + st = 1; + *val = cur; + } + break; + case 's': { /* read a word */ + char*str = va_arg(ap, char*); + char*sptr = str; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT__getch(); + /* read until whitespace */ + while ((nch!=MSVCRT_EOF) && !isspace(nch)) { + *sptr++ = nch; st++; + nch = MSVCRT__getch(); + } + /* terminate */ + *sptr = 0; + TRACE("read word: %s\n", str); + } + break; + default: FIXME("unhandled: %%%c\n", *format); + } + if (st) rd++; + else break; + } + else { + /* check for character match */ + if (nch == *format) + nch = MSVCRT__getch(); + else break; + } + format++; + } + if (nch != MSVCRT_EOF) + MSVCRT__ungetch(nch); + UNLOCK_CONSOLE; + va_end(ap); + TRACE("returning %d\n", rd); + return rd; +} + +/********************************************************************* + * _kbhit (MSVCRT.@) + */ +int __cdecl MSVCRT__kbhit(void) +{ + int retval = 0; + + LOCK_CONSOLE; + if (__MSVCRT_console_buffer != MSVCRT_EOF) + retval = 1; + else + { + /* FIXME: There has to be a faster way than this in Win32.. */ + INPUT_RECORD *ir = NULL; + DWORD count = 0, i; + + GetNumberOfConsoleInputEvents(MSVCRT_console_in, &count); + + if (count && (ir = MSVCRT_malloc(count * sizeof(INPUT_RECORD))) && + PeekConsoleInputA(MSVCRT_console_in, ir, count, &count)) + for(i = 0; i < count - 1; i++) + { + if (ir[i].EventType == KEY_EVENT && + ir[i].Event.KeyEvent.bKeyDown && + ir[i].Event.KeyEvent.uChar.AsciiChar) + { + retval = 1; + break; + } + } + if (ir) + MSVCRT_free(ir); + } + UNLOCK_CONSOLE; + return retval; +} + + +extern int snprintf(char *, int, const char *, ...); + +/********************************************************************* + * _cprintf (MSVCRT.@) + */ +int __cdecl MSVCRT__cprintf( const char * format, ... ) +{ + char buf[2048], *mem = buf; + int written, resize = sizeof(buf), retval; + va_list valist; + + va_start( valist, format ); + /* There are two conventions for snprintf failing: + * Return -1 if we truncated, or + * Return the number of bytes that would have been written + * The code below handles both cases + */ + while ((written = snprintf( mem, resize, format, valist )) == -1 || + written > resize) + { + resize = (written == -1 ? resize * 2 : written + 1); + if (mem != buf) + MSVCRT_free (mem); + if (!(mem = (char *)MSVCRT_malloc(resize))) + return MSVCRT_EOF; + va_start( valist, format ); + } + va_end(valist); + LOCK_CONSOLE; + retval = MSVCRT__cputs( mem ); + UNLOCK_CONSOLE; + if (mem != buf) + MSVCRT_free (mem); + return retval; +} diff --git a/dlls/msvcrt/cpp.c b/dlls/msvcrt/cpp.c new file mode 100644 index 00000000000..95fe29d2905 --- /dev/null +++ b/dlls/msvcrt/cpp.c @@ -0,0 +1,341 @@ +/* + * msvcrt.dll C++ objects + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + + +void __cdecl MSVCRT__purecall(void); + +typedef void (__cdecl *v_table_ptr)(); + +static v_table_ptr exception_vtable[2]; +static v_table_ptr bad_typeid_vtable[3]; +static v_table_ptr __non_rtti_object_vtable[3]; +static v_table_ptr bad_cast_vtable[3]; +static v_table_ptr type_info_vtable[1]; + +typedef struct __exception +{ + v_table_ptr *vtable; + const char *name; + int do_free; /* FIXME: take string copy with char* ctor? */ +} exception; + +typedef struct __bad_typeid +{ + exception base; +} bad_typeid; + +typedef struct ____non_rtti_object +{ + bad_typeid base; +} __non_rtti_object; + +typedef struct __bad_cast +{ + exception base; +} bad_cast; + +typedef struct __type_info +{ + v_table_ptr *vtable; + void *data; + char name[1]; +} type_info; + +/****************************************************************** + * ??0exception@@QAE@ABQBD@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_exception_ctor(exception * _this, const char ** name) +{ + TRACE("(%p %s)\n",_this,*name); + _this->vtable = exception_vtable; + _this->name = *name; + TRACE("name = %s\n",_this->name); + _this->do_free = 0; /* FIXME */ +} + +/****************************************************************** + * ??0exception@@QAE@ABV0@@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_exception_copy_ctor(exception * _this, const exception * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + if (_this != rhs) + memcpy (_this, rhs, sizeof (*_this)); + TRACE("name = %s\n",_this->name); +} + +/****************************************************************** + * ??0exception@@QAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT_exception_default_ctor(exception * _this) +{ + TRACE("(%p)\n",_this); + _this->vtable = exception_vtable; + _this->name = ""; + _this->do_free = 0; /* FIXME */ +} + +/****************************************************************** + * ??1exception@@UAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT_exception_dtor(exception * _this) +{ + TRACE("(%p)\n",_this); +} + +/****************************************************************** + * ??4exception@@QAEAAV0@ABV0@@Z (MSVCRT.@) + */ +exception * __cdecl MSVCRT_exception_opequals(exception * _this, const exception * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + memcpy (_this, rhs, sizeof (*_this)); + TRACE("name = %s\n",_this->name); + return _this; +} + +/****************************************************************** + * ??_Eexception@@UAEPAXI@Z (MSVCRT.@) + */ +void * __cdecl MSVCRT_exception__unknown_E(exception * _this, unsigned int arg1) +{ + TRACE("(%p %d)\n",_this,arg1); + MSVCRT__purecall(); + return NULL; +} + +/****************************************************************** + * ??_Gexception@@UAEPAXI@Z (MSVCRT.@) + */ +void * __cdecl MSVCRT_exception__unknown_G(exception * _this, unsigned int arg1) +{ + TRACE("(%p %d)\n",_this,arg1); + MSVCRT__purecall(); + return NULL; +} + +/****************************************************************** + * ?what@exception@@UBEPBDXZ (MSVCRT.@) + */ +const char * __stdcall MSVCRT_exception_what(exception * _this) +{ + TRACE("(%p) returning %s\n",_this,_this->name); + return _this->name; +} + + +/****************************************************************** + * ??0bad_typeid@@QAE@ABV0@@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_typeid_copy_ctor(bad_typeid * _this, const bad_typeid * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + MSVCRT_exception_copy_ctor(&_this->base,&rhs->base); +} + +/****************************************************************** + * ??0bad_typeid@@QAE@PBD@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_typeid_ctor(bad_typeid * _this, const char * name) +{ + TRACE("(%p %s)\n",_this,name); + MSVCRT_exception_ctor(&_this->base, &name); + _this->base.vtable = bad_typeid_vtable; +} + +/****************************************************************** + * ??1bad_typeid@@UAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_typeid_dtor(bad_typeid * _this) +{ + TRACE("(%p)\n",_this); + MSVCRT_exception_dtor(&_this->base); +} + +/****************************************************************** + * ??4bad_typeid@@QAEAAV0@ABV0@@Z (MSVCRT.@) + */ +bad_typeid * __cdecl MSVCRT_bad_typeid_opequals(bad_typeid * _this, const bad_typeid * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + MSVCRT_exception_copy_ctor(&_this->base,&rhs->base); + return _this; +} + +/****************************************************************** + * ??0__non_rtti_object@@QAE@ABV0@@Z (MSVCRT.@) + */ +void __cdecl MSVCRT___non_rtti_object_copy_ctor(__non_rtti_object * _this, + const __non_rtti_object * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + MSVCRT_bad_typeid_copy_ctor(&_this->base,&rhs->base); +} + +/****************************************************************** + * ??0__non_rtti_object@@QAE@PBD@Z (MSVCRT.@) + */ +void __cdecl MSVCRT___non_rtti_object_ctor(__non_rtti_object * _this, + const char * name) +{ + TRACE("(%p %s)\n",_this,name); + MSVCRT_bad_typeid_ctor(&_this->base,name); + _this->base.base.vtable = __non_rtti_object_vtable; +} + +/****************************************************************** + * ??1__non_rtti_object@@UAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT___non_rtti_object_dtor(__non_rtti_object * _this) +{ + TRACE("(%p)\n",_this); + MSVCRT_bad_typeid_dtor(&_this->base); +} + +/****************************************************************** + * ??4__non_rtti_object@@QAEAAV0@ABV0@@Z (MSVCRT.@) + */ +__non_rtti_object * __cdecl MSVCRT___non_rtti_object_opequals(__non_rtti_object * _this, + const __non_rtti_object *rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + memcpy (_this, rhs, sizeof (*_this)); + TRACE("name = %s\n",_this->base.base.name); + return _this; +} + +/****************************************************************** + * ??_E__non_rtti_object@@UAEPAXI@Z (MSVCRT.@) + */ +void * __cdecl MSVCRT___non_rtti_object__unknown_E(__non_rtti_object * _this, unsigned int arg1) +{ + TRACE("(%p %d)\n",_this,arg1); + MSVCRT__purecall(); + return NULL; +} + +/****************************************************************** + * ??_G__non_rtti_object@@UAEPAXI@Z (MSVCRT.@) + */ +void * __cdecl MSVCRT___non_rtti_object__unknown_G(__non_rtti_object * _this, unsigned int arg1) +{ + TRACE("(%p %d)\n",_this,arg1); + MSVCRT__purecall(); + return NULL; +} + +/****************************************************************** + * ??0bad_cast@@QAE@ABQBD@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_cast_ctor(bad_cast * _this, const char ** name) +{ + TRACE("(%p %s)\n",_this,*name); + MSVCRT_exception_ctor(&_this->base, name); + _this->base.vtable = bad_cast_vtable; +} + +/****************************************************************** + * ??0bad_cast@@QAE@ABV0@@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_cast_copy_ctor(bad_cast * _this, const bad_cast * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + MSVCRT_exception_copy_ctor(&_this->base,&rhs->base); +} + +/****************************************************************** + * ??1bad_cast@@UAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT_bad_cast_dtor(bad_cast * _this) +{ + TRACE("(%p)\n",_this); + MSVCRT_exception_dtor(&_this->base); +} + +/****************************************************************** + * ??4bad_cast@@QAEAAV0@ABV0@@Z (MSVCRT.@) + */ +bad_cast * __cdecl MSVCRT_bad_cast_opequals(bad_cast * _this, const bad_cast * rhs) +{ + TRACE("(%p %p)\n",_this,rhs); + MSVCRT_exception_copy_ctor(&_this->base,&rhs->base); + return _this; +} + +/****************************************************************** + * ??8type_info@@QBEHABV0@@Z (MSVCRT.@) + */ +int __stdcall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs) +{ + TRACE("(%p %p) returning %d\n",_this,rhs,_this->name == rhs->name); + return _this->name == rhs->name; +} + +/****************************************************************** + * ??9type_info@@QBEHABV0@@Z (MSVCRT.@) + */ +int __stdcall MSVCRT_type_info_opnot_equals(type_info * _this, const type_info * rhs) +{ + TRACE("(%p %p) returning %d\n",_this,rhs,_this->name == rhs->name); + return _this->name != rhs->name; +} + +/****************************************************************** + * ??1type_info@@UAE@XZ (MSVCRT.@) + */ +void __cdecl MSVCRT_type_info_dtor(type_info * _this) +{ + TRACE("(%p)\n",_this); + if (_this->data) + MSVCRT_free(_this->data); +} + +/****************************************************************** + * ?name@type_info@@QBEPBDXZ (MSVCRT.@) + */ +const char * __stdcall MSVCRT_type_info_name(type_info * _this) +{ + TRACE("(%p) returning %s\n",_this,_this->name); + return _this->name; +} + +/****************************************************************** + * ?raw_name@type_info@@QBEPBDXZ (MSVCRT.@) + */ +const char * __stdcall MSVCRT_type_info_raw_name(type_info * _this) +{ + TRACE("(%p) returning %s\n",_this,_this->name); + return _this->name; +} + + +/* INTERNAL: Set up vtables + * FIXME:should be static, cope with versions? + */ +void MSVCRT_init_vtables(void) +{ + exception_vtable[0] = MSVCRT_exception_dtor; + exception_vtable[1] = (void*)MSVCRT_exception_what; + + bad_typeid_vtable[0] = MSVCRT_bad_typeid_dtor; + bad_typeid_vtable[1] = exception_vtable[1]; + bad_typeid_vtable[2] = MSVCRT__purecall; /* FIXME */ + + __non_rtti_object_vtable[0] = MSVCRT___non_rtti_object_dtor; + __non_rtti_object_vtable[1] = bad_typeid_vtable[1]; + __non_rtti_object_vtable[2] = bad_typeid_vtable[2]; + + bad_cast_vtable[0] = MSVCRT_bad_cast_dtor; + bad_cast_vtable[1] = exception_vtable[1]; + bad_cast_vtable[2] = MSVCRT__purecall; /* FIXME */ + + type_info_vtable[0] = MSVCRT_type_info_dtor; + +} + diff --git a/dlls/msvcrt/ctype.c b/dlls/msvcrt/ctype.c new file mode 100644 index 00000000000..a41fd1dbc6f --- /dev/null +++ b/dlls/msvcrt/ctype.c @@ -0,0 +1,250 @@ +/* + * msvcrt.dll ctype functions + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* ASCII char classification table - binary compatible */ +#define MSVCRT_UPPER C1_UPPER +#define MSVCRT_LOWER C1_LOWER +#define MSVCRT_DIGIT C1_DIGIT +#define MSVCRT_SPACE C1_SPACE +#define MSVCRT_PUNCT C1_PUNCT +#define MSVCRT_CONTROL C1_CNTRL +#define MSVCRT_BLANK C1_BLANK +#define MSVCRT_HEX C1_XDIGIT +#define MSVCRT_LEADBYTE 0x8000 +#define MSVCRT_ALPHA (C1_ALPHA|MSVCRT_UPPER|MSVCRT_LOWER) + +#define _C_ MSVCRT_CONTROL +#define _S_ MSVCRT_SPACE +#define _P_ MSVCRT_PUNCT +#define _D_ MSVCRT_DIGIT +#define _H_ MSVCRT_HEX +#define _U_ MSVCRT_UPPER +#define _L_ MSVCRT_LOWER + +WORD MSVCRT__ctype [257] = { + 0, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|_C_, _S_|_C_, + _S_|_C_, _S_|_C_, _S_|_C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, + _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _C_, _S_|MSVCRT_BLANK, + _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, + _P_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, _D_|_H_, + _D_|_H_, _D_|_H_, _D_|_H_, _P_, _P_, _P_, _P_, _P_, _P_, _P_, _U_|_H_, + _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_|_H_, _U_, _U_, _U_, _U_, _U_, + _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, _U_, + _U_, _P_, _P_, _P_, _P_, _P_, _P_, _L_|_H_, _L_|_H_, _L_|_H_, _L_|_H_, + _L_|_H_, _L_|_H_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, + _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _L_, _P_, _P_, _P_, _P_, + _C_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Internal: Current ctype table for locale */ +WORD MSVCRT_current_ctype[257]; + +/* pctype is used by macros in the Win32 headers. It must point + * To a table of flags exactly like ctype. To allow locale + * changes to affect ctypes (i.e. isleadbyte), we use a second table + * and update its flags whenever the current locale changes. + */ +WORD* MSVCRT__pctype = MSVCRT_current_ctype + 1; + +/* mbctype data */ +extern int MSVCRT___mb_cur_max; +extern LCID MSVCRT_current_lc_all_lcid; + +/********************************************************************* + * MSVCRT___p__pctype (MSVCRT.@) + */ +WORD** MSVCRT___p__pctype(void) +{ + return &MSVCRT__pctype; +} + +/********************************************************************* + * _isctype (MSVCRT.@) + */ +int __cdecl MSVCRT__isctype(int c, int type) +{ + if (c >= -1 && c <= 255) + return MSVCRT__pctype[c] & type; + + if (MSVCRT___mb_cur_max != 1 && c > 0) + { + /* FIXME: Is there a faster way to do this? */ + WORD typeInfo; + char convert[3], *pconv = convert; + + if (MSVCRT__pctype[(UINT)c >> 8] & MSVCRT_LEADBYTE) + *pconv++ = (UINT)c >> 8; + *pconv++ = c & 0xff; + *pconv = 0; + /* FIXME: Use ctype LCID, not lc_all */ + if (GetStringTypeExA(MSVCRT_current_lc_all_lcid, CT_CTYPE1, + convert, convert[1] ? 2 : 1, &typeInfo)) + return typeInfo & type; + } + return 0; +} + +/********************************************************************* + * isalnum (MSVCRT.@) + */ +int __cdecl MSVCRT_isalnum(int c) +{ + return MSVCRT__isctype( c,MSVCRT_ALPHA | MSVCRT_DIGIT ); +} + +/********************************************************************* + * isalpha (MSVCRT.@) + */ +int __cdecl MSVCRT_isalpha(int c) +{ + return MSVCRT__isctype( c, MSVCRT_ALPHA ); +} + +/********************************************************************* + * iscntrl (MSVCRT.@) + */ +int __cdecl MSVCRT_iscntrl(int c) +{ + return MSVCRT__isctype( c, MSVCRT_CONTROL ); +} + +/********************************************************************* + * isdigit (MSVCRT.@) + */ +int __cdecl MSVCRT_isdigit(int c) +{ + return MSVCRT__isctype( c, MSVCRT_DIGIT ); +} + +/********************************************************************* + * isgraph (MSVCRT.@) + */ +int __cdecl MSVCRT_isgraph(int c) +{ + return MSVCRT__isctype( c, MSVCRT_ALPHA | MSVCRT_DIGIT | MSVCRT_PUNCT ); +} + +/********************************************************************* + * isleadbyte (MSVCRT.@) + */ +int __cdecl MSVCRT_isleadbyte(int c) +{ + return MSVCRT__isctype( c, MSVCRT_LEADBYTE ); +} + +/********************************************************************* + * islower (MSVCRT.@) + */ +int __cdecl MSVCRT_islower(int c) +{ + return MSVCRT__isctype( c, MSVCRT_LOWER ); +} + +/********************************************************************* + * isprint (MSVCRT.@) + */ +int __cdecl MSVCRT_isprint(int c) +{ + return MSVCRT__isctype( c, MSVCRT_ALPHA | MSVCRT_DIGIT | + MSVCRT_BLANK | MSVCRT_PUNCT ); +} + +/********************************************************************* + * ispunct (MSVCRT.@) + */ +int __cdecl MSVCRT_ispunct(int c) +{ + return MSVCRT__isctype( c, MSVCRT_PUNCT ); +} + +/********************************************************************* + * isspace (MSVCRT.@) + */ +int __cdecl MSVCRT_isspace(int c) +{ + return MSVCRT__isctype( c, MSVCRT_SPACE ); +} + +/********************************************************************* + * isupper (MSVCRT.@) + */ +int __cdecl MSVCRT_isupper(int c) +{ + return MSVCRT__isctype( c, MSVCRT_UPPER ); +} + +/********************************************************************* + * isxdigit (MSVCRT.@) + */ +int __cdecl MSVCRT_isxdigit(int c) +{ + return MSVCRT__isctype( c, MSVCRT_HEX ); +} + +/********************************************************************* + * __isascii (MSVCRT.@) + */ +int __cdecl MSVCRT___isascii(int c) +{ + return isascii((unsigned)c); +} + +/********************************************************************* + * __toascii (MSVCRT.@) + */ +int __cdecl MSVCRT___toascii(int c) +{ + return (unsigned)c & 0x7f; +} + +/********************************************************************* + * iswascii (MSVCRT.@) + * + */ +int __cdecl MSVCRT_iswascii(WCHAR c) +{ + return ((unsigned)c < 0x80); +} + +/********************************************************************* + * __iscsym (MSVCRT.@) + */ +int __cdecl MSVCRT___iscsym(int c) +{ + return (c < 127 && (isalnum(c) || c == '_')); +} + +/********************************************************************* + * __iscsymf (MSVCRT.@) + */ +int __cdecl MSVCRT___iscsymf(int c) +{ + return (c < 127 && (isalpha(c) || c == '_')); +} + +/********************************************************************* + * _toupper (MSVCRT.@) + */ +int __cdecl MSVCRT__toupper(int c) +{ + return toupper(c); +} + +/********************************************************************* + * _tolower (MSVCRT.@) + */ +int __cdecl MSVCRT__tolower(int c) +{ + return tolower(c); +} diff --git a/dlls/msvcrt/data.c b/dlls/msvcrt/data.c new file mode 100644 index 00000000000..3885d977f4f --- /dev/null +++ b/dlls/msvcrt/data.c @@ -0,0 +1,217 @@ +/* + * msvcrt.dll dll data items + * + * Copyright 2000 Jon Griffiths + */ +#include +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +unsigned int MSVCRT___argc; +unsigned int MSVCRT_basemajor;/* FIXME: */ +unsigned int MSVCRT_baseminor;/* FIXME: */ +unsigned int MSVCRT_baseversion; /* FIXME: */ +unsigned int MSVCRT__commode; +unsigned int MSVCRT__fmode; +unsigned int MSVCRT_osmajor;/* FIXME: */ +unsigned int MSVCRT_osminor;/* FIXME: */ +unsigned int MSVCRT_osmode;/* FIXME: */ +unsigned int MSVCRT__osver; +unsigned int MSVCRT_osversion; /* FIXME: */ +unsigned int MSVCRT__winmajor; +unsigned int MSVCRT__winminor; +unsigned int MSVCRT__winver; +unsigned int MSVCRT__sys_nerr; +unsigned int MSVCRT___setlc_active; +unsigned int MSVCRT___unguarded_readlc_active; +double MSVCRT__HUGE; +char **MSVCRT___argv; +WCHAR **MSVCRT___wargv; +char *MSVCRT__acmdln; +WCHAR *MSVCRT__wcmdln; +char *MSVCRT__environ; +WCHAR *MSVCRT__wenviron; +char **MSVCRT___initenv; +WCHAR **MSVCRT___winitenv; +int MSVCRT_timezone; +int MSVCRT_app_type; + +typedef void (__cdecl *MSVCRT__INITTERMFUN)(void); + +char * __cdecl MSVCRT__strdup(const char *); + +/* Data access functions */ +#define GET_UINT_PTR(x) unsigned int __cdecl *MSVCRT___p_##x(void) { return &MSVCRT_##x; } +GET_UINT_PTR(__argc) +GET_UINT_PTR(_commode) +GET_UINT_PTR(_fmode) +GET_UINT_PTR(_osver) +GET_UINT_PTR(_winmajor) +GET_UINT_PTR(_winminor) +GET_UINT_PTR(_winver) +char **__cdecl MSVCRT___p__acmdln(void) { return &MSVCRT__acmdln; } +WCHAR **__cdecl MSVCRT___p__wcmdln(void) { return &MSVCRT__wcmdln; } +char ***__cdecl MSVCRT___p___argv(void) { return &MSVCRT___argv; } +WCHAR ***__cdecl MSVCRT___p___wargv(void) { return &MSVCRT___wargv; } +char **__cdecl MSVCRT___p__environ(void) { return &MSVCRT__environ; } +WCHAR **__cdecl MSVCRT___p__wenviron(void) { return &MSVCRT__wenviron; } +char ***__cdecl MSVCRT___p___initenv(void) { return &MSVCRT___initenv; } +WCHAR ***__cdecl MSVCRT___p___winitenv(void) { return &MSVCRT___winitenv; } +int *__cdecl MSVCRT___p__timezone(void) { return &MSVCRT_timezone; } + +/* INTERNAL: Create a wide string from an ascii string */ +static WCHAR *wstrdupa(const char *str) +{ + const size_t len = strlen(str) + 1 ; + WCHAR *wstr = MSVCRT_malloc(len* sizeof (WCHAR)); + if (!wstr) + return NULL; + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len*sizeof(char),wstr,len* sizeof (WCHAR)); + return wstr; +} + +/* INTERNAL: Since we can't rely on Winelib startup code calling w/getmainargs, + * we initialise data values during DLL loading. The when called by a native + * program we simply return the data we've already initialised. This also means + * you can call multiple times without leaking + */ +void MSVCRT_init_args(void) +{ + char *cmdline, **xargv = NULL; + WCHAR *wcmdline, **wxargv = NULL; + int xargc,end,last_arg,afterlastspace; + DWORD version; + + MSVCRT__acmdln = cmdline = MSVCRT__strdup( GetCommandLineA() ); + MSVCRT__wcmdln = wcmdline = wstrdupa(cmdline); + TRACE("got '%s', wide = '%s'\n", cmdline, debugstr_w(wcmdline)); + + version = GetVersion(); + MSVCRT__osver = version >> 16; + MSVCRT__winminor = version & 0xFF; + MSVCRT__winmajor = (version>>8) & 0xFF; + MSVCRT_baseversion = version >> 16; + MSVCRT__winver = ((version >> 8) & 0xFF) + ((version & 0xFF) << 8); + MSVCRT_baseminor = (version >> 16) & 0xFF; + MSVCRT_basemajor = (version >> 24) & 0xFF; + MSVCRT_osversion = version & 0xFFFF; + MSVCRT_osminor = version & 0xFF; + MSVCRT_osmajor = (version>>8) & 0xFF; + MSVCRT__sys_nerr = 43; + MSVCRT__HUGE = HUGE_VAL; + MSVCRT___setlc_active = 0; + MSVCRT___unguarded_readlc_active = 0; + MSVCRT_timezone = 0; + + /* FIXME: set app type for Winelib apps */ + + end = last_arg = xargc = afterlastspace = 0; + while (1) + { + if ((cmdline[end]==' ') || (cmdline[end]=='\0')) + { + if (cmdline[end]=='\0') + last_arg=1; + else + cmdline[end]='\0'; + /* alloc xargc + NULL entry */ + xargv=(char**)HeapReAlloc( GetProcessHeap(), 0, xargv, + sizeof(char*)*(xargc+1)); + wxargv=(WCHAR**)HeapReAlloc( GetProcessHeap(), 0, wxargv, + sizeof(WCHAR*)*(xargc+1)); + + if (strlen(cmdline+afterlastspace)) + { + xargv[xargc] = MSVCRT__strdup(cmdline+afterlastspace); + wxargv[xargc] = wstrdupa(xargv[xargc]); + xargc++; + if (!last_arg) /* need to seek to the next arg ? */ + { + end++; + while (cmdline[end]==' ') + end++; + } + afterlastspace=end; + } + else + { + xargv[xargc] = NULL; + wxargv[xargc] = NULL; /* the last entry is NULL */ + break; + } + } + else + end++; + } + MSVCRT___argc = xargc; + MSVCRT___argv = xargv; + MSVCRT___wargv = wxargv; + + TRACE("found %d arguments\n",MSVCRT___argc); + MSVCRT__environ = GetEnvironmentStringsA(); + MSVCRT___initenv = &MSVCRT__environ; + MSVCRT__wenviron = GetEnvironmentStringsW(); + MSVCRT___winitenv = &MSVCRT__wenviron; +} + + +/* INTERNAL: free memory used by args */ +void MSVCRT_free_args(void) +{ + /* FIXME */ +} + +/********************************************************************* + * __getmainargs (MSVCRT.@) + */ +char** __cdecl MSVCRT___getmainargs(DWORD *argc,char ***argv,char **environ,DWORD flag) +{ + TRACE("(%p,%p,%p,%ld).\n",argc,argv,environ,flag); + *argc = MSVCRT___argc; + *argv = MSVCRT___argv; + *environ = MSVCRT__environ; + return environ; +} + +/********************************************************************* + * __wgetmainargs (MSVCRT.@) + */ +WCHAR** __cdecl MSVCRT___wgetmainargs(DWORD *argc,WCHAR ***wargv,WCHAR **wenviron,DWORD flag) +{ + TRACE("(%p,%p,%p,%ld).\n",argc,wargv,wenviron,flag); + *argc = MSVCRT___argc; + *wargv = MSVCRT___wargv; + *wenviron = MSVCRT__wenviron; + return wenviron; +} + +/********************************************************************* + * _initterm (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__initterm(MSVCRT__INITTERMFUN *start,MSVCRT__INITTERMFUN *end) +{ + MSVCRT__INITTERMFUN*current = start; + + TRACE("(%p,%p)\n",start,end); + while (current +#include "ntddk.h" +#include "wine/unicode.h" +#include "msvcrt.h" +#include "ms_errno.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +typedef struct MSVCRT_finddata_t +{ + unsigned attrib; + time_t time_create; /* -1 when N/A */ + time_t time_access; /* -1 when N/A */ + time_t time_write; + unsigned long size; /* FIXME: 64 bit ??*/ + char name[MAX_PATH]; +} MSVCRT_finddata_t; + +typedef struct MSVCRT_wfinddata_t +{ + unsigned attrib; + time_t time_create; /* -1 when N/A */ + time_t time_access; /* -1 when N/A */ + time_t time_write; + unsigned long size; /* FIXME: 64 bit ??*/ + WCHAR name[MAX_PATH]; +} MSVCRT_wfinddata_t; + +typedef struct __MSVCRT_diskfree_t { + unsigned num_clusters; + unsigned available; + unsigned cluster_sectors; + unsigned sector_bytes; +} MSVCRT_diskfree_t; + +/* INTERNAL: Translate finddata_t to PWIN32_FIND_DATAA */ +static void MSVCRT__fttofd(LPWIN32_FIND_DATAA fd, MSVCRT_finddata_t* ft) +{ + DWORD dw; + + if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL) + ft->attrib = 0; + else + ft->attrib = fd->dwFileAttributes; + + RtlTimeToSecondsSince1970( &fd->ftCreationTime, &dw ); + ft->time_create = dw; + RtlTimeToSecondsSince1970( &fd->ftLastAccessTime, &dw ); + ft->time_access = dw; + RtlTimeToSecondsSince1970( &fd->ftLastWriteTime, &dw ); + ft->time_write = dw; + ft->size = fd->nFileSizeLow; + strcpy(ft->name, fd->cFileName); +} + +/* INTERNAL: Translate wfinddata_t to PWIN32_FIND_DATAA */ +static void MSVCRT__wfttofd(LPWIN32_FIND_DATAW fd, MSVCRT_wfinddata_t* ft) +{ + DWORD dw; + + if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL) + ft->attrib = 0; + else + ft->attrib = fd->dwFileAttributes; + + RtlTimeToSecondsSince1970( &fd->ftCreationTime, &dw ); + ft->time_create = dw; + RtlTimeToSecondsSince1970( &fd->ftLastAccessTime, &dw ); + ft->time_access = dw; + RtlTimeToSecondsSince1970( &fd->ftLastWriteTime, &dw ); + ft->time_write = dw; + ft->size = fd->nFileSizeLow; + strcpyW(ft->name, fd->cFileName); +} + +char * MSVCRT__strndup(const char *, unsigned int); +LPWSTR __cdecl MSVCRT__wcsdup( LPCWSTR ); +LPWSTR __cdecl MSVCRT__wstrndup( LPCWSTR , unsigned int ); +char *__cdecl MSVCRT_getenv(const char *); + +/********************************************************************* + * _chdir (MSVCRT.@) + */ +int __cdecl MSVCRT__chdir(const char * newdir) +{ + if (!SetCurrentDirectoryA(newdir)) + { + MSVCRT__set_errno(newdir?GetLastError():0); + return -1; + } + return 0; +} + +/********************************************************************* + * _wchdir (MSVCRT.@) + */ +int __cdecl MSVCRT__wchdir(const WCHAR * newdir) +{ + if (!SetCurrentDirectoryW(newdir)) + { + MSVCRT__set_errno(newdir?GetLastError():0); + return -1; + } + return 0; +} + +/********************************************************************* + * _chdrive (MSVCRT.@) + */ +int __cdecl MSVCRT__chdrive(int newdrive) +{ + char buffer[3] = "A:"; + buffer[0] += newdrive - 1; + if (!SetCurrentDirectoryA( buffer )) + { + MSVCRT__set_errno(GetLastError()); + if (newdrive <= 0) + SET_THREAD_VAR(errno,MSVCRT_EACCES); + return -1; + } + return 0; +} + +/********************************************************************* + * _findclose (MSVCRT.@) + */ +int __cdecl MSVCRT__findclose(DWORD hand) +{ + TRACE(":handle %ld\n",hand); + if (!FindClose((HANDLE)hand)) + { + MSVCRT__set_errno(GetLastError()); + return -1; + } + return 0; +} + +/********************************************************************* + * _findfirst (MSVCRT.@) + */ +DWORD __cdecl MSVCRT__findfirst(const char * fspec, MSVCRT_finddata_t* ft) +{ + WIN32_FIND_DATAA find_data; + HANDLE hfind; + + hfind = FindFirstFileA(fspec, &find_data); + if (hfind == INVALID_HANDLE_VALUE) + { + MSVCRT__set_errno(GetLastError()); + return -1; + } + MSVCRT__fttofd(&find_data,ft); + TRACE(":got handle %d\n",hfind); + return hfind; +} + +/********************************************************************* + * _wfindfirst (MSVCRT.@) + */ +DWORD __cdecl MSVCRT__wfindfirst(const WCHAR * fspec, MSVCRT_wfinddata_t* ft) +{ + WIN32_FIND_DATAW find_data; + HANDLE hfind; + + hfind = FindFirstFileW(fspec, &find_data); + if (hfind == INVALID_HANDLE_VALUE) + { + MSVCRT__set_errno(GetLastError()); + return -1; + } + MSVCRT__wfttofd(&find_data,ft); + TRACE(":got handle %d\n",hfind); + return hfind; +} + +/********************************************************************* + * _findnext (MSVCRT.@) + */ +int __cdecl MSVCRT__findnext(DWORD hand, MSVCRT_finddata_t * ft) +{ + WIN32_FIND_DATAA find_data; + + if (!FindNextFileA(hand, &find_data)) + { + SET_THREAD_VAR(errno,MSVCRT_ENOENT); + return -1; + } + + MSVCRT__fttofd(&find_data,ft); + return 0; +} + +/********************************************************************* + * _wfindnext (MSVCRT.@) + */ +int __cdecl MSVCRT__wfindnext(DWORD hand, MSVCRT_wfinddata_t * ft) +{ + WIN32_FIND_DATAW find_data; + + if (!FindNextFileW(hand, &find_data)) + { + SET_THREAD_VAR(errno,MSVCRT_ENOENT); + return -1; + } + + MSVCRT__wfttofd(&find_data,ft); + return 0; +} + +/********************************************************************* + * _getcwd (MSVCRT.@) + */ +char* __cdecl MSVCRT__getcwd(char * buf, int size) +{ + char dir[_MAX_PATH]; + int dir_len = GetCurrentDirectoryA(MAX_PATH,dir); + + if (dir_len < 1) + return NULL; /* FIXME: Real return value untested */ + + if (!buf) + { + if (size < 0) + return MSVCRT__strdup(dir); + return MSVCRT__strndup(dir,size); + } + if (dir_len >= size) + { + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return NULL; /* buf too small */ + } + strcpy(buf,dir); + return buf; +} + +/********************************************************************* + * _wgetcwd (MSVCRT.@) + */ +WCHAR* __cdecl MSVCRT__wgetcwd(WCHAR * buf, int size) +{ + WCHAR dir[_MAX_PATH]; + int dir_len = GetCurrentDirectoryW(MAX_PATH,dir); + + if (dir_len < 1) + return NULL; /* FIXME: Real return value untested */ + + if (!buf) + { + if (size < 0) + return MSVCRT__wcsdup(dir); + return MSVCRT__wstrndup(dir,size); + } + if (dir_len >= size) + { + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return NULL; /* buf too small */ + } + strcpyW(buf,dir); + return buf; +} + +/********************************************************************* + * _getdrive (MSVCRT.@) + */ +int __cdecl MSVCRT__getdrive(void) +{ + char buffer[MAX_PATH]; + if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0; + if (buffer[1] != ':') return 0; + return toupper(buffer[0]) - 'A' + 1; +} + +/********************************************************************* + * _getdcwd (MSVCRT.@) + */ +char* __cdecl MSVCRT__getdcwd(int drive, char * buf, int size) +{ + static char* dummy; + + TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size); + + if (!drive || drive == MSVCRT__getdrive()) + return MSVCRT__getcwd(buf,size); /* current */ + else + { + char dir[_MAX_PATH]; + char drivespec[4] = {'A', ':', '\\', 0}; + int dir_len; + + drivespec[0] += drive - 1; + if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE) + { + SET_THREAD_VAR(errno,MSVCRT_EACCES); + return NULL; + } + + dir_len = GetFullPathNameA(drivespec,_MAX_PATH,dir,&dummy); + if (dir_len >= size || dir_len < 1) + { + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return NULL; /* buf too small */ + } + + TRACE(":returning '%s'\n", dir); + if (!buf) + return MSVCRT__strdup(dir); /* allocate */ + + strcpy(buf,dir); + } + return buf; +} + +/********************************************************************* + * _wgetdcwd (MSVCRT.@) + */ +WCHAR* __cdecl MSVCRT__wgetdcwd(int drive, WCHAR * buf, int size) +{ + static WCHAR* dummy; + + TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size); + + if (!drive || drive == MSVCRT__getdrive()) + return MSVCRT__wgetcwd(buf,size); /* current */ + else + { + WCHAR dir[_MAX_PATH]; + WCHAR drivespec[4] = {'A', ':', '\\', 0}; + int dir_len; + + drivespec[0] += drive - 1; + if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE) + { + SET_THREAD_VAR(errno,MSVCRT_EACCES); + return NULL; + } + + dir_len = GetFullPathNameW(drivespec,_MAX_PATH,dir,&dummy); + if (dir_len >= size || dir_len < 1) + { + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return NULL; /* buf too small */ + } + + TRACE(":returning '%s'\n", debugstr_w(dir)); + if (!buf) + return MSVCRT__wcsdup(dir); /* allocate */ + strcpyW(buf,dir); + } + return buf; +} + +/********************************************************************* + * _getdiskfree (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__getdiskfree(unsigned int disk, MSVCRT_diskfree_t* d) +{ + char drivespec[4] = {'@', ':', '\\', 0}; + DWORD ret[4]; + unsigned int err; + + if (disk > 26) + return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */ + + drivespec[0] += disk; /* make a drive letter */ + + if (GetDiskFreeSpaceA(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3)) + { + d->cluster_sectors = (unsigned)ret[0]; + d->sector_bytes = (unsigned)ret[1]; + d->available = (unsigned)ret[2]; + d->num_clusters = (unsigned)ret[3]; + return 0; + } + err = GetLastError(); + MSVCRT__set_errno(err); + return err; +} + +/********************************************************************* + * _mkdir (MSVCRT.@) + */ +int __cdecl MSVCRT__mkdir(const char * newdir) +{ + if (CreateDirectoryA(newdir,NULL)) + return 0; + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _wmkdir (MSVCRT.@) + */ +int __cdecl MSVCRT__wmkdir(const WCHAR* newdir) +{ + if (CreateDirectoryW(newdir,NULL)) + return 0; + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _rmdir (MSVCRT.@) + */ +int __cdecl MSVCRT__rmdir(const char * dir) +{ + if (RemoveDirectoryA(dir)) + return 0; + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _wrmdir (MSVCRT.@) + */ +int __cdecl MSVCRT__wrmdir(const WCHAR * dir) +{ + if (RemoveDirectoryW(dir)) + return 0; + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _splitpath (MSVCRT.@) + */ +void __cdecl MSVCRT__splitpath(const char* inpath, char * drv, char * dir, + char* fname, char * ext ) +{ + /* Modified PD code from 'snippets' collection. */ + char ch, *ptr, *p; + char pathbuff[MAX_PATH],*path=pathbuff; + + TRACE(":splitting path '%s'\n",path); + strcpy(pathbuff, inpath); + + /* convert slashes to backslashes for searching */ + for (ptr = (char*)path; *ptr; ++ptr) + if ('/' == *ptr) + *ptr = '\\'; + + /* look for drive spec */ + if ('\0' != (ptr = strchr(path, ':'))) + { + ++ptr; + if (drv) + { + strncpy(drv, path, ptr - path); + drv[ptr - path] = '\0'; + } + path = ptr; + } + else if (drv) + *drv = '\0'; + + /* find rightmost backslash or leftmost colon */ + if (NULL == (ptr = strrchr(path, '\\'))) + ptr = (strchr(path, ':')); + + if (!ptr) + { + ptr = (char *)path; /* no path */ + if (dir) + *dir = '\0'; + } + else + { + ++ptr; /* skip the delimiter */ + if (dir) + { + ch = *ptr; + *ptr = '\0'; + strcpy(dir, path); + *ptr = ch; + } + } + + if (NULL == (p = strrchr(ptr, '.'))) + { + if (fname) + strcpy(fname, ptr); + if (ext) + *ext = '\0'; + } + else + { + *p = '\0'; + if (fname) + strcpy(fname, ptr); + *p = '.'; + if (ext) + strcpy(ext, p); + } + + /* Fix pathological case - Win returns ':' as part of the + * directory when no drive letter is given. + */ + if (drv && drv[0] == ':') + { + *drv = '\0'; + if (dir) + { + pathbuff[0] = ':'; + pathbuff[1] = '\0'; + strcat(pathbuff,dir); + strcpy(dir,pathbuff); + } + } +} + +/* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */ +static void fln_fix(char *path) +{ + int dir_flag = 0, root_flag = 0; + char *r, *p, *q, *s; + + /* Skip drive */ + if (NULL == (r = strrchr(path, ':'))) + r = path; + else + ++r; + + /* Ignore leading slashes */ + while ('\\' == *r) + if ('\\' == r[1]) + strcpy(r, &r[1]); + else + { + root_flag = 1; + ++r; + } + + p = r; /* Change "\\" to "\" */ + while (NULL != (p = strchr(p, '\\'))) + if ('\\' == p[1]) + strcpy(p, &p[1]); + else + ++p; + + while ('.' == *r) /* Scrunch leading ".\" */ + { + if ('.' == r[1]) + { + /* Ignore leading ".." */ + for (p = (r += 2); *p && (*p != '\\'); ++p) + ; + } + else + { + for (p = r + 1 ;*p && (*p != '\\'); ++p) + ; + } + strcpy(r, p + ((*p) ? 1 : 0)); + } + + while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */ + { + dir_flag = 1; + path[strlen(path)-1] = '\0'; + } + + s = r; + + /* Look for "\." in path */ + + while (NULL != (p = strstr(s, "\\."))) + { + if ('.' == p[2]) + { + /* Execute this section if ".." found */ + q = p - 1; + while (q > r) /* Backup one level */ + { + if (*q == '\\') + break; + --q; + } + if (q > r) + { + strcpy(q, p + 3); + s = q; + } + else if ('.' != *q) + { + strcpy(q + ((*q == '\\') ? 1 : 0), + p + 3 + ((*(p + 3)) ? 1 : 0)); + s = q; + } + else s = ++p; + } + else + { + /* Execute this section if "." found */ + q = p + 2; + for ( ;*q && (*q != '\\'); ++q) + ; + strcpy (p, q); + } + } + + if (root_flag) /* Embedded ".." could have bubbled up to root */ + { + for (p = r; *p && ('.' == *p || '\\' == *p); ++p) + ; + if (r != p) + strcpy(r, p); + } + + if (dir_flag) + strcat(path, "\\"); +} + +/********************************************************************* + * _fullpath (MSVCRT.@) + */ +LPSTR __cdecl MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size) +{ + char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH]; + char res[MAX_PATH]; + size_t len; + + res[0] = '\0'; + + if (!relPath || !*relPath) + return MSVCRT__getcwd(absPath, size); + + if (size < 4) + { + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return NULL; + } + + TRACE(":resolving relative path '%s'\n",relPath); + + MSVCRT__splitpath(relPath, drive, dir, file, ext); + + /* Get Directory and drive into 'res' */ + if (!dir[0] || (dir[0] != '/' && dir[0] != '\\')) + { + /* Relative or no directory given */ + MSVCRT__getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH); + strcat(res,"\\"); + if (dir[0]) + strcat(res,dir); + if (drive[0]) + res[0] = drive[0]; /* If given a drive, preserve the letter case */ + } + else + { + strcpy(res,drive); + strcat(res,dir); + } + + strcat(res,"\\"); + strcat(res, file); + strcat(res, ext); + fln_fix(res); + + len = strlen(res); + if (len >= MAX_PATH || len >= (size_t)size) + return NULL; /* FIXME: errno? */ + + if (!absPath) + return MSVCRT__strdup(res); + strcpy(absPath,res); + return absPath; +} + +/********************************************************************* + * _makepath (MSVCRT.@) + */ +VOID __cdecl MSVCRT__makepath(char * path, const char * drive, + const char *directory, const char * filename, + const char * extension ) +{ + char ch; + TRACE("MSVCRT__makepath got %s %s %s %s\n", drive, directory, + filename, extension); + + if ( !path ) + return; + + path[0] = 0; + if (drive && drive[0]) + { + path[0] = drive[0]; + path[1] = ':'; + path[2] = 0; + } + if (directory && directory[0]) + { + strcat(path, directory); + ch = path[strlen(path)-1]; + if (ch != '/' && ch != '\\') + strcat(path,"\\"); + } + if (filename && filename[0]) + { + strcat(path, filename); + if (extension && extension[0]) + { + if ( extension[0] != '.' ) + strcat(path,"."); + strcat(path,extension); + } + } + + TRACE("MSVCRT__makepath returns %s\n",path); +} + + +/********************************************************************* + * _searchenv (MSVCRT.@) + */ +void __cdecl MSVCRT__searchenv(const char* file, const char* env, char *buf) +{ + char*envVal, *penv; + char curPath[MAX_PATH]; + + *buf = '\0'; + + /* Try CWD first */ + if (GetFileAttributesA( file ) != 0xFFFFFFFF) + { + GetFullPathNameA( file, MAX_PATH, buf, NULL ); + /* Sigh. This error is *always* set, regardless of success */ + MSVCRT__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + + /* Search given environment variable */ + envVal = MSVCRT_getenv(env); + if (!envVal) + { + MSVCRT__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + + penv = envVal; + TRACE(":searching for %s in paths %s\n", file, envVal); + + do + { + LPSTR end = penv; + + while(*end && *end != ';') end++; /* Find end of next path */ + if (penv == end || !*penv) + { + MSVCRT__set_errno(ERROR_FILE_NOT_FOUND); + return; + } + strncpy(curPath, penv, end - penv); + if (curPath[end - penv] != '/' || curPath[end - penv] != '\\') + { + curPath[end - penv] = '\\'; + curPath[end - penv + 1] = '\0'; + } + else + curPath[end - penv] = '\0'; + + strcat(curPath, file); + TRACE("Checking for file %s\n", curPath); + if (GetFileAttributesA( curPath ) != 0xFFFFFFFF) + { + strcpy(buf, curPath); + MSVCRT__set_errno(ERROR_FILE_NOT_FOUND); + return; /* Found */ + } + penv = *end ? end + 1 : end; + } while(1); +} + diff --git a/dlls/msvcrt/environ.c b/dlls/msvcrt/environ.c new file mode 100644 index 00000000000..6351bb3fabb --- /dev/null +++ b/dlls/msvcrt/environ.c @@ -0,0 +1,68 @@ +/* + * msvcrt.dll environment functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + */ +#include "wine/unicode.h" +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +LPWSTR __cdecl wcsrchr( LPWSTR str, WCHAR ch ); + +/********************************************************************* + * getenv (MSVCRT.@) + */ +char *__cdecl MSVCRT_getenv(const char *name) +{ + LPSTR environ = GetEnvironmentStringsA(); + LPSTR pp,pos = NULL; + unsigned int length; + + for (pp = environ; (*pp); pp = pp + strlen(pp) +1) + { + pos =strchr(pp,'='); + if (pos) + length = pos -pp; + else + length = strlen(pp); + if (!strncmp(pp,name,length)) break; + } + if ((pp)&& (pos)) + { + pp = pos+1; + TRACE("got %s\n",pp); + } + FreeEnvironmentStringsA( environ ); + return pp; +} + +/********************************************************************* + * _wgetenv (MSVCRT.@) + */ +WCHAR *__cdecl MSVCRT__wgetenv(const WCHAR *name) +{ + WCHAR* environ = GetEnvironmentStringsW(); + WCHAR* pp,*pos = NULL; + unsigned int length; + + for (pp = environ; (*pp); pp = pp + strlenW(pp) + 1) + { + pos =wcsrchr(pp,'='); + if (pos) + length = pos -pp; + else + length = strlenW(pp); + if (!strncmpW(pp,name,length)) break; + } + if ((pp)&& (pos)) + { + pp = pos+1; + TRACE("got %s\n",debugstr_w(pp)); + } + FreeEnvironmentStringsW( environ ); + return pp; +} diff --git a/dlls/msvcrt/errno.c b/dlls/msvcrt/errno.c new file mode 100644 index 00000000000..46fd73fc4b2 --- /dev/null +++ b/dlls/msvcrt/errno.c @@ -0,0 +1,119 @@ +/* + * msvcrt.dll errno functions + * + * Copyright 2000 Jon Griffiths + */ + +#include "msvcrt.h" +#include "ms_errno.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + + +/* INTERNAL: Set the crt and dos errno's from the OS error given. */ +void MSVCRT__set_errno(int err) +{ + int *errno = GET_THREAD_VAR_PTR(errno); + int *doserrno = GET_THREAD_VAR_PTR(doserrno); + + *doserrno = err; + + switch(err) + { +#define ERR_CASE(oserr) case oserr: +#define ERR_MAPS(oserr,crterr) case oserr:*errno = crterr;break; + ERR_CASE(ERROR_ACCESS_DENIED) + ERR_CASE(ERROR_NETWORK_ACCESS_DENIED) + ERR_CASE(ERROR_CANNOT_MAKE) + ERR_CASE(ERROR_SEEK_ON_DEVICE) + ERR_CASE(ERROR_LOCK_FAILED) + ERR_CASE(ERROR_FAIL_I24) + ERR_CASE(ERROR_CURRENT_DIRECTORY) + ERR_CASE(ERROR_DRIVE_LOCKED) + ERR_CASE(ERROR_NOT_LOCKED) + ERR_CASE(ERROR_INVALID_ACCESS) + ERR_MAPS(ERROR_LOCK_VIOLATION, MSVCRT_EACCES); + ERR_CASE(ERROR_FILE_NOT_FOUND) + ERR_CASE(ERROR_NO_MORE_FILES) + ERR_CASE(ERROR_BAD_PATHNAME) + ERR_CASE(ERROR_BAD_NETPATH) + ERR_CASE(ERROR_INVALID_DRIVE) + ERR_CASE(ERROR_BAD_NET_NAME) + ERR_CASE(ERROR_FILENAME_EXCED_RANGE) + ERR_MAPS(ERROR_PATH_NOT_FOUND, MSVCRT_ENOENT); + ERR_MAPS(ERROR_IO_DEVICE, MSVCRT_EIO); + ERR_MAPS(ERROR_BAD_FORMAT, MSVCRT_ENOEXEC); + ERR_MAPS(ERROR_INVALID_HANDLE, MSVCRT_EBADF); + ERR_CASE(ERROR_OUTOFMEMORY) + ERR_CASE(ERROR_INVALID_BLOCK) + ERR_CASE(ERROR_NOT_ENOUGH_QUOTA); + ERR_MAPS(ERROR_ARENA_TRASHED, MSVCRT_ENOMEM); + ERR_MAPS(ERROR_BUSY, MSVCRT_EBUSY); + ERR_CASE(ERROR_ALREADY_EXISTS) + ERR_MAPS(ERROR_FILE_EXISTS, MSVCRT_EEXIST); + ERR_MAPS(ERROR_BAD_DEVICE, MSVCRT_ENODEV); + ERR_MAPS(ERROR_TOO_MANY_OPEN_FILES, MSVCRT_EMFILE); + ERR_MAPS(ERROR_DISK_FULL, MSVCRT_ENOSPC); + ERR_MAPS(ERROR_BROKEN_PIPE, MSVCRT_EPIPE); + ERR_MAPS(ERROR_POSSIBLE_DEADLOCK, MSVCRT_EDEADLK); + ERR_MAPS(ERROR_DIR_NOT_EMPTY, MSVCRT_ENOTEMPTY); + ERR_MAPS(ERROR_BAD_ENVIRONMENT, MSVCRT_E2BIG); + ERR_CASE(ERROR_WAIT_NO_CHILDREN) + ERR_MAPS(ERROR_CHILD_NOT_COMPLETE, MSVCRT_ECHILD); + ERR_CASE(ERROR_NO_PROC_SLOTS) + ERR_CASE(ERROR_MAX_THRDS_REACHED) + ERR_MAPS(ERROR_NESTING_NOT_ALLOWED, MSVCRT_EAGAIN); + default: + /* Remaining cases map to EINVAL */ + /* FIXME: may be missing some errors above */ + *errno = MSVCRT_EINVAL; + } +} + +/********************************************************************* + * _errno (MSVCRT.@) + */ +LPINT __cdecl MSVCRT__errno( VOID ) +{ + return GET_THREAD_VAR_PTR(errno); +} + +/********************************************************************* + * __doserrno (MSVCRT.@) + */ +LPINT __cdecl MSVCRT___doserrno( VOID ) +{ + return GET_THREAD_VAR_PTR(doserrno); +} + +char *strerror(int); + +/********************************************************************* + * strerror (MSVCRT.@) + */ +char * __cdecl MSVCRT_strerror (int err) +{ + return strerror(err); /* FIXME */ +} + +/********************************************************************** + * _strerror (MSVCRT.@) + */ +extern int sprintf(char *str, const char *format, ...); + +LPSTR __cdecl MSVCRT__strerror (LPCSTR err) +{ + static char strerrbuff[256]; /* FIXME: Per thread, nprintf */ + sprintf(strerrbuff,"%s: %s\n",err,MSVCRT_strerror(GET_THREAD_VAR(errno))); + return strerrbuff; +} + +int __cdecl MSVCRT__cprintf( const char * format, ... ); + +/********************************************************************* + * perror (MSVCRT.@) + */ +void __cdecl MSVCRT_perror (const char *str) +{ + MSVCRT__cprintf("%s: %s\n",str,MSVCRT_strerror(GET_THREAD_VAR(errno))); +} diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c new file mode 100644 index 00000000000..51ff3d19642 --- /dev/null +++ b/dlls/msvcrt/except.c @@ -0,0 +1,147 @@ +/* + * msvcrt.dll exception handling + * + * Copyright 2000 Jon Griffiths + * + * See http://www.microsoft.com/msj/0197/exception/exception.htm, + * but don't believe all of it. + * + * FIXME: Incomplete, no support for nested exceptions or try block cleanup. + */ +#include +#include "ntddk.h" +#include "thread.h" +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +typedef void (*MSVCRT_sig_handler_func)(void); + +/* VC++ extensions to Win32 SEH */ +typedef struct _SCOPETABLE +{ + DWORD previousTryLevel; + int (__cdecl *lpfnFilter)(int, PEXCEPTION_POINTERS); + int (__cdecl *lpfnHandler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, + PCONTEXT, PEXCEPTION_FRAME *); +} SCOPETABLE, *PSCOPETABLE; + +typedef struct _MSVCRT_EXCEPTION_REGISTRATION +{ + struct _EXCEPTION_REGISTRATION *prev; + void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, + PCONTEXT, PEXCEPTION_RECORD); + PSCOPETABLE scopetable; + int trylevel; + int _ebp; + PEXCEPTION_POINTERS xpointers; +} MSVCRT_EXCEPTION_REGISTRATION; + +typedef struct _EXCEPTION_REGISTRATION +{ + struct _EXCEPTION_REGISTRATION *prev; + void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, + PCONTEXT, PEXCEPTION_RECORD); +} EXCEPTION_REGISTRATION; + +/********************************************************************* + * _EH_prolog (MSVCRT.@) + */ +void __cdecl MSVCRT__EH_prolog(void) +{ + FIXME("stub\n"); +} + +/********************************************************************* + * _XcptFilter (MSVCRT.@) + */ +int __cdecl MSVCRT__XcptFilter(int ex, PEXCEPTION_POINTERS ptr) +{ + FIXME("(%d,%p)semi-stub\n", ex, ptr); + return UnhandledExceptionFilter(ptr); +} + +/******************************************************************* + * _global_unwind2 (MSVCRT.@) + */ +void __cdecl MSVCRT__global_unwind2(PEXCEPTION_FRAME frame) +{ +#if defined(__GNUC__) && defined(__i386__) + TRACE("(%p)\n",frame); + if (0) +unwind_label: return; + RtlUnwind( frame, &&unwind_label, 0, 0 ); +#else + FIXME("(%p) stub\n",frame); +#endif +} + +/******************************************************************* + * _local_unwind2 (MSVCRT.@) + */ +void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_REGISTRATION *endframe, DWORD nr ) +{ + FIXME("(%p,%ld) stub\n",endframe,nr); +} + +/********************************************************************* + * _except_handler2 (MSVCRT.@) + */ +int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec, + PEXCEPTION_FRAME frame, + PCONTEXT context, PEXCEPTION_FRAME *dispatcher) +{ + FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + frame->Handler, context, dispatcher); + return ExceptionContinueSearch; +} + +/********************************************************************* + * _except_handler3 (MSVCRT.@) + */ +int __cdecl MSVCRT__except_handler3(PEXCEPTION_RECORD rec, + MSVCRT_EXCEPTION_REGISTRATION *frame, + PCONTEXT context,void *dispatcher) +{ + FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + frame->handler, context, dispatcher); + return ExceptionContinueSearch; +} + +/********************************************************************* + * _abnormal_termination (MSVCRT.@) + */ +int __cdecl MSVCRT__abnormal_termination(void) +{ + FIXME("(void)stub\n"); + return 0; +} + +/******************************************************************* + * _setjmp (MSVCRT.@) + */ +int __cdecl MSVCRT__setjmp(LPDWORD *jmpbuf) +{ + FIXME(":(%p): stub\n",jmpbuf); + return 0; +} + +/********************************************************************* + * longjmp (MSVCRT.@) + */ +void __cdecl MSVCRT_longjmp(jmp_buf env, int val) +{ + FIXME("MSVCRT_longjmp semistub, expect crash\n"); + longjmp(env, val); +} + +/********************************************************************* + * signal (MSVCRT.@) + */ +void * __cdecl MSVCRT_signal(int sig, MSVCRT_sig_handler_func func) +{ + FIXME("(%d %p):stub\n", sig, func); + return (void*)-1; +} diff --git a/dlls/msvcrt/exit.c b/dlls/msvcrt/exit.c new file mode 100644 index 00000000000..b5442ced835 --- /dev/null +++ b/dlls/msvcrt/exit.c @@ -0,0 +1,181 @@ +/* + * msvcrt.dll exit functions + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* MT */ +extern CRITICAL_SECTION MSVCRT_exit_cs; +#define LOCK_EXIT EnterCriticalSection(&MSVCRT_exit_cs) +#define UNLOCK_EXIT LeaveCriticalSection(&MSVCRT_exit_cs) + +typedef void (__cdecl *MSVCRT_atexit_func)(void); + +static MSVCRT_atexit_func *MSVCRT_atexit_table = NULL; +static int MSVCRT_atexit_table_size = 0; +static int MSVCRT_atexit_registered = 0; /* Points to free slot */ + +extern int MSVCRT_app_type; + +/* INTERNAL: call atexit functions */ +void __MSVCRT__call_atexit(void) +{ + /* Note: should only be called with the exit lock held */ + TRACE("%d atext functions to call\n", MSVCRT_atexit_registered); + /* Last registered gets executed first */ + while (MSVCRT_atexit_registered > 0) + { + MSVCRT_atexit_registered--; + TRACE("next is %p\n",MSVCRT_atexit_table[MSVCRT_atexit_registered]); + if (MSVCRT_atexit_table[MSVCRT_atexit_registered]) + (*MSVCRT_atexit_table[MSVCRT_atexit_registered])(); + TRACE("returned\n"); + } +} + +/********************************************************************* + * __dllonexit (MSVCRT.@) + */ +void __cdecl MSVCRT___dllonexit (MSVCRT_atexit_func func, MSVCRT_atexit_func **start, + MSVCRT_atexit_func **end) +{ + FIXME("(%p,%p,%p)stub\n", func, start,end); + /* FIXME: How do we know when to increase the table? */ +} + +/********************************************************************* + * _exit (MSVCRT.@) + */ +void __cdecl MSVCRT__exit(int exitcode) +{ + TRACE("(%d)\n", exitcode); + ExitProcess(exitcode); +} + +/********************************************************************* + * _amsg_exit (MSVCRT.@) + */ +void __cdecl MSVCRT__amsg_exit(int errnum) +{ + TRACE("(%d)\n", errnum); + /* FIXME: text for the error number. */ + if (MSVCRT_app_type == 2) + { + /* FIXME: MsgBox */ + } + MSVCRT__cprintf("\nruntime error R60%d\n",errnum); + MSVCRT__exit(255); +} + +/********************************************************************* + * abort (MSVCRT.@) + */ +void __cdecl MSVCRT_abort(void) +{ + TRACE("(void)\n"); + if (MSVCRT_app_type == 2) + { + /* FIXME: MsgBox */ + } + MSVCRT__cputs("\nabnormal program termination\n"); + MSVCRT__exit(3); +} + +/********************************************************************* + * _assert (MSVCRT.@) + */ +void __cdecl MSVCRT__assert(const char* str, const char* file, unsigned int line) +{ + TRACE("(%s,%s,%d)\n",str,file,line); + if (MSVCRT_app_type == 2) + { + /* FIXME: MsgBox */ + } + MSVCRT__cprintf("Assertion failed: %s, file %s, line %d\n\n",str,file, line); + MSVCRT_abort(); +} + +/********************************************************************* + * _c_exit (MSVCRT.@) + */ +void __cdecl MSVCRT__c_exit(void) +{ + TRACE("(void)\n"); + /* All cleanup is done on DLL detach; Return to caller */ +} + +/********************************************************************* + * _cexit (MSVCRT.@) + */ +void __cdecl MSVCRT__cexit(void) +{ + TRACE("(void)\n"); + /* All cleanup is done on DLL detach; Return to caller */ +} + +/********************************************************************* + * _onexit (MSVCRT.@) + */ + MSVCRT_atexit_func __cdecl MSVCRT__onexit(MSVCRT_atexit_func func) +{ + TRACE("(%p)\n",func); + + if (!func) + return NULL; + + LOCK_EXIT; + if (MSVCRT_atexit_registered > MSVCRT_atexit_table_size - 1) + { + MSVCRT_atexit_func *newtable; + TRACE("expanding table\n"); + newtable = MSVCRT_calloc(sizeof(void *),MSVCRT_atexit_table_size + 32); + if (!newtable) + { + TRACE("failed!\n"); + UNLOCK_EXIT; + return NULL; + } + memcpy (newtable, MSVCRT_atexit_table, MSVCRT_atexit_table_size); + MSVCRT_atexit_table_size += 32; + if (MSVCRT_atexit_table) + MSVCRT_free (MSVCRT_atexit_table); + MSVCRT_atexit_table = newtable; + } + MSVCRT_atexit_table[MSVCRT_atexit_registered] = func; + MSVCRT_atexit_registered++; + UNLOCK_EXIT; + return func; +} + +/********************************************************************* + * exit (MSVCRT.@) + */ +void __cdecl MSVCRT_exit(int exitcode) +{ + TRACE("(%d)\n",exitcode); + LOCK_EXIT; + __MSVCRT__call_atexit(); + UNLOCK_EXIT; + ExitProcess(exitcode); +} + +/********************************************************************* + * atexit (MSVCRT.@) + */ +int __cdecl MSVCRT_atexit(MSVCRT_atexit_func func) +{ + TRACE("(%p)\n", func); + return MSVCRT__onexit(func) == func ? 0 : -1; +} + +/********************************************************************* + * _purecall (MSVCRT.@) + */ +void __cdecl MSVCRT__purecall(void) +{ + TRACE("(void)\n"); + MSVCRT__amsg_exit( 25 ); +} diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c new file mode 100644 index 00000000000..9f6f068e299 --- /dev/null +++ b/dlls/msvcrt/file.c @@ -0,0 +1,1692 @@ +/* + * msvcrt.dll file functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + */ +#include +#include "ntddk.h" +#include "msvcrt.h" +#include "ms_errno.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* stat() mode bits */ +#define _S_IFMT 0170000 +#define _S_IFREG 0100000 +#define _S_IFDIR 0040000 +#define _S_IFCHR 0020000 +#define _S_IFIFO 0010000 +#define _S_IREAD 0000400 +#define _S_IWRITE 0000200 +#define _S_IEXEC 0000100 + +/* for stat mode, permissions apply to all,owner and group */ +#define MSVCRT_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)) +#define MSVCRT_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) +#define MSVCRT_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)) + +/* _open modes */ +#define _O_RDONLY 0x0000 +#define _O_WRONLY 0x0001 +#define _O_RDWR 0x0002 +#define _O_APPEND 0x0008 +#define _O_CREAT 0x0100 +#define _O_TRUNC 0x0200 +#define _O_EXCL 0x0400 +#define _O_TEXT 0x4000 +#define _O_BINARY 0x8000 +#define _O_TEMPORARY 0x0040 /* Will be closed and deleted on exit */ + +/* _access() bit flags FIXME: incomplete */ +#define W_OK 2 + +typedef struct _crtfile +{ + char* _ptr; + int _cnt; + char* _base; + int _flag; + int _file; /* fd */ + int _charbuf; + int _bufsiz; + char *_tmpfname; +} MSVCRT_FILE; + +/* file._flag flags */ +#define _IOREAD 0x0001 +#define _IOWRT 0x0002 +#define _IOEOF 0x0010 +#define _IOERR 0x0020 +#define _IORW 0x0080 +#define _IOAPPEND 0x0200 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define MSVCRT_stdin (&MSVCRT__iob[0]) +#define MSVCRT_stdout (&MSVCRT__iob[1]) +#define MSVCRT_stderr (&MSVCRT__iob[2]) + +struct _stat +{ + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + unsigned int st_rdev; + int st_size; + int st_atime; + int st_mtime; + int st_ctime; +}; + +typedef long MSVCRT_fpos_t; + +struct _utimbuf +{ + time_t actime; + time_t modtime; +}; + +/* FIXME: Make this dynamic */ +#define MSVCRT_MAX_FILES 257 + +HANDLE MSVCRT_handles[MSVCRT_MAX_FILES]; +MSVCRT_FILE* MSVCRT_files[MSVCRT_MAX_FILES]; +int MSVCRT_flags[MSVCRT_MAX_FILES]; +char *MSVCRT_tempfiles[MSVCRT_MAX_FILES]; +MSVCRT_FILE MSVCRT__iob[3]; + +static int MSVCRT_fdstart = 3; /* first unallocated fd */ +static int MSVCRT_fdend = 3; /* highest allocated fd */ + +/* INTERNAL: process umask */ +static int MSVCRT_umask = 0; + +/* INTERNAL: Static buffer for temp file name */ +static char MSVCRT_tmpname[MAX_PATH]; + +static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e'; +static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't'; +static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd'; +static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm'; + +extern CRITICAL_SECTION MSVCRT_file_cs; +#define LOCK_FILES EnterCriticalSection(&MSVCRT_file_cs) +#define UNLOCK_FILES LeaveCriticalSection(&MSVCRT_file_cs) + +time_t __cdecl MSVCRT_time(time_t *); +int __cdecl MSVCRT__getdrive(void); + +/* INTERNAL: Get the HANDLE for a fd */ +static HANDLE MSVCRT__fdtoh(int fd) +{ + if (fd < 0 || fd >= MSVCRT_fdend || + MSVCRT_handles[fd] == INVALID_HANDLE_VALUE) + { + WARN(":fd (%d) - no handle!\n",fd); + SET_THREAD_VAR(doserrno,0); + SET_THREAD_VAR(errno,MSVCRT_EBADF); + return INVALID_HANDLE_VALUE; + } + return MSVCRT_handles[fd]; +} + +/* INTERNAL: free a file entry fd */ +static void MSVCRT__free_fd(int fd) +{ + MSVCRT_handles[fd] = INVALID_HANDLE_VALUE; + MSVCRT_files[fd] = 0; + MSVCRT_flags[fd] = 0; + TRACE(":fd (%d) freed\n",fd); + if (fd < 3) + return; /* dont use 0,1,2 for user files */ + if (fd == MSVCRT_fdend - 1) + MSVCRT_fdend--; + if (fd < MSVCRT_fdstart) + MSVCRT_fdstart = fd; +} + +/* INTERNAL: Allocate an fd slot from a Win32 HANDLE */ +static int MSVCRT__alloc_fd(HANDLE hand, int flag) +{ + int fd = MSVCRT_fdstart; + + TRACE(":handle (%d) allocating fd (%d)\n",hand,fd); + if (fd >= MSVCRT_MAX_FILES) + { + WARN(":files exhausted!\n"); + return -1; + } + MSVCRT_handles[fd] = hand; + MSVCRT_flags[fd] = flag; + + /* locate next free slot */ + if (fd == MSVCRT_fdend) + MSVCRT_fdstart = ++MSVCRT_fdend; + else + while(MSVCRT_fdstart < MSVCRT_fdend && + MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE) + MSVCRT_fdstart++; + + return fd; +} + +/* INTERNAL: Allocate a FILE* for an fd slot + * This is done lazily to avoid memory wastage for low level open/write + * usage when a FILE* is not requested (but may be later). + */ +static MSVCRT_FILE* MSVCRT__alloc_fp(int fd) +{ + TRACE(":fd (%d) allocating FILE*\n",fd); + if (fd < 0 || fd >= MSVCRT_fdend || + MSVCRT_handles[fd] == INVALID_HANDLE_VALUE) + { + WARN(":invalid fd %d\n",fd); + SET_THREAD_VAR(doserrno,0); + SET_THREAD_VAR(errno,MSVCRT_EBADF); + return NULL; + } + if (!MSVCRT_files[fd]) + { + if ((MSVCRT_files[fd] = MSVCRT_calloc(sizeof(MSVCRT_FILE),1))) + { + MSVCRT_files[fd]->_file = fd; + MSVCRT_files[fd]->_flag = MSVCRT_flags[fd]; + MSVCRT_files[fd]->_flag &= ~_IOAPPEND; /* mask out, see above */ + } + } + TRACE(":got FILE* (%p)\n",MSVCRT_files[fd]); + return MSVCRT_files[fd]; +} + + +/* INTERNAL: Set up stdin, stderr and stdout */ +void MSVCRT_init_io(void) +{ + int i; + memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE)); + MSVCRT_handles[0] = GetStdHandle(STD_INPUT_HANDLE); + MSVCRT_flags[0] = MSVCRT__iob[0]._flag = _IOREAD; + MSVCRT_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE); + MSVCRT_flags[1] = MSVCRT__iob[1]._flag = _IOWRT; + MSVCRT_handles[2] = GetStdHandle(STD_ERROR_HANDLE); + MSVCRT_flags[2] = MSVCRT__iob[2]._flag = _IOWRT; + + TRACE(":handles (%d)(%d)(%d)\n",MSVCRT_handles[0], + MSVCRT_handles[1],MSVCRT_handles[2]); + + for (i = 0; i < 3; i++) + { + /* FILE structs for stdin/out/err are static and never deleted */ + MSVCRT_files[i] = &MSVCRT__iob[i]; + MSVCRT__iob[i]._file = i; + MSVCRT_tempfiles[i] = NULL; + } +} + +/********************************************************************* + * __p__iob(MSVCRT.@) + */ +MSVCRT_FILE *MSVCRT___p__iob(void) +{ + return &MSVCRT__iob[0]; +} + +/********************************************************************* + * _access (MSVCRT.@) + */ +int __cdecl MSVCRT__access(const char *filename, int mode) +{ + DWORD attr = GetFileAttributesA(filename); + + if (attr == 0xffffffff) + { + if (!filename) + { + /* FIXME: Should GetFileAttributesA() return this? */ + MSVCRT__set_errno(ERROR_INVALID_DATA); + return -1; + } + MSVCRT__set_errno(GetLastError()); + return -1; + } + if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) + { + MSVCRT__set_errno(ERROR_ACCESS_DENIED); + return -1; + } + TRACE(":file %s, mode (%d) ok\n",filename,mode); + return 0; +} + + +/********************************************************************* + * _chmod (MSVCRT.@) + */ +int __cdecl MSVCRT__chmod(const char *path, int flags) +{ + DWORD oldFlags = GetFileAttributesA(path); + + if (oldFlags != 0x0FFFFFFFF) + { + DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY: + oldFlags | FILE_ATTRIBUTE_READONLY; + + if (newFlags == oldFlags || SetFileAttributesA(path, newFlags)) + return 0; + } + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _unlink (MSVCRT.@) + */ +int __cdecl MSVCRT__unlink(const char *path) +{ + TRACE("path (%s)\n",path); + if(DeleteFileA(path)) + return 0; + TRACE("failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * _close (MSVCRT.@) + */ +int __cdecl MSVCRT__close(int fd) +{ + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* Dont free std FILE*'s, they are not dynamic */ + if (fd > 2 && MSVCRT_files[fd]) + MSVCRT_free(MSVCRT_files[fd]); + + MSVCRT__free_fd(fd); + + if (!CloseHandle(hand)) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; + } + if (MSVCRT_tempfiles[fd]) + { + TRACE("deleting temporary file '%s'\n",MSVCRT_tempfiles[fd]); + MSVCRT__unlink(MSVCRT_tempfiles[fd]); + MSVCRT_free(MSVCRT_tempfiles[fd]); + MSVCRT_tempfiles[fd] = NULL; + } + + TRACE(":ok\n"); + return 0; +} + +/********************************************************************* + * _commit (MSVCRT.@) + */ +int __cdecl MSVCRT__commit(int fd) +{ + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (!FlushFileBuffers(hand)) + { + if (GetLastError() == ERROR_INVALID_HANDLE) + { + /* FlushFileBuffers fails for console handles + * so we ignore this error. + */ + return 0; + } + TRACE(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; + } + TRACE(":ok\n"); + return 0; +} + +/********************************************************************* + * _eof (MSVCRT.@) + */ +int __cdecl MSVCRT__eof(int fd) +{ + DWORD curpos,endpos; + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* If we have a FILE* for this file, the EOF flag + * will be set by the read()/write() functions. + */ + if (MSVCRT_files[fd]) + return MSVCRT_files[fd]->_flag & _IOEOF; + + /* Otherwise we do it the hard way */ + curpos = SetFilePointer(hand, 0, NULL, SEEK_CUR); + endpos = SetFilePointer(hand, 0, NULL, FILE_END); + + if (curpos == endpos) + return TRUE; + + SetFilePointer(hand, curpos, 0, FILE_BEGIN); + return FALSE; +} + +/********************************************************************* + * _fcloseall (MSVCRT.@) + */ +int __cdecl MSVCRT__fcloseall(void) +{ + int num_closed = 0, i; + + for (i = 3; i < MSVCRT_fdend; i++) + if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE) + { + MSVCRT__close(i); + num_closed++; + } + + TRACE(":closed (%d) handles\n",num_closed); + return num_closed; +} + +/********************************************************************* + * _lseek (MSVCRT.@) + */ +LONG __cdecl MSVCRT__lseek(int fd, LONG offset, int whence) +{ + DWORD ret; + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (whence < 0 || whence > 2) + { + SET_THREAD_VAR(errno,MSVCRT_EINVAL); + return -1; + } + + TRACE(":fd (%d) to 0x%08lx pos %s\n", + fd,offset,(whence==SEEK_SET)?"SEEK_SET": + (whence==SEEK_CUR)?"SEEK_CUR": + (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); + + if ((ret = SetFilePointer(hand, offset, NULL, whence)) != 0xffffffff) + { + if (MSVCRT_files[fd]) + MSVCRT_files[fd]->_flag &= ~_IOEOF; + /* FIXME: What if we seek _to_ EOF - is EOF set? */ + return ret; + } + TRACE(":error-last error (%ld)\n",GetLastError()); + if (MSVCRT_files[fd]) + switch(GetLastError()) + { + case ERROR_NEGATIVE_SEEK: + case ERROR_SEEK_ON_DEVICE: + MSVCRT__set_errno(GetLastError()); + MSVCRT_files[fd]->_flag |= _IOERR; + break; + default: + break; + } + return -1; +} + +/********************************************************************* + * rewind (MSVCRT.@) + */ +VOID __cdecl MSVCRT_rewind(MSVCRT_FILE* file) +{ + TRACE(":file (%p) fd (%d)\n",file,file->_file); + MSVCRT__lseek(file->_file,0,SEEK_SET); + file->_flag &= ~(_IOEOF | _IOERR); +} + +/********************************************************************* + * _fdopen (MSVCRT.@) + */ +MSVCRT_FILE* __cdecl MSVCRT__fdopen(int fd, const char *mode) +{ + MSVCRT_FILE* file = MSVCRT__alloc_fp(fd); + + TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file); + if (file) + MSVCRT_rewind(file); + + return file; +} + +/********************************************************************* + * _filelength (MSVCRT.@) + */ +LONG __cdecl MSVCRT__filelength(int fd) +{ + LONG curPos = MSVCRT__lseek(fd, 0, SEEK_CUR); + if (curPos != -1) + { + LONG endPos = MSVCRT__lseek(fd, 0, SEEK_END); + if (endPos != -1) + { + if (endPos != curPos) + MSVCRT__lseek(fd, curPos, SEEK_SET); + return endPos; + } + } + return -1; +} + +/********************************************************************* + * _fileno (MSVCRT.@) + */ +int __cdecl MSVCRT__fileno(MSVCRT_FILE* file) +{ + TRACE(":FILE* (%p) fd (%d)\n",file,file->_file); + return file->_file; +} + +/********************************************************************* + * _flushall (MSVCRT.@) + */ +int __cdecl MSVCRT__flushall(VOID) +{ + int num_flushed = 0, i = 3; + + while(i < MSVCRT_fdend) + if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE) + { + if (MSVCRT__commit(i) == -1) + if (MSVCRT_files[i]) + MSVCRT_files[i]->_flag |= _IOERR; + num_flushed++; + } + + TRACE(":flushed (%d) handles\n",num_flushed); + return num_flushed; +} + +/********************************************************************* + * _fstat (MSVCRT.@) + */ +int __cdecl MSVCRT__fstat(int fd, struct _stat* buf) +{ + DWORD dw; + BY_HANDLE_FILE_INFORMATION hfi; + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) stat (%p)\n",fd,buf); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + if (!buf) + { + WARN(":failed-NULL buf\n"); + MSVCRT__set_errno(ERROR_INVALID_PARAMETER); + return -1; + } + + memset(&hfi, 0, sizeof(hfi)); + memset(buf, 0, sizeof(struct _stat)); + if (!GetFileInformationByHandle(hand, &hfi)) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(ERROR_INVALID_PARAMETER); + return -1; + } + FIXME(":dwFileAttributes = %d, mode set to 0",hfi.dwFileAttributes); + buf->st_nlink = hfi.nNumberOfLinks; + buf->st_size = hfi.nFileSizeLow; + RtlTimeToSecondsSince1970(&hfi.ftLastAccessTime, &dw); + buf->st_atime = dw; + RtlTimeToSecondsSince1970(&hfi.ftLastWriteTime, &dw); + buf->st_mtime = buf->st_ctime = dw; + return 0; +} + +/********************************************************************* + * _futime (MSVCRT.@) + */ +int __cdecl MSVCRT__futime(int fd, struct _utimbuf *t) +{ + HANDLE hand = MSVCRT__fdtoh(fd); + FILETIME at, wt; + + if (!t) + { + time_t currTime; + MSVCRT_time(&currTime); + RtlSecondsSince1970ToTime(currTime, &at); + memcpy(&wt, &at, sizeof(wt)); + } + else + { + RtlSecondsSince1970ToTime(t->actime, &at); + if (t->actime == t->modtime) + memcpy(&wt, &at, sizeof(wt)); + else + RtlSecondsSince1970ToTime(t->modtime, &wt); + } + + if (!SetFileTime(hand, NULL, &at, &wt)) + { + MSVCRT__set_errno(GetLastError()); + return -1 ; + } + return 0; +} + +/********************************************************************* + * _get_osfhandle (MSVCRT.@) + */ +HANDLE MSVCRT__get_osfhandle(int fd) +{ + HANDLE hand = MSVCRT__fdtoh(fd); + HANDLE newhand = hand; + TRACE(":fd (%d) handle (%d)\n",fd,hand); + + if (hand != INVALID_HANDLE_VALUE) + { + /* FIXME: I'm not convinced that I should be copying the + * handle here - it may be leaked if the app doesn't + * close it (and the API docs dont say that it should) + * Not duplicating it means that it can't be inherited + * and so lcc's wedit doesn't cope when it passes it to + * child processes. I've an idea that it should either + * be copied by CreateProcess, or marked as inheritable + * when initialised, or maybe both? JG 21-9-00. + */ + DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(), + &newhand,0,TRUE,DUPLICATE_SAME_ACCESS); + } + return newhand; +} + +/********************************************************************* + * _isatty (MSVCRT.@) + */ +int __cdecl MSVCRT__isatty(int fd) +{ + HANDLE hand = MSVCRT__fdtoh(fd); + + TRACE(":fd (%d) handle (%d)\n",fd,hand); + if (hand == INVALID_HANDLE_VALUE) + return 0; + + return GetFileType(fd) == FILE_TYPE_CHAR? 1 : 0; +} + +/********************************************************************* + * _mktemp (MSVCRT.@) + */ +char *__cdecl MSVCRT__mktemp(char *pattern) +{ + int numX = 0; + char *retVal = pattern; + int id; + char letter = 'a'; + + while(*pattern) + numX = (*pattern++ == 'X')? numX + 1 : 0; + if (numX < 5) + return NULL; + pattern--; + id = GetCurrentProcessId(); + numX = 6; + while(numX--) + { + int tempNum = id / 10; + *pattern-- = id - (tempNum * 10) + '0'; + id = tempNum; + } + pattern++; + do + { + if (GetFileAttributesA(retVal) == 0xFFFFFFFF && + GetLastError() == ERROR_FILE_NOT_FOUND) + return retVal; + *pattern = letter++; + } while(letter != '|'); + return NULL; +} + +/********************************************************************* + * _open (MSVCRT.@) + */ +int __cdecl MSVCRT__open(const char *path,int flags) +{ + DWORD access = 0, creation = 0; + int ioflag = 0, fd; + HANDLE hand; + + TRACE(":file (%s) mode 0x%04x\n",path,flags); + + switch(flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) + { + case _O_RDONLY: + access |= GENERIC_READ; + ioflag |= _IOREAD; + break; + case _O_WRONLY: + access |= GENERIC_WRITE; + ioflag |= _IOWRT; + break; + case _O_RDWR: + access |= GENERIC_WRITE | GENERIC_READ; + ioflag |= _IORW; + break; + } + + if (flags & _O_CREAT) + { + if (flags & _O_EXCL) + creation = CREATE_NEW; + else if (flags & _O_TRUNC) + creation = CREATE_ALWAYS; + else + creation = OPEN_ALWAYS; + } + else /* no _O_CREAT */ + { + if (flags & _O_TRUNC) + creation = TRUNCATE_EXISTING; + else + creation = OPEN_EXISTING; + } + if (flags & _O_APPEND) + ioflag |= _IOAPPEND; + + + flags |= _O_BINARY; /* FIXME: Default to text */ + + if (flags & _O_TEXT) + { + /* Dont warn when writing */ + if (ioflag & GENERIC_READ) + FIXME(":TEXT node not implemented\n"); + flags &= ~_O_TEXT; + } + + if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL + |_O_CREAT|_O_RDWR|_O_TEMPORARY)) + TRACE(":unsupported flags 0x%04x\n",flags); + + hand = CreateFileA(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, creation, FILE_ATTRIBUTE_NORMAL, 0); + + if (hand == INVALID_HANDLE_VALUE) + { + WARN(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; + } + + fd = MSVCRT__alloc_fd(hand, ioflag); + + TRACE(":fd (%d) handle (%d)\n",fd, hand); + + if (fd > 0) + { + if (flags & _O_TEMPORARY) + MSVCRT_tempfiles[fd] = MSVCRT__strdup(path); + if (ioflag & _IOAPPEND) + MSVCRT__lseek(fd, 0, FILE_END); + } + + return fd; +} + +/********************************************************************* + * _creat (MSVCRT.@) + */ +int __cdecl MSVCRT__creat(const char *path, int flags) +{ + int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC; + return MSVCRT__open(path, usedFlags); +} + +/********************************************************************* + * _open_osfhandle (MSVCRT.@) + */ +int __cdecl MSVCRT__open_osfhandle(HANDLE hand, int flags) +{ + int fd = MSVCRT__alloc_fd(hand,flags); + TRACE(":handle (%d) fd (%d)\n",hand,fd); + return fd; +} + +/********************************************************************* + * _rmtmp (MSVCRT.@) + */ +int __cdecl MSVCRT__rmtmp(void) +{ + int num_removed = 0, i; + + for (i = 3; i < MSVCRT_fdend; i++) + if (MSVCRT_tempfiles[i]) + { + MSVCRT__close(i); + num_removed++; + } + + if (num_removed) + TRACE(":removed (%d) temp files\n",num_removed); + return num_removed; +} + +/********************************************************************* + * _read (MSVCRT.@) + */ +int __cdecl MSVCRT__read(int fd, LPVOID buf, unsigned int count) +{ + DWORD num_read; + HANDLE hand = MSVCRT__fdtoh(fd); + + /* Dont trace small reads, it gets *very* annoying */ + if (count > 4) + TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* Set _cnt to 0 so optimised binaries will call our implementation + * of putc/getc. See _filbuf/_flsbuf comments. + */ + if (MSVCRT_files[fd]) + MSVCRT_files[fd]->_cnt = 0; + + if (ReadFile(hand, buf, count, &num_read, NULL)) + { + if (num_read != count && MSVCRT_files[fd]) + { + TRACE(":EOF\n"); + MSVCRT_files[fd]->_flag |= _IOEOF; + } + return num_read; + } + TRACE(":failed-last error (%ld)\n",GetLastError()); + if (MSVCRT_files[fd]) + MSVCRT_files[fd]->_flag |= _IOERR; + return -1; +} + +/********************************************************************* + * _getw (MSVCRT.@) + */ +int __cdecl MSVCRT__getw(MSVCRT_FILE* file) +{ + int i; + if (MSVCRT__read(file->_file, &i, sizeof(int)) != 1) + return MSVCRT_EOF; + return i; +} + +/********************************************************************* + * _setmode (MSVCRT.@) + */ +int __cdecl MSVCRT__setmode(int fd,int mode) +{ + if (mode & _O_TEXT) + FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode); + return 0; +} + +/********************************************************************* + * _stat (MSVCRT.@) + */ +int __cdecl MSVCRT__stat(const char* path, struct _stat * buf) +{ + DWORD dw; + WIN32_FILE_ATTRIBUTE_DATA hfi; + unsigned short mode = MSVCRT_S_IREAD; + int plen; + + TRACE(":file (%s) buf(%p)\n",path,buf); + + if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi)) + { + TRACE("failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(ERROR_FILE_NOT_FOUND); + return -1; + } + + memset(buf,0,sizeof(struct _stat)); + + /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */ + if (isalpha(*path)) + buf->st_dev = buf->st_rdev = toupper(*path - 'A'); /* drive num */ + else + buf->st_dev = buf->st_rdev = MSVCRT__getdrive() - 1; + + plen = strlen(path); + + /* Dir, or regular file? */ + if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || + (path[plen-1] == '\\')) + mode |= (_S_IFDIR | MSVCRT_S_IEXEC); + else + { + mode |= _S_IFREG; + /* executable? */ + if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */ + { + unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) + | (tolower(path[plen-3]) << 16); + if (ext == EXE || ext == BAT || ext == CMD || ext == COM) + mode |= MSVCRT_S_IEXEC; + } + } + + if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + mode |= MSVCRT_S_IWRITE; + + buf->st_mode = mode; + buf->st_nlink = 1; + buf->st_size = hfi.nFileSizeLow; + RtlTimeToSecondsSince1970(&hfi.ftLastAccessTime, &dw); + buf->st_atime = dw; + RtlTimeToSecondsSince1970(&hfi.ftLastWriteTime, &dw); + buf->st_mtime = buf->st_ctime = dw; + TRACE("\n%d %d %d %d %d %d\n", buf->st_mode,buf->st_nlink,buf->st_size, + buf->st_atime,buf->st_mtime, buf->st_ctime); + return 0; +} + +/********************************************************************* + * _tell (MSVCRT.@) + */ +LONG __cdecl MSVCRT__tell(int fd) +{ + return MSVCRT__lseek(fd, 0, SEEK_CUR); +} + +/********************************************************************* + * _tempnam (MSVCRT.@) + */ +char *__cdecl MSVCRT__tempnam(const char *dir, const char *prefix) +{ + char tmpbuf[MAX_PATH]; + + TRACE("dir (%s) prefix (%s)\n",dir,prefix); + if (GetTempFileNameA(dir,prefix,0,tmpbuf)) + { + TRACE("got name (%s)\n",tmpbuf); + return MSVCRT__strdup(tmpbuf); + } + TRACE("failed-last error (%ld)\n",GetLastError()); + return NULL; +} + +/********************************************************************* + * _umask (MSVCRT.@) + */ +int __cdecl MSVCRT__umask(int umask) +{ + int old_umask = MSVCRT_umask; + TRACE("umask (%d)\n",umask); + MSVCRT_umask = umask; + return old_umask; +} + +/********************************************************************* + * _utime (MSVCRT.@) + */ +int __cdecl MSVCRT__utime(const char *path, struct _utimbuf *t) +{ + int fd = MSVCRT__open(path, _O_WRONLY | _O_BINARY); + + if (fd > 0) + { + int retVal = MSVCRT__futime(fd, t); + MSVCRT__close(fd); + return retVal; + } + return -1; +} + +/********************************************************************* + * _write (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__write(int fd, LPCVOID buf, unsigned int count) +{ + DWORD num_written; + HANDLE hand = MSVCRT__fdtoh(fd); + + /* Dont trace small writes, it gets *very* annoying */ +// if (count > 32) +// TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count); + if (hand == INVALID_HANDLE_VALUE) + return -1; + + /* If appending, go to EOF */ + if (MSVCRT_flags[fd] & _IOAPPEND) + MSVCRT__lseek(fd, 0, FILE_END); + + /* Set _cnt to 0 so optimised binaries will call our implementation + * of putc/getc. + */ + if (MSVCRT_files[fd]) + MSVCRT_files[fd]->_cnt = 0; + + if (WriteFile(hand, buf, count, &num_written, NULL) + && (num_written == count)) + return num_written; + + TRACE(":failed-last error (%ld)\n",GetLastError()); + if (MSVCRT_files[fd]) + MSVCRT_files[fd]->_flag |= _IOERR; + + return -1; +} + +/********************************************************************* + * _putw (MSVCRT.@) + */ +int __cdecl MSVCRT__putw(int val, MSVCRT_FILE* file) +{ + return MSVCRT__write(file->_file, &val, sizeof(val)) == 1? val : MSVCRT_EOF; +} + +/********************************************************************* + * clearerr (MSVCRT.@) + */ +VOID __cdecl MSVCRT_clearerr(MSVCRT_FILE* file) +{ + TRACE(":file (%p) fd (%d)\n",file,file->_file); + file->_flag &= ~(_IOERR | _IOEOF); +} + +/********************************************************************* + * fclose (MSVCRT.@) + */ +int __cdecl MSVCRT_fclose(MSVCRT_FILE* file) +{ + return MSVCRT__close(file->_file); +} + +/********************************************************************* + * feof (MSVCRT.@) + */ +int __cdecl MSVCRT_feof(MSVCRT_FILE* file) +{ + return file->_flag & _IOEOF; +} + +/********************************************************************* + * ferror (MSVCRT.@) + */ +int __cdecl MSVCRT_ferror(MSVCRT_FILE* file) +{ + return file->_flag & _IOERR; +} + +/********************************************************************* + * fflush (MSVCRT.@) + */ +int __cdecl MSVCRT_fflush(MSVCRT_FILE* file) +{ + return MSVCRT__commit(file->_file); +} + +/********************************************************************* + * fgetc (MSVCRT.@) + */ +int __cdecl MSVCRT_fgetc(MSVCRT_FILE* file) +{ + char c; + if (MSVCRT__read(file->_file,&c,1) != 1) + return MSVCRT_EOF; + return c; +} + +/********************************************************************* + * _fgetchar (MSVCRT.@) + */ +int __cdecl MSVCRT__fgetchar(void) +{ + return MSVCRT_fgetc(MSVCRT_stdin); +} + +/********************************************************************* + * _filbuf (MSVCRT.@) + */ +int __cdecl MSVCRT__filbuf(MSVCRT_FILE* file) +{ + return MSVCRT_fgetc(file); +} + +/********************************************************************* + * fgetpos (MSVCRT.@) + */ +int __cdecl MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos) +{ + *pos = MSVCRT__tell(file->_file); + return (*pos == -1? -1 : 0); +} + +/********************************************************************* + * fgets (MSVCRT.@) + */ +CHAR* __cdecl MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file) +{ + int cc; + char * buf_start = s; + + TRACE(":file(%p) fd (%d) str (%p) len (%d)\n", + file,file->_file,s,size); + + /* BAD, for the whole WINE process blocks... just done this way to test + * windows95's ftp.exe. + * JG - Is this true now we use ReadFile() on stdin too? + */ + for(cc = MSVCRT_fgetc(file); cc != MSVCRT_EOF && cc != '\n'; + cc = MSVCRT_fgetc(file)) + if (cc != '\r') + { + if (--size <= 0) break; + *s++ = (char)cc; + } + if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/ + { + TRACE(":nothing read\n"); + return 0; + } + if (cc == '\n') + if (--size > 0) + *s++ = '\n'; + *s = '\0'; + TRACE(":got '%s'\n", buf_start); + return buf_start; +} + +/********************************************************************* + * fgetwc (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT_fgetwc(MSVCRT_FILE* file) +{ + WCHAR wc; + if (MSVCRT__read(file->_file, &wc, sizeof(wc)) != sizeof(wc)) + return MSVCRT_WEOF; + return wc; +} + +/********************************************************************* + * getwc (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT_getwc(MSVCRT_FILE* file) +{ + return MSVCRT_fgetwc(file); +} + +/********************************************************************* + * _fgetwchar (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT__fgetwchar(void) +{ + return MSVCRT_fgetwc(MSVCRT_stdin); +} + +/********************************************************************* + * getwchar (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT_getwchar(void) +{ + return MSVCRT__fgetwchar(); +} + +/********************************************************************* + * fputwc (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT_fputwc(WCHAR wc, MSVCRT_FILE* file) +{ + if (MSVCRT__write(file->_file, &wc, sizeof(wc)) != sizeof(wc)) + return MSVCRT_WEOF; + return wc; +} + +/********************************************************************* + * _fputwchar (MSVCRT.@) + */ +WCHAR __cdecl MSVCRT__fputwchar(WCHAR wc) +{ + return MSVCRT_fputwc(wc, MSVCRT_stdout); +} + +/********************************************************************* + * fopen (MSVCRT.@) + */ +MSVCRT_FILE* __cdecl MSVCRT_fopen(const char *path, const char *mode) +{ + MSVCRT_FILE* file; + int flags = 0, plus = 0, fd; + const char* search = mode; + + TRACE(":path (%s) mode (%s)\n",path,mode); + + while (*search) + if (*search++ == '+') + plus = 1; + + /* map mode string to open() flags. "man fopen" for possibilities. */ + switch(*mode++) + { + case 'R': case 'r': + flags = (plus ? _O_RDWR : _O_RDONLY); + break; + case 'W': case 'w': + flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY); + break; + case 'A': case 'a': + flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY); + break; + default: + return NULL; + } + + while (*mode) + switch (*mode++) + { + case 'B': case 'b': + flags |= _O_BINARY; + flags &= ~_O_TEXT; + break; + case 'T': case 't': + flags |= _O_TEXT; + flags &= ~_O_BINARY; + break; + case '+': + break; + default: + FIXME(":unknown flag %c not supported\n",mode[-1]); + } + + fd = MSVCRT__open(path, flags); + + if (fd < 0) + return NULL; + + file = MSVCRT__alloc_fp(fd); + TRACE(":get file (%p)\n",file); + if (!file) + MSVCRT__close(fd); + + return file; +} + +/********************************************************************* + * _fsopen (MSVCRT.@) + */ +MSVCRT_FILE* __cdecl MSVCRT__fsopen(const char *path, const char *mode, int share) +{ + FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share); + return MSVCRT_fopen(path,mode); +} + +/********************************************************************* + * fputc (MSVCRT.@) + */ +int __cdecl MSVCRT_fputc(int c, MSVCRT_FILE* file) +{ + return MSVCRT__write(file->_file, &c, 1) == 1? c : MSVCRT_EOF; +} + +/********************************************************************* + * _flsbuf (MSVCRT.@) + */ +int __cdecl MSVCRT__flsbuf(int c, MSVCRT_FILE* file) +{ + return MSVCRT_fputc(c,file); +} + +/********************************************************************* + * _fputchar (MSVCRT.@) + */ +int __cdecl MSVCRT__fputchar(int c) +{ + return MSVCRT_fputc(c, MSVCRT_stdout); +} + +/********************************************************************* + * fread (MSVCRT.@) + */ +DWORD __cdecl MSVCRT_fread(LPVOID ptr, int size, int nmemb, MSVCRT_FILE* file) +{ + DWORD read = MSVCRT__read(file->_file,ptr, size * nmemb); + if (read <= 0) + return 0; + return read / size; +} + +/********************************************************************* + * freopen (MSVCRT.@) + * + */ +MSVCRT_FILE* __cdecl MSVCRT_freopen(const char *path, const char *mode,MSVCRT_FILE* file) +{ + MSVCRT_FILE* newfile; + int fd; + + TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file); + if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend) + return NULL; + + if (fd > 2) + { + FIXME(":reopen on user file not implemented!\n"); + MSVCRT__set_errno(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; + } + + /* first, create the new file */ + if ((newfile = MSVCRT_fopen(path,mode)) == NULL) + return NULL; + + if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE : + (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), + MSVCRT_handles[newfile->_file])) + { + /* Redirecting std handle to file , copy over.. */ + MSVCRT_handles[fd] = MSVCRT_handles[newfile->_file]; + MSVCRT_flags[fd] = MSVCRT_flags[newfile->_file]; + memcpy(&MSVCRT__iob[fd], newfile, sizeof (MSVCRT_FILE)); + MSVCRT__iob[fd]._file = fd; + /* And free up the resources allocated by fopen, but + * not the HANDLE we copied. */ + MSVCRT_free(MSVCRT_files[fd]); + MSVCRT__free_fd(newfile->_file); + return &MSVCRT__iob[fd]; + } + + WARN(":failed-last error (%ld)\n",GetLastError()); + MSVCRT_fclose(newfile); + MSVCRT__set_errno(GetLastError()); + return NULL; +} + +/********************************************************************* + * fsetpos (MSVCRT.@) + */ +int __cdecl MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos) +{ + return MSVCRT__lseek(file->_file,*pos,SEEK_SET); +} + +/********************************************************************* + * fscanf (MSVCRT.@) + */ +int __cdecl MSVCRT_fscanf(MSVCRT_FILE* file, const char *format, ...) +{ + /* NOTE: If you extend this function, extend MSVCRT__cscanf in console.c too */ + int rd = 0; + int nch; + va_list ap; + if (!*format) return 0; + WARN("%p (\"%s\"): semi-stub\n", file, format); + nch = MSVCRT_fgetc(file); + va_start(ap, format); + while (*format) { + if (*format == ' ') { + /* skip whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT_fgetc(file); + } + else if (*format == '%') { + int st = 0; + format++; + switch(*format) { + case 'd': { /* read an integer */ + int*val = va_arg(ap, int*); + int cur = 0; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT_fgetc(file); + /* get sign and first digit */ + if (nch == '-') { + nch = MSVCRT_fgetc(file); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + nch = MSVCRT_fgetc(file); + /* read until no more digits */ + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = MSVCRT_fgetc(file); + } + st = 1; + *val = cur; + } + break; + case 'f': { /* read a float */ + float*val = va_arg(ap, float*); + float cur = 0; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT_fgetc(file); + /* get sign and first digit */ + if (nch == '-') { + nch = MSVCRT_fgetc(file); + if (isdigit(nch)) + cur = -(nch - '0'); + else break; + } else { + if (isdigit(nch)) + cur = nch - '0'; + else break; + } + /* read until no more digits */ + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + cur = cur*10 + (nch - '0'); + nch = MSVCRT_fgetc(file); + } + if (nch == '.') { + /* handle decimals */ + float dec = 1; + nch = MSVCRT_fgetc(file); + while ((nch!=MSVCRT_EOF) && isdigit(nch)) { + dec /= 10; + cur += dec * (nch - '0'); + nch = MSVCRT_fgetc(file); + } + } + st = 1; + *val = cur; + } + break; + case 's': { /* read a word */ + char*str = va_arg(ap, char*); + char*sptr = str; + /* skip initial whitespace */ + while ((nch!=MSVCRT_EOF) && isspace(nch)) + nch = MSVCRT_fgetc(file); + /* read until whitespace */ + while ((nch!=MSVCRT_EOF) && !isspace(nch)) { + *sptr++ = nch; st++; + nch = MSVCRT_fgetc(file); + } + /* terminate */ + *sptr = 0; + TRACE("read word: %s\n", str); + } + break; + default: FIXME("unhandled: %%%c\n", *format); + } + if (st) rd++; + else break; + } + else { + /* check for character match */ + if (nch == *format) + nch = MSVCRT_fgetc(file); + else break; + } + format++; + } + va_end(ap); + if (nch!=MSVCRT_EOF) { + WARN("need ungetch\n"); + } + TRACE("returning %d\n", rd); + return rd; +} + +/********************************************************************* + * fseek (MSVCRT.@) + */ +LONG __cdecl MSVCRT_fseek(MSVCRT_FILE* file, LONG offset, int whence) +{ + return MSVCRT__lseek(file->_file,offset,whence); +} + +/********************************************************************* + * ftell (MSVCRT.@) + */ +LONG __cdecl MSVCRT_ftell(MSVCRT_FILE* file) +{ + return MSVCRT__tell(file->_file); +} + +/********************************************************************* + * fwrite (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT_fwrite(LPCVOID ptr, int size, int nmemb, MSVCRT_FILE* file) +{ + unsigned int written = MSVCRT__write(file->_file, ptr, size * nmemb); + if (written <= 0) + return 0; + return written / size; +} + +/********************************************************************* + * fputs (MSVCRT.@) + */ +int __cdecl MSVCRT_fputs(const char *s, MSVCRT_FILE* file) +{ + return MSVCRT_fwrite(s,strlen(s),1,file) == 1 ? 0 : MSVCRT_EOF; +} + +/********************************************************************* + * getchar (MSVCRT.@) + */ +int __cdecl MSVCRT_getchar(void) +{ + return MSVCRT_fgetc(MSVCRT_stdin); +} + +/********************************************************************* + * getc (MSVCRT.@) + */ +int __cdecl MSVCRT_getc(MSVCRT_FILE* file) +{ + return MSVCRT_fgetc(file); +} + +/********************************************************************* + * gets (MSVCRT.@) + */ +char *__cdecl MSVCRT_gets(char *buf) +{ + int cc; + char * buf_start = buf; + + /* BAD, for the whole WINE process blocks... just done this way to test + * windows95's ftp.exe. + * JG 19/9/00: Is this still true, now we are using ReadFile? + */ + for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n'; + cc = MSVCRT_fgetc(MSVCRT_stdin)) + if(cc != '\r') *buf++ = (char)cc; + + *buf = '\0'; + + TRACE("got '%s'\n", buf_start); + return buf_start; +} + +/********************************************************************* + * putc (MSVCRT.@) + */ +int __cdecl MSVCRT_putc(int c, MSVCRT_FILE* file) +{ + return MSVCRT_fputc(c, file); +} + +/********************************************************************* + * putchar (MSVCRT.@) + */ +void __cdecl MSVCRT_putchar(int c) +{ + MSVCRT_fputc(c, MSVCRT_stdout); +} + +/********************************************************************* + * puts (MSVCRT.@) + */ +int __cdecl MSVCRT_puts(const char *s) +{ + int retval = MSVCRT_EOF; + if (MSVCRT_fwrite(s,strlen(s),1,MSVCRT_stdout) == 1) + return MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF; + return retval; +} + +/********************************************************************* + * remove (MSVCRT.@) + */ +int __cdecl MSVCRT_remove(const char *path) +{ + TRACE(":path (%s)\n",path); + if (DeleteFileA(path)) + return 0; + TRACE(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * scanf (MSVCRT.@) + */ +int __cdecl MSVCRT_scanf(const char *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = MSVCRT_fscanf(MSVCRT_stdin, format, valist); + va_end(valist); + return res; +} + +/********************************************************************* + * rename (MSVCRT.@) + */ +int __cdecl MSVCRT_rename(const char *oldpath,const char *newpath) +{ + TRACE(":from %s to %s\n",oldpath,newpath); + if (MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) + return 0; + TRACE(":failed-last error (%ld)\n",GetLastError()); + MSVCRT__set_errno(GetLastError()); + return -1; +} + +/********************************************************************* + * setbuf (MSVCRT.@) + */ +int __cdecl MSVCRT_setbuf(MSVCRT_FILE* file, char *buf) +{ + TRACE(":file (%p) fd (%d) buf (%p)\n", file, file->_file,buf); + if (buf) + WARN(":user buffer will not be used!\n"); + /* FIXME: no buffering for now */ + return 0; +} + +/********************************************************************* + * tmpnam (MSVCRT.@) + */ +char *__cdecl MSVCRT_tmpnam(char *s) +{ + char tmpbuf[MAX_PATH]; + char* prefix = "TMP"; + if (!GetTempPathA(MAX_PATH,tmpbuf) || + !GetTempFileNameA(tmpbuf,prefix,0,MSVCRT_tmpname)) + { + TRACE(":failed-last error (%ld)\n",GetLastError()); + return NULL; + } + TRACE(":got tmpnam %s\n",MSVCRT_tmpname); + s = MSVCRT_tmpname; + return s; +} + +/********************************************************************* + * tmpfile (MSVCRT.@) + */ +MSVCRT_FILE* __cdecl MSVCRT_tmpfile(void) +{ + char *filename = MSVCRT_tmpnam(NULL); + int fd; + fd = MSVCRT__open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY); + if (fd != -1) + return MSVCRT__alloc_fp(fd); + return NULL; +} +extern int vsnprintf(void *, unsigned int, const void*, va_list); + +/********************************************************************* + * vfprintf (MSVCRT.@) + */ +int __cdecl MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist) +{ + char buf[2048], *mem = buf; + int written, resize = sizeof(buf); + /* There are two conventions for vsnprintf failing: + * Return -1 if we truncated, or + * Return the number of bytes that would have been written + * The code below handles both cases + */ + while ((written = vsnprintf(mem, resize, format, valist)) == -1 || + written > resize) + { + resize = (written == -1 ? resize * 2 : written + 1); + if (mem != buf) + MSVCRT_free (mem); + if (!(mem = (char *)MSVCRT_malloc(resize))) + return MSVCRT_EOF; + } + if (mem != buf) + MSVCRT_free (mem); + return MSVCRT_fwrite(mem, 1, written, file); +} + +/********************************************************************* + * fprintf (MSVCRT.@) + */ +int __cdecl MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...) +{ + va_list valist; + int res; + va_start(valist, format); + res = MSVCRT_vfprintf(file, format, valist); + va_end(valist); + return res; +} + +/********************************************************************* + * printf (MSVCRT.@) + */ +int __cdecl MSVCRT_printf(const char *format, ...) +{ + va_list valist; + int res; + va_start(valist, format); + res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist); + va_end(valist); + return res; +} + diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c new file mode 100644 index 00000000000..6149dfb2170 --- /dev/null +++ b/dlls/msvcrt/heap.c @@ -0,0 +1,250 @@ +/* + * msvcrt.dll heap functions + * + * Copyright 2000 Jon Griffiths + * + * Note: Win32 heap operations are MT safe. We only lock the new + * handler and non atomic heap operations + */ + +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* MT */ +extern CRITICAL_SECTION MSVCRT_heap_cs; +#define LOCK_HEAP EnterCriticalSection(&MSVCRT_heap_cs) +#define UNLOCK_HEAP LeaveCriticalSection(&MSVCRT_heap_cs) + +/* heap function constants */ +#define MSVCRT_HEAPEMPTY -1 +#define MSVCRT_HEAPOK -2 +#define MSVCRT_HEAPBADBEGIN -3 +#define MSVCRT_HEAPBADNODE -4 +#define MSVCRT_HEAPEND -5 +#define MSVCRT_HEAPBADPTR -6 +#define MSVCRT_FREEENTRY 0 +#define MSVCRT_USEDENTRY 1 + +typedef struct MSVCRT_heapinfo +{ + int * _pentry; + size_t _size; + int _useflag; +} MSVCRT_HEAPINFO; + +typedef void (*MSVCRT_new_handler_func)(void); + +static MSVCRT_new_handler_func MSVCRT_new_handler; +static int MSVCRT_new_mode; + +/********************************************************************* + * ??2@YAPAXI@Z (MSVCRT.@) + */ +void *__cdecl MSVCRT_operator_new(unsigned long size) +{ + void *retval = HeapAlloc(GetProcessHeap(), 0, size); + TRACE("(%ld) returning %p\n", size, retval); + LOCK_HEAP; + if(retval && MSVCRT_new_handler) + (*MSVCRT_new_handler)(); + UNLOCK_HEAP; + return retval; +} + +/********************************************************************* + * ??3@YAXPAX@Z (MSVCRT.@) + */ +void __cdecl MSVCRT_operator_delete(void *mem) +{ + TRACE("(%p)\n", mem); + HeapFree(GetProcessHeap(), 0, mem); +} + + +/********************************************************************* + * ?_query_new_handler@@YAP6AHI@ZXZ (MSVCRT.@) + */ +MSVCRT_new_handler_func __cdecl MSVCRT__query_new_handler(void) +{ + return MSVCRT_new_handler; +} + + +/********************************************************************* + * ?_query_new_mode@@YAHXZ (MSVCRT.@) + */ +int __cdecl MSVCRT__query_new_mode(void) +{ + return MSVCRT_new_mode; +} + +/********************************************************************* + * ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z (MSVCRT.@) + */ +MSVCRT_new_handler_func __cdecl MSVCRT__set_new_handler(MSVCRT_new_handler_func func) +{ + MSVCRT_new_handler_func old_handler; + LOCK_HEAP; + old_handler = MSVCRT_new_handler; + MSVCRT_new_handler = func; + UNLOCK_HEAP; + return old_handler; +} + +/********************************************************************* + * ?_set_new_mode@@YAHH@Z (MSVCRT.@) + */ +int __cdecl MSVCRT__set_new_mode(int mode) +{ + int old_mode; + LOCK_HEAP; + old_mode = MSVCRT_new_mode; + MSVCRT_new_mode = mode; + UNLOCK_HEAP; + return old_mode; +} + +/********************************************************************* + * _expand (MSVCRT.@) + */ +void *__cdecl MSVCRT__expand(void *mem, unsigned int size) +{ + return HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, mem, size); +} + +/********************************************************************* + * _heapchk (MSVCRT.@) + */ +int __cdecl MSVCRT__heapchk(void) +{ + if (!HeapValidate( GetProcessHeap(), 0, NULL)) + { + MSVCRT__set_errno(GetLastError()); + return MSVCRT_HEAPBADNODE; + } + return MSVCRT_HEAPOK; +} + +/********************************************************************* + * _heapmin (MSVCRT.@) + */ +int __cdecl MSVCRT__heapmin(void) +{ + if (!HeapCompact( GetProcessHeap(), 0 )) + { + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + MSVCRT__set_errno(GetLastError()); + return -1; + } + return 0; +} + +/********************************************************************* + * _heapwalk (MSVCRT.@) + */ +int __cdecl MSVCRT__heapwalk(MSVCRT_HEAPINFO *next) +{ + PROCESS_HEAP_ENTRY phe; + + LOCK_HEAP; + phe.lpData = next->_pentry; + phe.cbData = next->_size; + phe.wFlags = next->_useflag == MSVCRT_USEDENTRY ? PROCESS_HEAP_ENTRY_BUSY : 0; + + if (phe.lpData && phe.wFlags & PROCESS_HEAP_ENTRY_BUSY && + !HeapValidate( GetProcessHeap(), 0, phe.lpData )) + { + UNLOCK_HEAP; + MSVCRT__set_errno(GetLastError()); + return MSVCRT_HEAPBADNODE; + } + + do + { + if (!HeapWalk( GetProcessHeap(), &phe )) + { + UNLOCK_HEAP; + if (GetLastError() == ERROR_NO_MORE_ITEMS) + return MSVCRT_HEAPEND; + MSVCRT__set_errno(GetLastError()); + if (!phe.lpData) + return MSVCRT_HEAPBADBEGIN; + return MSVCRT_HEAPBADNODE; + } + } while (phe.wFlags & (PROCESS_HEAP_REGION|PROCESS_HEAP_UNCOMMITTED_RANGE)); + + UNLOCK_HEAP; + next->_pentry = phe.lpData; + next->_size = phe.cbData; + next->_useflag = phe.wFlags & PROCESS_HEAP_ENTRY_BUSY ? MSVCRT_USEDENTRY : MSVCRT_FREEENTRY; + return MSVCRT_HEAPOK; +} + +/********************************************************************* + * _heapset (MSVCRT.@) + */ +int __cdecl MSVCRT__heapset(unsigned int value) +{ + int retval; + MSVCRT_HEAPINFO heap; + + memset( &heap, 0, sizeof(MSVCRT_HEAPINFO) ); + LOCK_HEAP; + while ((retval = MSVCRT__heapwalk(&heap)) == MSVCRT_HEAPOK) + { + if (heap._useflag == MSVCRT_FREEENTRY) + memset(heap._pentry, value, heap._size); + } + UNLOCK_HEAP; + return retval == MSVCRT_HEAPEND? MSVCRT_HEAPOK : retval; +} + +/********************************************************************* + * _msize (MSVCRT.@) + */ +long __cdecl MSVCRT__msize(void *mem) +{ + long size = HeapSize(GetProcessHeap(),0,mem); + if (size == -1) + { + WARN(":Probably called with non wine-allocated memory, ret = -1\n"); + /* At least the Win32 crtdll/msvcrt also return -1 in this case */ + } + return size; +} + +/********************************************************************* + * calloc (MSVCRT.@) + */ +void *__cdecl MSVCRT_calloc(unsigned int size, unsigned int count) +{ + return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size * count ); +} + +/********************************************************************* + * free (MSVCRT.@) + */ +void __cdecl MSVCRT_free(void *ptr) +{ + HeapFree(GetProcessHeap(),0,ptr); +} + +/********************************************************************* + * malloc (MSVCRT.@) + */ +void * __cdecl MSVCRT_malloc(unsigned int size) +{ + void *ret = HeapAlloc(GetProcessHeap(),0,size); + if (!ret) + MSVCRT__set_errno(GetLastError()); + return ret; +} + +/********************************************************************* + * realloc (MSVCRT.@) + */ +void *__cdecl MSVCRT_realloc(void *ptr, unsigned int size) +{ + return HeapReAlloc(GetProcessHeap(), 0, ptr, size); +} diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c new file mode 100644 index 00000000000..a26c89b6c28 --- /dev/null +++ b/dlls/msvcrt/locale.c @@ -0,0 +1,528 @@ +/* + * msvcrt.dll locale functions + * + * Copyright 2000 Jon Griffiths + */ +#include "winnt.h" +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* FIXME: Need to hold locale for each LC_* type and aggregate + * string to produce lc_all. + */ +#define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */ +#define MAX_LOCALE_LENGTH 256 +char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH]; +LCID MSVCRT_current_lc_all_lcid; +unsigned int MSVCRT_current_lc_all_cp; + +/* MT */ +extern CRITICAL_SECTION MSVCRT_locale_cs; +#define LOCK_LOCALE EnterCriticalSection(&MSVCRT_locale_cs) +#define UNLOCK_LOCALE LeaveCriticalSection(&MSVCRT_locale_cs) + +/* ctype data modified when the locale changes */ +extern WORD MSVCRT__ctype [257]; +extern WORD MSVCRT_current_ctype[257]; +extern WORD* MSVCRT__pctype; + +/* mbctype data modified when the locale changes */ +extern int MSVCRT___mb_cur_max; +extern unsigned char MSVCRT_mbctype[257]; + +#define MSVCRT_LEADBYTE 0x8000 + +/* Locales */ +#define MSVCRT_LC_ALL 0 +#define MSVCRT_LC_COLLATE 1 +#define MSVCRT_LC_CTYPE 2 +#define MSVCRT_LC_MONETARY 3 +#define MSVCRT_LC_NUMERIC 4 +#define MSVCRT_LC_TIME 5 +#define MSVCRT_LC_MIN MSVCRT_LC_ALL +#define MSVCRT_LC_MAX MSVCRT_LC_TIME + +/* Friendly country strings & iso codes for synonym support. + * Based on MS documentation for setlocale(). + */ +static const char* _country_synonyms[] = +{ + "Hong Kong","HK", + "Hong-Kong","HK", + "New Zealand","NZ", + "New-Zealand","NZ", + "PR China","CN", + "PR-China","CN", + "United Kingdom","GB", + "United-Kingdom","GB", + "Britain","GB", + "England","GB", + "Great Britain","GB", + "United States","US", + "United-States","US", + "America","US" +}; + +/* INTERNAL: Map a synonym to an ISO code */ +static void remap_synonym(char *name) +{ + size_t i; + for (i = 0; i < sizeof(_country_synonyms)/sizeof(char*); i += 2 ) + { + if (!strcasecmp(_country_synonyms[i],name)) + { + TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); + name[0] = _country_synonyms[i+1][0]; + name[1] = _country_synonyms[i+1][1]; + name[2] = '\0'; + return; + } + } +} + +/* Note: Flags are weighted in order of matching importance */ +#define FOUND_LANGUAGE 0x4 +#define FOUND_COUNTRY 0x2 +#define FOUND_CODEPAGE 0x1 + +typedef struct { + char search_language[MAX_ELEM_LEN]; + char search_country[MAX_ELEM_LEN]; + char search_codepage[MAX_ELEM_LEN]; + char found_language[MAX_ELEM_LEN]; + char found_country[MAX_ELEM_LEN]; + char found_codepage[MAX_ELEM_LEN]; + unsigned int match_flags; + LANGID found_lang_id; +} locale_search_t; + +#define CONTINUE_LOOKING TRUE +#define STOP_LOOKING FALSE + +/* INTERNAL: Get and compare locale info with a given string */ +static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp) +{ + buff[0] = 0; + GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE,buff, MAX_ELEM_LEN); + if (!buff[0] || !cmp[0]) + return 0; + /* Partial matches are allowed, e.g. "Germ" matches "Germany" */ + return !strncasecmp(cmp, buff, strlen(cmp)); +} + + +/* INTERNAL: Callback for enumerated languages */ +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +static BOOL CALLBACK +find_best_locale_proc(HMODULE hModule UNUSED, LPCSTR type UNUSED, + LPCSTR name UNUSED, WORD LangID, LONG lParam) +{ + locale_search_t *res = (locale_search_t *)lParam; + const LCID lcid = MAKELCID(LangID, SORT_DEFAULT); + char buff[MAX_ELEM_LEN]; + unsigned int flags = 0; + + if(PRIMARYLANGID(LangID) == LANG_NEUTRAL) + return CONTINUE_LOOKING; + + /* Check Language */ + if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language) || + compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language) || + compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language)) + { + TRACE(":Found language: %s->%s\n", res->search_language, buff); + flags |= FOUND_LANGUAGE; + memcpy(res->found_language,res->search_language,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_LANGUAGE) + { + return CONTINUE_LOOKING; + } + + /* Check Country */ + if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country) || + compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country) || + compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country)) + { + TRACE("Found country:%s->%s\n", res->search_country, buff); + flags |= FOUND_COUNTRY; + memcpy(res->found_country,res->search_country,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_COUNTRY) + { + return CONTINUE_LOOKING; + } + + /* Check codepage */ + if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage) || + (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage))) + { + TRACE("Found codepage:%s->%s\n", res->search_codepage, buff); + flags |= FOUND_CODEPAGE; + memcpy(res->found_codepage,res->search_codepage,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_CODEPAGE) + { + return CONTINUE_LOOKING; + } + + if (flags > res->match_flags) + { + /* Found a better match than previously */ + res->match_flags = flags; + res->found_lang_id = LangID; + } + if (flags & (FOUND_LANGUAGE & FOUND_COUNTRY & FOUND_CODEPAGE)) + { + TRACE(":found exact locale match\n"); + return STOP_LOOKING; + } + return CONTINUE_LOOKING; +} + +extern int atoi(const char *); + +/* Internal: Find the LCID for a locale specification */ +static LCID MSVCRT_locale_to_LCID(locale_search_t* locale) +{ + LCID lcid; + EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, + (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc, + (LONG)locale); + + if (!locale->match_flags) + return 0; + + /* If we were given something that didn't match, fail */ + if (locale->search_country[0] && !(locale->match_flags & FOUND_COUNTRY)) + return 0; + + lcid = MAKELCID(locale->found_lang_id, SORT_DEFAULT); + + /* Populate partial locale, translating LCID to locale string elements */ + if (!locale->found_codepage[0]) + { + /* Even if a codepage is not enumerated for a locale + * it can be set if valid */ + if (locale->search_codepage[0]) + { + if (IsValidCodePage(atoi(locale->search_codepage))) + memcpy(locale->found_codepage,locale->search_codepage,MAX_ELEM_LEN); + else + { + /* Special codepage values: OEM & ANSI */ + if (strcasecmp(locale->search_codepage,"OCP")) + { + GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + if (strcasecmp(locale->search_codepage,"ACP")) + { + GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + else + return 0; + + if (!atoi(locale->found_codepage)) + return 0; + } + } + else + { + /* Prefer ANSI codepages if present */ + GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + if (!locale->found_codepage[0] || !atoi(locale->found_codepage)) + GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + } + GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, + locale->found_language, MAX_ELEM_LEN); + GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY|LOCALE_NOUSEROVERRIDE, + locale->found_country, MAX_ELEM_LEN); + return lcid; +} + +extern int snprintf(char *, int, const char *, ...); + +/* INTERNAL: Set ctype behaviour for a codepage */ +static void MSVCRT_set_ctype(unsigned int codepage, LCID lcid) +{ + CPINFO cp; + + memset(&cp, 0, sizeof(CPINFO)); + + if (GetCPInfo(codepage, &cp)) + { + int i; + char str[3]; + unsigned char *traverse = (unsigned char *)cp.LeadByte; + + memset(MSVCRT_current_ctype, 0, sizeof(MSVCRT__ctype)); + MSVCRT_current_lc_all_cp = codepage; + + /* Switch ctype macros to MBCS if needed */ + MSVCRT___mb_cur_max = cp.MaxCharSize; + + /* Set remaining ctype flags: FIXME: faster way to do this? */ + str[1] = str[2] = 0; + for (i = 0; i < 256; i++) + { + if (!(MSVCRT__pctype[i] & MSVCRT_LEADBYTE)) + { + str[0] = i; + GetStringTypeA(lcid, CT_CTYPE1, str, 1, MSVCRT__pctype + i); + } + } + + /* Set leadbyte flags */ + while (traverse[0] || traverse[1]) + { + for( i = traverse[0]; i <= traverse[1]; i++ ) + MSVCRT_current_ctype[i+1] |= MSVCRT_LEADBYTE; + traverse += 2; + }; + } +} + + +/********************************************************************* + * setlocale (MSVCRT.@) + */ +char *__cdecl MSVCRT_setlocale(int category, const char *locale) +{ + LCID lcid = 0; + locale_search_t lc; + int haveLang, haveCountry, haveCP; + char* next; + int lc_all = 0; + + TRACE("(%d %s)\n",category,locale); + + if (category < MSVCRT_LC_MIN || category > MSVCRT_LC_MAX) + return NULL; + + if (locale == NULL) + { + /* Report the current Locale */ + return MSVCRT_current_lc_all; + } + + LOCK_LOCALE; + + if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') + { + FIXME(":restore previous locale not implemented!\n"); + /* FIXME: Easiest way to do this is parse the string and + * call this function recursively with its elements, + * Where they differ for each lc_ type. + */ + UNLOCK_LOCALE; + return MSVCRT_current_lc_all; + } + + /* Default Locale: Special case handling */ + if (!strlen(locale) || ((toupper(locale[0]) == 'C') && !locale[1])) + { + MSVCRT_current_lc_all[0] = 'C'; + MSVCRT_current_lc_all[1] = '\0'; + MSVCRT_current_lc_all_cp = GetACP(); + + switch (category) { + case MSVCRT_LC_ALL: + lc_all = 1; /* Fall through all cases ... */ + case MSVCRT_LC_COLLATE: + if (!lc_all) break; + case MSVCRT_LC_CTYPE: + /* Restore C locale ctype info */ + MSVCRT___mb_cur_max = 1; + memcpy(MSVCRT_current_ctype, MSVCRT__ctype, sizeof(MSVCRT__ctype)); + memset(MSVCRT_mbctype, 0, sizeof(MSVCRT_mbctype)); + if (!lc_all) break; + case MSVCRT_LC_MONETARY: + if (!lc_all) break; + case MSVCRT_LC_NUMERIC: + if (!lc_all) break; + case MSVCRT_LC_TIME: + } + UNLOCK_LOCALE; + return MSVCRT_current_lc_all; + } + + /* Get locale elements */ + haveLang = haveCountry = haveCP = 0; + memset(&lc,0,sizeof(lc)); + + next = strchr(locale,'_'); + if (next && next != locale) + { + haveLang = 1; + strncpy(lc.search_language,locale,next-locale); + locale += next-locale+1; + } + + next = strchr(locale,'.'); + if (next) + { + haveCP = 1; + if (next == locale) + { + locale++; + strncpy(lc.search_codepage, locale, MAX_ELEM_LEN); + } + else + { + if (haveLang) + { + haveCountry = 1; + strncpy(lc.search_country,locale,next-locale); + locale += next-locale+1; + } + else + { + haveLang = 1; + strncpy(lc.search_language,locale,next-locale); + locale += next-locale+1; + } + strncpy(lc.search_codepage, locale, MAX_ELEM_LEN); + } + } + else + { + if (haveLang) + { + haveCountry = 1; + strncpy(lc.search_country, locale, MAX_ELEM_LEN); + } + else + { + haveLang = 1; + strncpy(lc.search_language, locale, MAX_ELEM_LEN); + } + } + + if (haveCountry) + remap_synonym(lc.search_country); + + if (haveCP && !haveCountry && !haveLang) + { + FIXME(":Codepage only locale not implemented"); + /* FIXME: Use default lang/country and skip locale_to_LCID() + * call below... + */ + UNLOCK_LOCALE; + return NULL; + } + + lcid = MSVCRT_locale_to_LCID(&lc); + + TRACE(":found LCID %ld\n",lcid); + + if (lcid == 0) + { + UNLOCK_LOCALE; + return NULL; + } + + MSVCRT_current_lc_all_lcid = lcid; + + snprintf(MSVCRT_current_lc_all,MAX_LOCALE_LENGTH,"%s_%s.%s", + lc.found_language,lc.found_country,lc.found_codepage); + + switch (category) { + case MSVCRT_LC_ALL: + lc_all = 1; /* Fall through all cases ... */ + case MSVCRT_LC_COLLATE: + if (!lc_all) break; + case MSVCRT_LC_CTYPE: + MSVCRT_set_ctype(atoi(lc.found_codepage),lcid); + if (!lc_all) break; + case MSVCRT_LC_MONETARY: + if (!lc_all) break; + case MSVCRT_LC_NUMERIC: + if (!lc_all) break; + case MSVCRT_LC_TIME: + } + UNLOCK_LOCALE; + return MSVCRT_current_lc_all; +} + + +/********************************************************************* + * _Getdays (MSVCRT.@) + */ +const char *__cdecl MSVCRT__Getdays(void) +{ + static const char *MSVCRT_days = ":Sun:Sunday:Mon:Monday:Tue:Tuesday:Wed:" + "Wednesday:Thu:Thursday:Fri:Friday:Sat:Saturday"; + /* FIXME: Use locale */ + TRACE("(void) semi-stub"); + return MSVCRT_days; +} + +/********************************************************************* + * _Getmonths (MSVCRT.@) + */ +const char *__cdecl MSVCRT__Getmonths(void) +{ + static const char *MSVCRT_months = ":Jan:January:Feb:February:Mar:March:Apr:" + "April:May:May:Jun:June:Jul:July:Aug:August:Sep:September:Oct:" + "October:Nov:November:Dec:December"; + /* FIXME: Use locale */ + TRACE("(void) semi-stub"); + return MSVCRT_months; +} + +/********************************************************************* + * _Getnames (MSVCRT.@) + */ +const char *__cdecl MSVCRT__Getnames(void) +{ + /* FIXME: */ + TRACE("(void) stub"); + return ""; +} + +/********************************************************************* + * _Strftime (MSVCRT.@) + */ +const char *__cdecl MSVCRT__Strftime(char *out, unsigned int len, const char *fmt, + const /* struct tm */ void *tm, void *foo) +{ + /* FIXME: */ + TRACE("(%p %d %s %p %p) stub", out, len, fmt, tm, foo); + return ""; +} + +/* FIXME: MBCP probably belongs in mbcs.c */ + +/********************************************************************* + * _setmbcp (MSVCRT.@) + */ +void __cdecl MSVCRT__setmbcp(int cp) +{ + LOCK_LOCALE; + if (MSVCRT_current_lc_all_cp != cp) + { + /* FIXME: set ctype behaviour for this cp */ + MSVCRT_current_lc_all_cp = cp; + } + UNLOCK_LOCALE; +} + +/********************************************************************* + * _getmbcp (MSVCRT.@) + */ +int __cdecl MSVCRT__getmbcp(void) +{ + return MSVCRT_current_lc_all_cp; +} + diff --git a/dlls/msvcrt/main.c b/dlls/msvcrt/main.c new file mode 100644 index 00000000000..847e8b1f143 --- /dev/null +++ b/dlls/msvcrt/main.c @@ -0,0 +1,173 @@ +/* + * msvcrt.dll initialisation functions + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* Index to TLS */ +DWORD MSVCRT_tls_index; + +/* MT locks */ +CRITICAL_SECTION MSVCRT_heap_cs; +CRITICAL_SECTION MSVCRT_file_cs; +CRITICAL_SECTION MSVCRT_exit_cs; +CRITICAL_SECTION MSVCRT_console_cs; +CRITICAL_SECTION MSVCRT_locale_cs; + +static inline BOOL MSVCRT_init_tls(void); +static inline BOOL MSVCRT_free_tls(void); +static inline void MSVCRT_init_critical_sections(void); +static inline void MSVCRT_free_critical_sections(void); +#ifdef __GNUC__ +const char *MSVCRT_get_reason(DWORD reason) __attribute__((unused)); +#else +const char *MSVCRT_get_reason(DWORD reason); +#endif + +void MSVCRT_init_io(void); +void MSVCRT_init_console(void); +void MSVCRT_free_console(void); +void MSVCRT_init_args(void); +void MSVCRT_free_args(void); +void MSVCRT_init_vtables(void); +char *__cdecl MSVCRT_setlocale(int category, const char *locale); + + +/********************************************************************* + * Init + */ +BOOL WINAPI MSVCRT_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + MSVCRT_thread_data *tls; + + TRACE("(0x%08x, %s, %p) pid(%ld), tid(%ld), tls(%ld)\n", + hinstDLL, MSVCRT_get_reason(fdwReason), lpvReserved, + (long)GetCurrentProcessId(), (long)GetCurrentThreadId(), + (long)MSVCRT_tls_index); + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + if (!MSVCRT_init_tls()) + return FALSE; + MSVCRT_init_vtables(); + MSVCRT_init_critical_sections(); + MSVCRT_init_io(); + MSVCRT_init_console(); + MSVCRT_init_args(); + MSVCRT_setlocale(0, "C"); + TRACE("finished process init\n"); + /* FALL THROUGH for Initial TLS allocation!! */ + case DLL_THREAD_ATTACH: + TRACE("starting thread init\n"); + /* Create TLS */ + tls = (MSVCRT_thread_data*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(MSVCRT_thread_data)); + if (!tls || !TlsSetValue(MSVCRT_tls_index, tls)) + { + ERR("TLS init failed! error = %ld\n", GetLastError()); + return FALSE; + } + TRACE("finished thread init\n"); + break; + case DLL_PROCESS_DETACH: + MSVCRT_free_critical_sections(); + MSVCRT__fcloseall(); + MSVCRT_free_console(); + MSVCRT_free_args(); + if (!MSVCRT_free_tls()) + return FALSE; + TRACE("finished process free\n"); + break; + case DLL_THREAD_DETACH: + /* Free TLS */ + tls = TlsGetValue(MSVCRT_tls_index); + + if (!tls) + { + ERR("TLS free failed! error = %ld\n", GetLastError()); + return FALSE; + } + HeapFree(GetProcessHeap(), 0, tls); + TRACE("finished thread free\n"); + break; + } + return TRUE; +} + +static inline BOOL MSVCRT_init_tls(void) +{ + MSVCRT_tls_index = TlsAlloc(); + + if (MSVCRT_tls_index == TLS_OUT_OF_INDEXES) + { + ERR("TlsAlloc() failed!\n"); + return FALSE; + } + return TRUE; +} + +static inline BOOL MSVCRT_free_tls(void) +{ + if (!TlsFree(MSVCRT_tls_index)) + { + ERR("TlsFree() failed!\n"); + return FALSE; + } + return TRUE; +} + +static inline void MSVCRT_init_critical_sections(void) +{ + InitializeCriticalSectionAndSpinCount(&MSVCRT_heap_cs, 4000); + InitializeCriticalSection(&MSVCRT_file_cs); + InitializeCriticalSection(&MSVCRT_exit_cs); + InitializeCriticalSection(&MSVCRT_console_cs); + InitializeCriticalSection(&MSVCRT_locale_cs); +} + +static inline void MSVCRT_free_critical_sections(void) +{ + DeleteCriticalSection(&MSVCRT_locale_cs); + DeleteCriticalSection(&MSVCRT_console_cs); + DeleteCriticalSection(&MSVCRT_exit_cs); + DeleteCriticalSection(&MSVCRT_file_cs); + DeleteCriticalSection(&MSVCRT_heap_cs); +} + +const char *MSVCRT_get_reason(DWORD reason) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: return "DLL_PROCESS_ATTACH"; + case DLL_PROCESS_DETACH: return "DLL_PROCESS_DETACH"; + case DLL_THREAD_ATTACH: return "DLL_THREAD_ATTACH"; + case DLL_THREAD_DETACH: return "DLL_THREAD_DETACH"; + } + return "UNKNOWN"; +} + + +/********************************************************************* + * Fixup functions + * + * Anything not really understood but needed to make the DLL work + */ +void MSVCRT_I10_OUTPUT(void) +{ + /* FIXME: This is probably data, not a function */ +} + +void MSVCRT___unDName(void) +{ + /* Called by all VC compiled progs on startup. No idea what it does */ +} + +void MSVCRT___unDNameEx(void) +{ + /* As above */ +} + diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c new file mode 100644 index 00000000000..e89ad77c885 --- /dev/null +++ b/dlls/msvcrt/math.c @@ -0,0 +1,729 @@ +/* + * msvcrt.dll math functions + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" +#include "ms_errno.h" + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 +#include +#ifdef HAVE_IEEEFP_H +#include +#endif + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +#ifndef HAVE_FINITE +#ifndef finite /* Could be a macro */ +#ifdef isfinite +#define finite(x) isfinite(x) +#else +#define finite(x) (!isnan(x)) /* At least catch some cases */ +#endif +#endif +#endif + +#ifndef signbit +#define signbit(x) 0 +#endif + +/* fpclass constants */ +#define _FPCLASS_SNAN 1 +#define _FPCLASS_QNAN 2 +#define _FPCLASS_NINF 4 +#define _FPCLASS_NN 8 +#define _FPCLASS_ND 16 +#define _FPCLASS_NZ 32 +#define _FPCLASS_PZ 64 +#define _FPCLASS_PD 128 +#define _FPCLASS_PN 256 +#define _FPCLASS_PINF 512 + +/* _statusfp bit flags */ +#define _SW_INEXACT 0x1 +#define _SW_UNDERFLOW 0x2 +#define _SW_OVERFLOW 0x4 +#define _SW_ZERODIVIDE 0x8 +#define _SW_INVALID 0x10 +#define _SW_DENORMAL 0x80000 + +/* _controlfp masks and bitflags - x86 only so far*/ +#ifdef __i386__ +#define _MCW_EM 0x8001f +#define _EM_INEXACT 0x1 +#define _EM_UNDERFLOW 0x2 +#define _EM_OVERFLOW 0x4 +#define _EM_ZERODIVIDE 0x8 +#define _EM_INVALID 0x10 + +#define _MCW_RC 0x300 +#define _RC_NEAR 0x0 +#define _RC_DOWN 0x100 +#define _RC_UP 0x200 +#define _RC_CHOP 0x300 + +#define _MCW_PC 0x30000 +#define _PC_64 0x0 +#define _PC_53 0x10000 +#define _PC_24 0x20000 + +#define _MCW_IC 0x40000 +#define _IC_AFFINE 0x40000 +#define _IC_PROJECTIVE 0x0 + +#define _EM_DENORMAL 0x80000 +#endif + +typedef struct __MSVCRT_complex +{ + double real; + double imaginary; +} MSVCRT_complex; + +typedef struct __MSVCRT_exception +{ + int type; + char *name; + double arg1; + double arg2; + double retval; +} MSVCRT_exception; + + +typedef int (__cdecl *MSVCRT_matherr_func)(MSVCRT_exception *); + +static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL; + +#if defined(__GNUC__) && defined(__i386__) + +#define FPU_DOUBLE(var) double var; \ + __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var) : ) +#define FPU_DOUBLES(var1,var2) double var1,var2; \ + __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var2) : ); \ + __asm__ __volatile__( "fstpl %0;fwait" : "=m" (var1) : ) + +/********************************************************************* + * _CIacos (MSVCRT.@) + */ +double __cdecl MSVCRT__CIacos(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return acos(x); +} + +/********************************************************************* + * _CIasin (MSVCRT.@) + */ +double __cdecl MSVCRT__CIasin(void) +{ + FPU_DOUBLE(x); + if (x < -1.0 || x > 1.0 || !finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + + return asin(x); +} + +/********************************************************************* + * _CIatan (MSVCRT.@) + */ +double __cdecl MSVCRT__CIatan(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return atan(x); +} + +/********************************************************************* + * _CIatan2 (MSVCRT.@) + */ +double __cdecl MSVCRT__CIatan2(void) +{ + FPU_DOUBLES(x,y); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return atan2(x,y); +} + +/********************************************************************* + * _CIcos (MSVCRT.@) + */ +double __cdecl MSVCRT__CIcos(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return cos(x); +} + +/********************************************************************* + * _CIcosh (MSVCRT.@) + */ +double __cdecl MSVCRT__CIcosh(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return cosh(x); +} + +/********************************************************************* + * _CIexp (MSVCRT.@) + */ +double __cdecl MSVCRT__CIexp(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return exp(x); +} + +/********************************************************************* + * _CIfmod (MSVCRT.@) + */ +double __cdecl MSVCRT__CIfmod(void) +{ + FPU_DOUBLES(x,y); + if (!finite(x) || !finite(y)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return fmod(x,y); +} + +/********************************************************************* + * _CIlog (MSVCRT.@) + */ +double __cdecl MSVCRT__CIlog(void) +{ + FPU_DOUBLE(x); + if (x < 0.0 || !finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + if (x == 0.0) SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return log(x); +} + +/********************************************************************* + * _CIlog10 (MSVCRT.@) + */ +double __cdecl MSVCRT__CIlog10(void) +{ + FPU_DOUBLE(x); + if (x < 0.0 || !finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + if (x == 0.0) SET_THREAD_VAR(errno,MSVCRT_ERANGE); + return log10(x); +} + +/********************************************************************* + * _CIpow (MSVCRT.@) + */ +double __cdecl MSVCRT__CIpow(void) +{ + double z; + FPU_DOUBLES(x,y); + /* FIXME: If x < 0 and y is not integral, set EDOM */ + z = pow(x,y); + if (!finite(z)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return z; +} + +/********************************************************************* + * _CIsin (MSVCRT.@) + */ +double __cdecl MSVCRT__CIsin(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return sin(x); +} + +/********************************************************************* + * _CIsinh (MSVCRT.@) + */ +double __cdecl MSVCRT__CIsinh(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return sinh(x); +} + +/********************************************************************* + * _CIsqrt (MSVCRT.@) + */ +double __cdecl MSVCRT__CIsqrt(void) +{ + FPU_DOUBLE(x); + if (x < 0.0 || !finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return sqrt(x); +} + +/********************************************************************* + * _CItan (MSVCRT.@) + */ +double __cdecl MSVCRT__CItan(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return tan(x); +} + +/********************************************************************* + * _CItanh (MSVCRT.@) + */ +double __cdecl MSVCRT__CItanh(void) +{ + FPU_DOUBLE(x); + if (!finite(x)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return tanh(x); +} + +#else /* defined(__GNUC__) && defined(__i386__) */ + +/* The above cannot be called on non x86 platforms, stub them for linking */ + +#define IX86_ONLY(func) double __cdecl MSVCRT_##func(void) { return 0.0; } + +IX86_ONLY(_CIacos) +IX86_ONLY(_CIasin) +IX86_ONLY(_CIatan) +IX86_ONLY(_CIatan2) +IX86_ONLY(_CIcos) +IX86_ONLY(_CIcosh) +IX86_ONLY(_CIexp) +IX86_ONLY(_CIfmod) +IX86_ONLY(_CIlog) +IX86_ONLY(_CIlog10) +IX86_ONLY(_CIpow) +IX86_ONLY(_CIsin) +IX86_ONLY(_CIsinh) +IX86_ONLY(_CIsqrt) +IX86_ONLY(_CItan) +IX86_ONLY(_CItanh) + +#endif /* defined(__GNUC__) && defined(__i386__) */ + +/********************************************************************* + * _fpclass (MSVCRT.@) + */ +int __cdecl MSVCRT__fpclass(double num) +{ +#if defined(HAVE_FPCLASS) || defined(fpclass) + switch (fpclass( num )) + { + case FP_SNAN: return _FPCLASS_SNAN; + case FP_QNAN: return _FPCLASS_QNAN; + case FP_NINF: return _FPCLASS_NINF; + case FP_PINF: return _FPCLASS_PINF; + case FP_NDENORM: return _FPCLASS_ND; + case FP_PDENORM: return _FPCLASS_PD; + case FP_NZERO: return _FPCLASS_NZ; + case FP_PZERO: return _FPCLASS_PZ; + case FP_NNORM: return _FPCLASS_NN; + } + return _FPCLASS_PN; +#elif defined (fpclassify) + switch (fpclassify( num )) + { + case FP_NAN: return _FPCLASS_QNAN; + case FP_INFINITE: return signbit(num) ? _FPCLASS_NINF : _FPCLASS_PINF; + case FP_SUBNORMAL: return signbit(num) ?_FPCLASS_ND : _FPCLASS_PD; + case FP_ZERO: return signbit(num) ? _FPCLASS_NZ : _FPCLASS_PZ; + } + return signbit(num) ? _FPCLASS_NN : _FPCLASS_PN; +#else + if (!finite(num)) + return _FPCLASS_QNAN; + return num == 0.0 ? _FPCLASS_PZ : (d < 0 ? _FPCLASS_NN : _FPCLASS_PN); +#endif +} + +/********************************************************************* + * _rotl (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__rotl(unsigned int num, int shift) +{ + shift &= 31; + return (num << shift) | (num >> (32-shift)); +} + +/********************************************************************* + * _logb (MSVCRT.@) + */ +double __cdecl MSVCRT__logb(double num) +{ + if (!finite(num)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return logb(num); +} + +/********************************************************************* + * _lrotl (MSVCRT.@) + */ +unsigned long __cdecl MSVCRT__lrotl(unsigned long num, int shift) +{ + shift &= 0x1f; + return (num << shift) | (num >> (32-shift)); +} + +/********************************************************************* + * _lrotr (MSVCRT.@) + */ +unsigned long __cdecl MSVCRT__lrotr(unsigned long num, int shift) +{ + shift &= 0x1f; + return (num >> shift) | (num << (32-shift)); +} + +/********************************************************************* + * _rotr (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__rotr(unsigned int num, int shift) +{ + shift &= 0x1f; + return (num >> shift) | (num << (32-shift)); +} + +/********************************************************************* + * _scalb (MSVCRT.@) + */ +double __cdecl MSVCRT__scalb(double num, long power) +{ + /* Note - Can't forward directly as libc expects y as double */ + double dblpower = (double)power; + if (!finite(num)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + return scalb(num, dblpower); +} + +/********************************************************************* + * _matherr (MSVCRT.@) + */ +int __cdecl MSVCRT__matherr(MSVCRT_exception *e) +{ + if (e) + TRACE("(%p = %d, %s, %g %g %g)\n",e, e->type, e->name, e->arg1, e->arg2, + e->retval); + else + TRACE("(null)\n"); + if (MSVCRT_default_matherr_func) + return MSVCRT_default_matherr_func(e); + ERR(":Unhandled math error!\n"); + return 0; +} + +/********************************************************************* + * __setusermatherr (MSVCRT.@) + */ +void __cdecl MSVCRT___setusermatherr(MSVCRT_matherr_func func) +{ + MSVCRT_default_matherr_func = func; + TRACE(":new matherr handler %p\n", func); +} + +/********************************************************************** + * _statusfp (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__statusfp(void) +{ + unsigned int retVal = 0; +#if defined(__GNUC__) && defined(__i386__) + unsigned int fpword; + + __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : ); + if (fpword & 0x1) retVal |= _SW_INVALID; + if (fpword & 0x2) retVal |= _SW_DENORMAL; + if (fpword & 0x4) retVal |= _SW_ZERODIVIDE; + if (fpword & 0x8) retVal |= _SW_OVERFLOW; + if (fpword & 0x10) retVal |= _SW_UNDERFLOW; + if (fpword & 0x20) retVal |= _SW_INEXACT; +#else + FIXME(":Not implemented!\n"); +#endif + return retVal; +} + +/********************************************************************* + * _clearfp (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__clearfp(void) +{ + UINT retVal = MSVCRT__statusfp(); +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__( "fnclex" ); +#else + FIXME(":Not Implemented\n"); +#endif + return retVal; +} + +/********************************************************************* + * ldexp (MSVCRT.@) + */ +double __cdecl MSVCRT_ldexp(double num, long exp) +{ + double z = ldexp(num,exp); + + if (!finite(z)) + SET_THREAD_VAR(errno,MSVCRT_ERANGE); + else if (z == 0 && signbit(z)) + z = 0.0; /* Convert -0 -> +0 */ + return z; +} + +/********************************************************************* + * _cabs (MSVCRT.@) + */ +double __cdecl MSVCRT__cabs(MSVCRT_complex num) +{ + return sqrt(num.real * num.imaginary + num.real * num.imaginary); +} + +/********************************************************************* + * _chgsign (MSVCRT.@) + */ +double __cdecl MSVCRT__chgsign(double num) +{ + /* FIXME: +-infinity,Nan not tested */ + return -num; +} + +/********************************************************************* + * _control87 (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__control87(unsigned int newval, unsigned int mask) +{ +#if defined(__GNUC__) && defined(__i386__) + UINT fpword, flags = 0; + + /* Get fp control word */ + __asm__ __volatile__( "fstsw %0" : "=m" (fpword) : ); + + /* Convert into mask constants */ + if (fpword & 0x1) flags |= _EM_INVALID; + if (fpword & 0x2) flags |= _EM_DENORMAL; + if (fpword & 0x4) flags |= _EM_ZERODIVIDE; + if (fpword & 0x8) flags |= _EM_OVERFLOW; + if (fpword & 0x10) flags |= _EM_UNDERFLOW; + if (fpword & 0x20) flags |= _EM_INEXACT; + switch(fpword & 0xC00) { + case 0xC00: flags |= _RC_UP|_RC_DOWN; break; + case 0x800: flags |= _RC_UP; break; + case 0x400: flags |= _RC_DOWN; break; + } + switch(fpword & 0x300) { + case 0x0: flags |= _PC_24; break; + case 0x200: flags |= _PC_53; break; + case 0x300: flags |= _PC_64; break; + } + if (fpword & 0x1000) flags |= _IC_AFFINE; + + /* Mask with parameters */ + flags = (flags & ~mask) | (newval & mask); + + /* Convert (masked) value back to fp word */ + fpword = 0; + if (flags & _EM_INVALID) fpword |= 0x1; + if (flags & _EM_DENORMAL) fpword |= 0x2; + if (flags & _EM_ZERODIVIDE) fpword |= 0x4; + if (flags & _EM_OVERFLOW) fpword |= 0x8; + if (flags & _EM_UNDERFLOW) fpword |= 0x10; + if (flags & _EM_INEXACT) fpword |= 0x20; + switch(flags & (_RC_UP | _RC_DOWN)) { + case _RC_UP|_RC_DOWN: fpword |= 0xC00; break; + case _RC_UP: fpword |= 0x800; break; + case _RC_DOWN: fpword |= 0x400; break; + } + switch (flags & (_PC_24 | _PC_53)) { + case _PC_64: fpword |= 0x300; break; + case _PC_53: fpword |= 0x200; break; + case _PC_24: fpword |= 0x0; break; + } + if (!(flags & _IC_AFFINE)) fpword |= 0x1000; + + /* Put fp control word */ + __asm__ __volatile__( "fldcw %0" : : "m" (fpword) ); + return fpword; +#else + return MSVCRT__controlfp( newVal, mask ); +#endif +} + +/********************************************************************* + * _controlfp (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__controlfp(unsigned int newval, unsigned int mask) +{ +#if defined(__GNUC__) && defined(__i386__) + return MSVCRT__control87( newval, mask ); +#else + FIXME(":Not Implemented!\n"); + return 0; +#endif +} + +/********************************************************************* + * _copysign (MSVCRT.@) + */ +double __cdecl MSVCRT__copysign(double num, double sign) +{ + /* FIXME: Behaviour for Nan/Inf? */ + if (sign < 0.0) + return num < 0.0 ? num : -num; + return num < 0.0 ? -num : num; +} + +/********************************************************************* + * _finite (MSVCRT.@) + */ +int __cdecl MSVCRT__finite(double num) +{ + return (finite(num)?1:0); /* See comment for _isnan() */ +} + +/********************************************************************* + * _fpreset (MSVCRT.@) + */ +void __cdecl MSVCRT__fpreset(void) +{ +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__( "fninit" ); +#else + FIXME(":Not Implemented!\n"); +#endif +} + +/********************************************************************* + * _isnan (MSVCRT.@) + */ +INT __cdecl MSVCRT__isnan(double num) +{ + /* Some implementations return -1 for true(glibc), msvcrt/crtdll return 1. + * Do the same, as the result may be used in calculations + */ + return isnan(num) ? 1 : 0; +} + +/********************************************************************* + * _y0 (MSVCRT.@) + */ +double __cdecl MSVCRT__y0(double num) +{ + double retval; + if (!finite(num)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = y0(num); + if (MSVCRT__fpclass(retval) == _FPCLASS_NINF) + { + SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = sqrt(-1); + } + return retval; +} + +/********************************************************************* + * _y1 (MSVCRT.@) + */ +double __cdecl MSVCRT__y1(double num) +{ + double retval; + if (!finite(num)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = y1(num); + if (MSVCRT__fpclass(retval) == _FPCLASS_NINF) + { + SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = sqrt(-1); + } + return retval; +} + +/********************************************************************* + * _yn (MSVCRT.@) + */ +double __cdecl MSVCRT__yn(int order, double num) +{ + double retval; + if (!finite(num)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = yn(order,num); + if (MSVCRT__fpclass(retval) == _FPCLASS_NINF) + { + SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = sqrt(-1); + } + return retval; +} + +/********************************************************************* + * _nextafter (MSVCRT.@) + */ +double __cdecl MSVCRT__nextafter(double num, double next) +{ + double retval; + if (!finite(num) || !finite(next)) SET_THREAD_VAR(errno,MSVCRT_EDOM); + retval = nextafter(num,next); + return retval; +} + +#include /* div_t, ldiv_t */ + +/********************************************************************* + * div (MSVCRT.@) + * VERSION + * [i386] Windows binary compatible - returns the struct in eax/edx. + */ +#ifdef __i386__ +LONGLONG __cdecl MSVCRT_div(int num, int denom) +{ + LONGLONG retval; + div_t dt = div(num,denom); + retval = ((LONGLONG)dt.rem << 32) | dt.quot; + return retval; +} +#else +/********************************************************************* + * div (MSVCRT.@) + * VERSION + * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility + */ +div_t __cdecl MSVCRT_div(int num, int denom) +{ + return div(num,denom); +} +#endif /* ifdef __i386__ */ + + +/********************************************************************* + * ldiv (MSVCRT.@) + * VERSION + * [i386] Windows binary compatible - returns the struct in eax/edx. + */ +#ifdef __i386__ +ULONGLONG __cdecl MSVCRT_ldiv(long num, long denom) +{ + ULONGLONG retval; + ldiv_t ldt = ldiv(num,denom); + retval = ((ULONGLONG)ldt.rem << 32) | (ULONG)ldt.quot; + return retval; +} +#else +/********************************************************************* + * ldiv (MSVCRT.@) + * VERSION + * [!i386] Non-x86 can't run win32 apps so we don't need binary compatibility + */ +ldiv_t __cdecl MSVCRT_ldiv(long num, long denom) +{ + return ldiv(num,denom); +} +#endif /* ifdef __i386__ */ + +/* I _think_ these functions are intended to work around the pentium fdiv bug */ +#define DUMMY_FUNC(x) void __cdecl MSVCRT_##x(void) { TRACE("stub"); } +DUMMY_FUNC(_adj_fdiv_m16i) +DUMMY_FUNC(_adj_fdiv_m32) +DUMMY_FUNC(_adj_fdiv_m32i) +DUMMY_FUNC(_adj_fdiv_m64) +DUMMY_FUNC(_adj_fdiv_r) +DUMMY_FUNC(_adj_fdivr_m16i) +DUMMY_FUNC(_adj_fdivr_m32) +DUMMY_FUNC(_adj_fdivr_m32i) +DUMMY_FUNC(_adj_fdivr_m64) +DUMMY_FUNC(_adj_fpatan) +DUMMY_FUNC(_adj_fprem) +DUMMY_FUNC(_adj_fprem1) +DUMMY_FUNC(_adj_fptan) +DUMMY_FUNC(_adjust_fdiv) +DUMMY_FUNC(_safe_fdiv); +DUMMY_FUNC(_safe_fdivr); +DUMMY_FUNC(_safe_fprem); +DUMMY_FUNC(_safe_fprem1); + diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c new file mode 100644 index 00000000000..5141b69bdbf --- /dev/null +++ b/dlls/msvcrt/mbcs.c @@ -0,0 +1,495 @@ +/* + * msvcrt.dll mbcs functions + * + * Copyright 1999 Alexandre Julliard + * Copyright 2000 Jon Griffths + * + * FIXME + * Not currently binary compatable with win32. MSVCRT_mbctype must be + * populated correctly and the ismb* functions should reference it. + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +unsigned char MSVCRT_mbctype[257]; +int MSVCRT___mb_cur_max = 1; + +int __cdecl MSVCRT_isleadbyte(int); +char *__cdecl MSVCRT__strset(char *, int); +char *__cdecl MSVCRT__strnset(char *, int, unsigned int); +extern unsigned int MSVCRT_current_lc_all_cp; + + +/********************************************************************* + * __p__mbctype (MSVCRT.@) + */ +unsigned char *__cdecl MSVCRT___p__mbctype(void) +{ + return MSVCRT_mbctype; +} + +/********************************************************************* + * __p___mb_cur_max(MSVCRT.@) + */ +int *__cdecl MSVCRT___p___mb_cur_max(void) +{ + return &MSVCRT___mb_cur_max; +} + +/********************************************************************* + * _mbsnextc(MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__mbsnextc(const char *str) +{ + if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str)) + return *str << 8 | str[1]; + return *str; /* ASCII CP or SB char */ +} + +/********************************************************************* + * _mbscmp(MSVCRT.@) + */ +int __cdecl MSVCRT__mbscmp(const char *str, const char *cmp) +{ + if(MSVCRT___mb_cur_max > 1) + { + unsigned int strc, cmpc; + do { + if(!*str) + return *cmp ? -1 : 0; + if(!*cmp) + return 1; + strc = MSVCRT__mbsnextc(str); + cmpc = MSVCRT__mbsnextc(cmp); + if(strc != cmpc) + return strc < cmpc ? -1 : 1; + str +=(strc > 255) ? 2 : 1; + cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */ + } while(1); + } + return strcmp(str, cmp); /* ASCII CP */ +} + +/********************************************************************* + * _mbsicmp(MSVCRT.@) + */ +int __cdecl MSVCRT__mbsicmp(const char *str, const char *cmp) +{ + /* FIXME: No tolower() for mb strings yet */ + if(MSVCRT___mb_cur_max > 1) + return MSVCRT__mbscmp(str, cmp); + return strcasecmp(str, cmp); /* ASCII CP */ +} + +/********************************************************************* + * _mbsncmp (MSVCRT.@) + */ +int __cdecl MSVCRT__mbsncmp(const char *str, const char *cmp, unsigned int len) +{ + if(!len) + return 0; + + if(MSVCRT___mb_cur_max > 1) + { + unsigned int strc, cmpc; + while(len--) + { + if(!*str) + return *cmp ? -1 : 0; + if(!*cmp) + return 1; + strc = MSVCRT__mbsnextc(str); + cmpc = MSVCRT__mbsnextc(cmp); + if(strc != cmpc) + return strc < cmpc ? -1 : 1; + str +=(strc > 255) ? 2 : 1; + cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */ + } + return 0; /* Matched len chars */ + } + return strncmp(str, cmp, len); /* ASCII CP */ +} + +/********************************************************************* + * _mbsnicmp(MSVCRT.@) + * + * Compare two multibyte strings case insensitively to 'len' characters. + */ +int __cdecl MSVCRT__mbsnicmp(const char *str, const char *cmp, unsigned int len) +{ + /* FIXME: No tolower() for mb strings yet */ + if(MSVCRT___mb_cur_max > 1) + return MSVCRT__mbsncmp(str, cmp, len); + return strncasecmp(str, cmp, len); /* ASCII CP */ +} + +/********************************************************************* + * _mbsinc(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsinc(const char *str) +{ + if(MSVCRT___mb_cur_max > 1 && + MSVCRT_isleadbyte(*str)) + return(char *)str + 2; /* MB char */ + + return(char *)str + 1; /* ASCII CP or SB char */ +} + +/********************************************************************* + * _mbsninc(MSVCRT.@) + */ +char *MSVCRT__mbsninc(const char *str, unsigned int num) +{ + if(!str || num < 1) + return NULL; + if(MSVCRT___mb_cur_max > 1) + { + while(num--) + str = MSVCRT__mbsinc(str); + return(char *)str; + } + return(char *)str + num; /* ASCII CP */ +} + +/********************************************************************* + * _mbslen(MSVCRT.206) + */ +int __cdecl MSVCRT__mbslen(const char *str) +{ + if(MSVCRT___mb_cur_max > 1) + { + int len = 0; + while(*str) + { + str += MSVCRT_isleadbyte(*str) ? 2 : 1; + len++; + } + return len; + } + return strlen(str); /* ASCII CP */ +} + +/********************************************************************* + * _mbsrchr(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsrchr(const char *s,unsigned int x) +{ + /* FIXME: handle multibyte strings */ + return strrchr(s,x); +} + +/********************************************************************* + * mbtowc(MSVCRT.@) + */ +int __cdecl MSVCRT_mbtowc(WCHAR *dst, const char *str, unsigned int n) +{ + if(n <= 0 || !str) + return 0; + if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1)) + return 0; + /* return the number of bytes from src that have been used */ + if(!*str) + return 0; + if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1]) + return 2; + return 1; +} + +/********************************************************************* + * _mbccpy(MSVCRT.@) + */ +void __cdecl MSVCRT__mbccpy(char *dest, char *src) +{ + *dest++ = *src; + if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src)) + *dest = *++src; /* MB char */ +} + +/********************************************************************* + * _mbbtombc(MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__mbbtombc(unsigned int c) +{ + if(MSVCRT___mb_cur_max > 1 && + ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf))) + { + /* FIXME: I can't get this function to return anything + * different to what I pass it... + */ + } + return c; /* ASCII CP or no MB char */ +} + +/********************************************************************* + * _mbclen(MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__mbclen(const char *str) +{ + return MSVCRT_isleadbyte(*str) ? 2 : 1; +} + +/********************************************************************* + * _ismbbkana(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbbkana(unsigned int c) +{ + /* FIXME: use lc_ctype when supported, not lc_all */ + if(MSVCRT_current_lc_all_cp == 932) + { + /* Japanese/Katakana, CP 932 */ + return(c >= 0xa1 && c <= 0xdf); + } + return 0; +} + +/********************************************************************* + * _ismbchira(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbchira(unsigned int c) +{ + /* FIXME: use lc_ctype when supported, not lc_all */ + if(MSVCRT_current_lc_all_cp == 932) + { + /* Japanese/Hiragana, CP 932 */ + return(c >= 0x829f && c <= 0x82f1); + } + return 0; +} + +/********************************************************************* + * _ismbckata(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbckata(unsigned int c) +{ + /* FIXME: use lc_ctype when supported, not lc_all */ + if(MSVCRT_current_lc_all_cp == 932) + { + if(c < 256) + return MSVCRT__ismbbkana(c); + /* Japanese/Katakana, CP 932 */ + return(c >= 0x8340 && c <= 0x8396 && c != 0x837f); + } + return 0; +} + +/********************************************************************* + * _ismbblead(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbblead(unsigned int c) +{ + /* FIXME: should reference MSVCRT_mbctype */ + return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c); +} + + +/********************************************************************* + * _ismbbtrail(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbbtrail(unsigned int c) +{ + /* FIXME: should reference MSVCRT_mbctype */ + return !MSVCRT__ismbblead(c); +} + +/********************************************************************* + * _ismbslead(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbslead(const char *start, const char *str) +{ + /* Lead bytes can also be trail bytes if caller messed up + * iterating through the string... + */ + if(MSVCRT___mb_cur_max > 1) + { + while(start < str) + start += MSVCRT_isleadbyte(*str) ? 2 : 1; + + if(start == str) + return MSVCRT_isleadbyte(*str); + } + return 0; /* Must have been a trail, we skipped it */ +} + +/********************************************************************* + * _ismbstrail(MSVCRT.@) + */ +int __cdecl MSVCRT__ismbstrail(const char *start, const char *str) +{ + /* Must not be a lead, and must be preceeded by one */ + return !MSVCRT__ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]); +} + +/********************************************************************* + * _mbsdec(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsdec(const char *start, const char *cur) +{ + if(MSVCRT___mb_cur_max > 1) + return(char *)(MSVCRT__ismbstrail(start,cur-1) ? cur - 2 : cur -1); + + return(char *)cur - 1; /* ASCII CP or SB char */ +} + +/********************************************************************* + * _mbsset(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsset(char *str, unsigned int c) +{ + char *ret = str; + + if(MSVCRT___mb_cur_max == 1 || c < 256) + return MSVCRT__strset(str, c); /* ASCII CP or SB char */ + + c &= 0xffff; /* Strip high bits */ + + while(str[0] && str[1]) + { + *str++ = c >> 8; + *str++ = c & 0xff; + } + if(str[0]) + str[0] = '\0'; /* FIXME: OK to shorten? */ + + return ret; +} + +/********************************************************************* + * _mbsnset(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsnset(char *str, unsigned int c, unsigned int len) +{ + char *ret = str; + + if(!len) + return ret; + + if(MSVCRT___mb_cur_max == 1 || c < 256) + return MSVCRT__strnset(str, c, len); /* ASCII CP or SB char */ + + c &= 0xffff; /* Strip high bits */ + + while(str[0] && str[1] && len--) + { + *str++ = c >> 8; + *str++ = c & 0xff; + } + if(len && str[0]) + str[0] = '\0'; /* FIXME: OK to shorten? */ + + return ret; +} + +/********************************************************************* + * _mbstrlen(MSVCRT.@) + */ +int __cdecl MSVCRT__mbstrlen(const char *str) +{ + if(MSVCRT___mb_cur_max > 1) + { + int len = 0; + while(*str) + { + str += MSVCRT_isleadbyte(*str) ? 2 : 1; + len++; + } + return len; + } + return strlen(str); /* ASCII CP */ +} + +/********************************************************************* + * _mbsncpy(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsncpy(char *dst, const char *src, unsigned int len) +{ + if(!len) + return dst; + if(MSVCRT___mb_cur_max > 1) + { + char *ret = dst; + while(src[0] && src[1] && len--) + { + *dst++ = *src++; + *dst++ = *src++; + } + if(len--) + { + *dst++ = *src++; /* Last char or '\0' */ + while(len--) + *dst++ = '\0'; + } + return ret; + } + return strncpy(dst, src, len); /* ASCII CP */ +} + +/********************************************************************* + * _mbschr(MSVCRT.@) + * + * Find a multibyte character in a multibyte string. + */ +char *__cdecl MSVCRT__mbschr(const char *str, unsigned int c) +{ + if(MSVCRT___mb_cur_max > 1) + { + unsigned int next; + while((next = MSVCRT__mbsnextc(str))) + { + if(next == c) + return(char *)str; + str += next > 255 ? 2 : 1; + } + return c ? NULL :(char *)str; + } + return strchr(str, c); /* ASCII CP */ +} + +/********************************************************************* + * _mbsnccnt(MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__mbsnccnt(const char *str, unsigned int len) +{ + int ret = 0; + + if(MSVCRT___mb_cur_max > 1) + { + while(*str && len-- > 0) + { + if(MSVCRT_isleadbyte(*str)) + { + str++; + len--; + } + ret++; + str++; + } + return ret; + } + return min(strlen(str), len); /* ASCII CP */ +} + + +/********************************************************************* + * _mbsncat(MSVCRT.@) + */ +char *__cdecl MSVCRT__mbsncat(char *dst, const char *src, unsigned int len) +{ + if(MSVCRT___mb_cur_max > 1) + { + char *res = dst; + dst += MSVCRT__mbslen(dst); + while(*src && len--) + { + *dst = *src; + if(MSVCRT_isleadbyte(*src)) + *++dst = *++src; + dst++; + src++; + } + *dst++ = '\0'; + return res; + } + return strncat(dst, src, len); /* ASCII CP */ +} + diff --git a/dlls/msvcrt/misc.c b/dlls/msvcrt/misc.c new file mode 100644 index 00000000000..11fe3439e53 --- /dev/null +++ b/dlls/msvcrt/misc.c @@ -0,0 +1,85 @@ +/* + * msvcrt.dll misc functions + * + * Copyright 2000 Jon Griffiths + */ + +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +typedef INT (__cdecl *MSVCRT_comp_func)(LPCVOID, LPCVOID ); + +/********************************************************************* + * _beep (MSVCRT.@) + */ +void __cdecl MSVCRT__beep( unsigned int freq, unsigned int duration) +{ + TRACE(":Freq %d, Duration %d\n",freq,duration); + Beep(freq, duration); +} + +extern int rand(void); + +/********************************************************************* + * rand (MSVCRT.@) + */ +INT __cdecl MSVCRT_rand() +{ + return (rand() & 0x7fff); +} + +/********************************************************************* + * _sleep (MSVCRT.@) + */ +VOID __cdecl MSVCRT__sleep(ULONG timeout) +{ + TRACE("MSVCRT__sleep for %ld milliseconds\n",timeout); + Sleep((timeout)?timeout:1); +} + +/********************************************************************* + * _lfind (MSVCRT.@) + */ +void* __cdecl MSVCRT__lfind(const void * match, const void * start, +unsigned int * array_size,unsigned int elem_size, MSVCRT_comp_func cf) +{ + unsigned int size = *array_size; + if (size) + do + { + if (cf(match, start) == 0) + return (void *)start; /* found */ + start += elem_size; + } while (--size); + return NULL; +} + +/********************************************************************* + * _lsearch (MSVCRT.@) + */ +void * __cdecl MSVCRT__lsearch(const void * match,void * start, +unsigned int * array_size,unsigned int elem_size, MSVCRT_comp_func cf) +{ + unsigned int size = *array_size; + if (size) + do + { + if (cf(match, start) == 0) + return start; /* found */ + start += elem_size; + } while (--size); + + /* not found, add to end */ + memcpy(start, match, elem_size); + array_size[0]++; + return start; +} + +/********************************************************************* + * _chkesp (MSVCRT.@) + */ +void __cdecl MSVCRT__chkesp(void) +{ + +} diff --git a/dlls/msvcrt/ms_errno.h b/dlls/msvcrt/ms_errno.h new file mode 100644 index 00000000000..7b2fa3dea0e --- /dev/null +++ b/dlls/msvcrt/ms_errno.h @@ -0,0 +1,42 @@ +#ifndef __WINE_MSVCRT_ERRNO_H +#define __WINE_MSVCRT_ERRNO_H + +#define MSVCRT_EPERM 1 +#define MSVCRT_ENOENT 2 +#define MSVCRT_ESRCH 3 +#define MSVCRT_EINTR 4 +#define MSVCRT_EIO 5 +#define MSVCRT_ENXIO 6 +#define MSVCRT_E2BIG 7 +#define MSVCRT_ENOEXEC 8 +#define MSVCRT_EBADF 9 +#define MSVCRT_ECHILD 10 +#define MSVCRT_EAGAIN 11 +#define MSVCRT_ENOMEM 12 +#define MSVCRT_EACCES 13 +#define MSVCRT_EFAULT 14 +#define MSVCRT_EBUSY 16 +#define MSVCRT_EEXIST 17 +#define MSVCRT_EXDEV 18 +#define MSVCRT_ENODEV 19 +#define MSVCRT_ENOTDIR 20 +#define MSVCRT_EISDIR 21 +#define MSVCRT_EINVAL 22 +#define MSVCRT_ENFILE 23 +#define MSVCRT_EMFILE 24 +#define MSVCRT_ENOTTY 25 +#define MSVCRT_EFBIG 27 +#define MSVCRT_ENOSPC 28 +#define MSVCRT_ESPIPE 29 +#define MSVCRT_EROFS 30 +#define MSVCRT_EMLINK 31 +#define MSVCRT_EPIPE 32 +#define MSVCRT_EDOM 33 +#define MSVCRT_ERANGE 34 +#define MSVCRT_EDEADLK 36 +#define MSVCRT_ENAMETOOLONG 38 +#define MSVCRT_ENOLCK 39 +#define MSVCRT_ENOSYS 40 +#define MSVCRT_ENOTEMPTY 41 + +#endif /* __WINE_MSVCRT_ERRNO_H */ diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h new file mode 100644 index 00000000000..a5af9eef171 --- /dev/null +++ b/dlls/msvcrt/msvcrt.h @@ -0,0 +1,43 @@ +#ifndef __WINE_MSVCRT_H +#define __WINE_MSVCRT_H + +#include "config.h" +#include "windef.h" +#include "debugtools.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include + +/* Files */ +#define MSVCRT_EOF -1 +#define MSVCRT_WEOF (WCHAR)(0xFFFF) + +/* TLS data */ +extern DWORD MSVCRT_tls_index; + +typedef struct __MSVCRT_thread_data +{ + int errno; + int doserrno; +} MSVCRT_thread_data; + +#define GET_THREAD_DATA(x) \ + x = TlsGetValue(MSVCRT_tls_index) +#define GET_THREAD_VAR(x) \ + ((MSVCRT_thread_data*)TlsGetValue(MSVCRT_tls_index))->x +#define GET_THREAD_VAR_PTR(x) \ + (&((MSVCRT_thread_data*)TlsGetValue(MSVCRT_tls_index))->x) +#define SET_THREAD_VAR(x,y) \ + ((MSVCRT_thread_data*)TlsGetValue(MSVCRT_tls_index))->x = y + +void MSVCRT__set_errno(int); +int __cdecl MSVCRT__fcloseall(void); +void *__cdecl MSVCRT_malloc(unsigned int); +void *__cdecl MSVCRT_calloc(unsigned int, unsigned int); +void __cdecl MSVCRT_free(void *); +int __cdecl MSVCRT__cputs(const char *); +int __cdecl MSVCRT__cprintf( const char *, ... ); +char *__cdecl MSVCRT__strdup(const char *); + +#endif /* __WINE_MSVCRT_H */ diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec new file mode 100644 index 00000000000..2568ea91966 --- /dev/null +++ b/dlls/msvcrt/msvcrt.spec @@ -0,0 +1,767 @@ +# msvcrt.dll - MS VC++ Run Time Library +name msvcrt +type win32 +init MSVCRT_Init + +import kernel32.dll +import ntdll.dll + +debug_channels (msvcrt) + +@ cdecl $I10_OUTPUT() MSVCRT_I10_OUTPUT +@ cdecl ??0__non_rtti_object@@QAE@ABV0@@Z(ptr ptr) MSVCRT___non_rtti_object_copy_ctor +@ cdecl ??0__non_rtti_object@@QAE@PBD@Z(ptr ptr) MSVCRT___non_rtti_object_ctor +@ cdecl ??0bad_cast@@QAE@ABQBD@Z(ptr ptr) MSVCRT_bad_cast_ctor +@ cdecl ??0bad_cast@@QAE@ABV0@@Z(ptr ptr) MSVCRT_bad_cast_copy_ctor +@ cdecl ??0bad_typeid@@QAE@ABV0@@Z(ptr ptr) MSVCRT_bad_typeid_copy_ctor +@ cdecl ??0bad_typeid@@QAE@PBD@Z(ptr ptr) MSVCRT_bad_typeid_ctor +@ cdecl ??0exception@@QAE@ABQBD@Z(ptr ptr) MSVCRT_exception_ctor +@ cdecl ??0exception@@QAE@ABV0@@Z(ptr ptr) MSVCRT_exception_copy_ctor +@ cdecl ??0exception@@QAE@XZ(ptr) MSVCRT_exception_default_ctor +@ cdecl ??1__non_rtti_object@@UAE@XZ(ptr) MSVCRT___non_rtti_object_dtor +@ cdecl ??1bad_cast@@UAE@XZ(ptr) MSVCRT_bad_cast_dtor +@ cdecl ??1bad_typeid@@UAE@XZ(ptr) MSVCRT_bad_typeid_dtor +@ cdecl ??1exception@@UAE@XZ(ptr) MSVCRT_exception_dtor +@ cdecl ??1type_info@@UAE@XZ(ptr) MSVCRT_type_info_dtor +@ cdecl ??2@YAPAXI@Z(long) MSVCRT_operator_new +@ cdecl ??3@YAXPAX@Z(ptr) MSVCRT_operator_delete +@ cdecl ??4__non_rtti_object@@QAEAAV0@ABV0@@Z(ptr ptr) MSVCRT___non_rtti_object_opequals +@ cdecl ??4bad_cast@@QAEAAV0@ABV0@@Z(ptr ptr) MSVCRT_bad_cast_opequals +@ cdecl ??4bad_typeid@@QAEAAV0@ABV0@@Z(ptr ptr)MSVCRT_bad_typeid_opequals +@ cdecl ??4exception@@QAEAAV0@ABV0@@Z(ptr ptr) MSVCRT_exception_opequals +@ stdcall ??8type_info@@QBEHABV0@@Z(ptr ptr) MSVCRT_type_info_opequals_equals +@ stdcall ??9type_info@@QBEHABV0@@Z(ptr ptr) MSVCRT_type_info_opnot_equals +@ stub ??_7__non_rtti_object@@6B@ +@ stub ??_7bad_cast@@6B@ +@ stub ??_7bad_typeid@@6B@ +@ stub ??_7exception@@6B@ +@ cdecl ??_E__non_rtti_object@@UAEPAXI@Z(ptr long) MSVCRT___non_rtti_object__unknown_E +@ stub ??_Ebad_cast@@UAEPAXI@Z #(ptr long) +@ stub ??_Ebad_typeid@@UAEPAXI@Z #(ptr long) +@ cdecl ??_Eexception@@UAEPAXI@Z(ptr long) MSVCRT_exception__unknown_E +@ cdecl ??_G__non_rtti_object@@UAEPAXI@Z(ptr long) MSVCRT___non_rtti_object__unknown_G +@ stub ??_Gbad_cast@@UAEPAXI@Z #(ptr long) +@ stub ??_Gbad_typeid@@UAEPAXI@Z #(ptr long) +@ cdecl ??_Gexception@@UAEPAXI@Z(ptr long) MSVCRT_exception__unknown_G +@ cdecl ?_query_new_handler@@YAP6AHI@ZXZ() MSVCRT__query_new_handler +@ cdecl ?_query_new_mode@@YAHXZ() MSVCRT__query_new_mode +@ cdecl ?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z(ptr) MSVCRT__set_new_handler +@ cdecl ?_set_new_mode@@YAHH@Z(long) MSVCRT__set_new_mode +@ stub ?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +@ stub ?before@type_info@@QBEHABV1@@Z #(ptr ptr) stdcall +@ stdcall ?name@type_info@@QBEPBDXZ(ptr) MSVCRT_type_info_name +@ stdcall ?raw_name@type_info@@QBEPBDXZ(ptr) MSVCRT_type_info_raw_name +@ stub ?set_new_handler@@YAP6AXXZP6AXXZ@Z +@ stub ?set_terminate@@YAP6AXXZP6AXXZ@Z +@ stub ?set_unexpected@@YAP6AXXZP6AXXZ@Z +@ stub ?terminate@@YAXXZ #() +@ stub ?unexpected@@YAXXZ #() +@ stdcall ?what@exception@@UBEPBDXZ(ptr) MSVCRT_exception_what +@ cdecl -noimport _CIacos() MSVCRT__CIacos +@ cdecl -noimport _CIasin() MSVCRT__CIasin +@ cdecl -noimport _CIatan() MSVCRT__CIatan +@ cdecl -noimport _CIatan2() MSVCRT__CIatan2 +@ cdecl -noimport _CIcos() MSVCRT__CIcos +@ cdecl -noimport _CIcosh() MSVCRT__CIcosh +@ cdecl -noimport _CIexp() MSVCRT__CIexp +@ cdecl -noimport _CIfmod() MSVCRT__CIfmod +@ cdecl -noimport _CIlog() MSVCRT__CIlog +@ cdecl -noimport _CIlog10() MSVCRT__CIlog10 +@ cdecl -noimport _CIpow() MSVCRT__CIpow +@ cdecl -noimport _CIsin() MSVCRT__CIsin +@ cdecl -noimport _CIsinh() MSVCRT__CIsinh +@ cdecl -noimport _CIsqrt() MSVCRT__CIsqrt +@ cdecl -noimport _CItan() MSVCRT__CItan +@ cdecl -noimport _CItanh() MSVCRT__CItanh +@ stub _CxxThrowException +@ cdecl _EH_prolog() MSVCRT__EH_prolog # FIXME: crashes relay debugging +@ cdecl _Getdays() MSVCRT__Getdays +@ cdecl _Getmonths() MSVCRT__Getmonths +@ cdecl _Getnames() MSVCRT__Getnames +@ extern _HUGE MSVCRT__HUGE +@ cdecl _Strftime(str long str ptr ptr) MSVCRT__Strftime +@ cdecl _XcptFilter(long ptr) MSVCRT__XcptFilter +@ stub __CxxFrameHandler +@ stub __CxxLongjmpUnwind +@ stub __RTCastToVoid +@ stub __RTDynamicCast +@ stub __RTtypeid +@ stub __STRINGTOLD +@ extern __argc MSVCRT___argc +@ extern __argv MSVCRT___argv +@ stub __badioinfo +@ stub __crtCompareStringA +@ stub __crtGetLocaleInfoW +@ stub __crtLCMapStringA +@ cdecl __dllonexit() MSVCRT___dllonexit +@ cdecl __doserrno() MSVCRT___doserrno +@ stub __fpecode #() +@ cdecl __getmainargs(ptr ptr ptr long) MSVCRT___getmainargs +@ extern __initenv MSVCRT___initenv +@ cdecl __isascii(long) MSVCRT___isascii +@ cdecl __iscsym(long) MSVCRT___iscsym +@ cdecl __iscsymf(long) MSVCRT___iscsymf +@ stub __lc_codepage +@ stub __lc_collate +@ stub __lc_handle +@ stub __lconv_init +@ extern __mb_cur_max MSVCRT___mb_cur_max +@ cdecl __p___argc() MSVCRT___p___argc +@ cdecl __p___argv() MSVCRT___p___argv +@ cdecl __p___initenv() MSVCRT___p___initenv +@ cdecl __p___mb_cur_max() MSVCRT___p___mb_cur_max +@ cdecl __p___wargv() MSVCRT___p___wargv +@ cdecl __p___winitenv() MSVCRT___p___winitenv +@ cdecl __p__acmdln() MSVCRT___p__acmdln +@ stub __p__amblksiz #() +@ cdecl __p__commode() MSVCRT___p__commode +@ stub __p__daylight #() +@ stub __p__dstbias #() +@ cdecl __p__environ() MSVCRT___p__environ +@ stub __p__fileinfo #() +@ cdecl __p__fmode() MSVCRT___p__fmode +@ cdecl __p__iob() MSVCRT___p__iob +@ stub __p__mbcasemap #() +@ cdecl __p__mbctype() MSVCRT___p__mbctype +@ cdecl __p__osver() MSVCRT___p__osver +@ cdecl __p__pctype() MSVCRT___p__pctype +@ stub __p__pgmptr #() +@ stub __p__pwctype #() +@ cdecl __p__timezone() MSVCRT___p__timezone +@ stub __p__tzname #() +@ cdecl __p__wcmdln() MSVCRT___p__wcmdln +@ cdecl __p__wenviron() MSVCRT___p__wenviron +@ cdecl __p__winmajor() MSVCRT___p__winmajor +@ cdecl __p__winminor() MSVCRT___p__winminor +@ cdecl __p__winver() MSVCRT___p__winver +@ stub __p__wpgmptr #() +@ stub __pioinfo #() +@ stub __pxcptinfoptrs #() +@ cdecl __set_app_type(long) MSVCRT___set_app_type +@ extern __setlc_active MSVCRT___setlc_active +@ cdecl __setusermatherr(ptr) MSVCRT___setusermatherr +@ forward __threadhandle kernel32.GetCurrentThread +@ forward __threadid kernel32.GetCurrentThreadId +@ cdecl __toascii(long) MSVCRT___toascii +@ cdecl __unDName() MSVCRT___unDName #FIXME +@ cdecl __unDNameEx() MSVCRT___unDNameEx #FIXME +@ extern __unguarded_readlc_active MSVCRT___unguarded_readlc_active +@ extern __wargv MSVCRT___wargv +@ cdecl __wgetmainargs(ptr ptr ptr long) MSVCRT___wgetmainargs +@ extern __winitenv MSVCRT___winitenv +@ cdecl _abnormal_termination() MSVCRT__abnormal_termination +@ cdecl _access(str long) MSVCRT__access +@ extern _acmdln MSVCRT__acmdln +@ cdecl _adj_fdiv_m16i() MSVCRT__adj_fdiv_m16i +@ cdecl _adj_fdiv_m32() MSVCRT__adj_fdiv_m32 +@ cdecl _adj_fdiv_m32i() MSVCRT__adj_fdiv_m32i +@ cdecl _adj_fdiv_m64() MSVCRT__adj_fdiv_m64 +@ cdecl _adj_fdiv_r() MSVCRT__adj_fdiv_r +@ cdecl _adj_fdivr_m16i() MSVCRT__adj_fdivr_m16i +@ cdecl _adj_fdivr_m32() MSVCRT__adj_fdivr_m32 +@ cdecl _adj_fdivr_m32i() MSVCRT__adj_fdivr_m32i +@ cdecl _adj_fdivr_m64() MSVCRT__adj_fdivr_m64 +@ cdecl _adj_fpatan() MSVCRT__adj_fpatan +@ cdecl _adj_fprem() MSVCRT__adj_fprem +@ cdecl _adj_fprem1() MSVCRT__adj_fprem1 +@ cdecl _adj_fptan() MSVCRT__adj_fptan +@ cdecl _adjust_fdiv() MSVCRT__adjust_fdiv +@ stub _aexit_rtn +@ cdecl _amsg_exit(long) MSVCRT__amsg_exit +@ cdecl _assert(str str long) MSVCRT__assert +@ stub _atodbl +@ stub _atoi64 #(str) +@ stub _atoldbl +@ cdecl _beep(long long) MSVCRT__beep +@ stub _beginthread #(ptr long ptr) +@ cdecl _beginthreadex (ptr long ptr ptr long ptr) MSVCRT__beginthreadex +@ cdecl _c_exit() MSVCRT__c_exit +@ cdecl _cabs(long) MSVCRT__cabs +@ stub _callnewh +@ cdecl _cexit() MSVCRT__cexit +@ cdecl _cgets(str) MSVCRT__cgets +@ cdecl _chdir(str) MSVCRT__chdir +@ cdecl _chdrive(long) MSVCRT__chdrive +@ cdecl _chgsign( double ) MSVCRT__chgsign +@ cdecl -i386 _chkesp() MSVCRT__chkesp +@ cdecl _chmod(str long) MSVCRT__chmod +@ stub _chsize #(long long) +@ cdecl _clearfp() MSVCRT__clearfp +@ cdecl _close(long) MSVCRT__close +@ cdecl _commit(long) MSVCRT__commit +@ extern _commode MSVCRT__commode +@ cdecl _control87(long long) MSVCRT__control87 +@ cdecl _controlfp(long long) MSVCRT__controlfp +@ cdecl _copysign( double double ) MSVCRT__copysign +@ varargs _cprintf(str) MSVCRT__cprintf +@ cdecl _cputs(str) MSVCRT__cputs +@ cdecl _creat(str long) MSVCRT__creat +@ varargs _cscanf(str) MSVCRT__cscanf +@ extern _ctype MSVCRT__ctype +@ cdecl _cwait(ptr long long) MSVCRT__cwait +@ stub _daylight +@ stub _dstbias +@ stub _dup #(long) +@ stub _dup2 #(long long) +@ cdecl _ecvt( double long ptr ptr) ecvt +@ stub _endthread #() +@ cdecl _endthreadex(long) MSVCRT__endthreadex +@ extern _environ MSVCRT__environ +@ cdecl _eof(long) MSVCRT__eof +@ cdecl _errno() MSVCRT__errno +@ cdecl _except_handler2(ptr ptr ptr ptr) MSVCRT__except_handler2 +@ cdecl _except_handler3(ptr ptr ptr ptr) MSVCRT__except_handler3 +@ stub _execl #(str str) varargs +@ stub _execle #(str str) varargs +@ stub _execlp #(str str) varargs +@ stub _execlpe #(str str) varargs +@ stub _execv #(str str) +@ stub _execve #(str str str) +@ stub _execvp #(str str) +@ stub _execvpe #(str str str) +@ cdecl _exit(long) MSVCRT__exit +@ cdecl _expand(ptr long) MSVCRT__expand +@ cdecl _fcloseall() MSVCRT__fcloseall +@ cdecl _fcvt( double long ptr ptr) fcvt +@ cdecl _fdopen(long str) MSVCRT__fdopen +@ cdecl _fgetchar() MSVCRT__fgetchar +@ cdecl _fgetwchar() MSVCRT__fgetwchar +@ cdecl _filbuf(ptr) MSVCRT__filbuf +@ stub _fileinfo +@ cdecl _filelength(long) MSVCRT__filelength +@ stub _filelengthi64 #(long) +@ cdecl _fileno(ptr) MSVCRT__fileno +@ cdecl _findclose(long) MSVCRT__findclose +@ cdecl _findfirst(str ptr) MSVCRT__findfirst +@ stub _findfirsti64 #(str ptr) +@ cdecl _findnext(long ptr) MSVCRT__findnext +@ stub _findnexti64 #(long ptr) +@ cdecl _finite( double ) MSVCRT__finite +@ cdecl _flsbuf(long ptr) MSVCRT__flsbuf +@ cdecl _flushall() MSVCRT__flushall +@ extern _fmode MSVCRT__fmode +@ cdecl _fpclass(double) MSVCRT__fpclass +@ stub _fpieee_flt +@ cdecl _fpreset() MSVCRT__fpreset +@ cdecl _fputchar(long) MSVCRT__fputchar +@ cdecl _fputwchar(long) MSVCRT__fputwchar +@ cdecl _fsopen(str str) MSVCRT__fsopen +@ cdecl _fstat(long ptr) MSVCRT__fstat +@ stub _fstati64 #(long ptr) +@ cdecl _ftime(ptr) MSVCRT__ftime +@ forward _ftol ntdll._ftol +@ cdecl _fullpath(str str long) MSVCRT__fullpath +@ cdecl _futime() MSVCRT__futime +@ cdecl _gcvt( double long str) gcvt +@ cdecl _get_osfhandle(long) MSVCRT__get_osfhandle +@ stub _get_sbh_threshold #() +@ cdecl _getch() MSVCRT__getch +@ cdecl _getche() MSVCRT__getche +@ cdecl _getcwd(str long) MSVCRT__getcwd +@ cdecl _getdcwd(long str long) MSVCRT__getdcwd +@ cdecl _getdiskfree(long ptr) MSVCRT__getdiskfree +@ forward _getdllprocaddr kernel32.GetProcAddress +@ cdecl _getdrive() MSVCRT__getdrive +@ forward _getdrives kernel32.GetLogicalDrives +@ stub _getmaxstdio #() +@ cdecl _getmbcp() MSVCRT__getmbcp +@ forward _getpid kernel32.GetCurrentProcessId +@ stub _getsystime #(ptr) +@ cdecl _getw(ptr) MSVCRT__getw +@ stub _getws #(wstr) +@ cdecl _global_unwind2(ptr) MSVCRT__global_unwind2 +@ stub _heapadd #() +@ cdecl _heapchk() MSVCRT__heapchk +@ cdecl _heapmin() MSVCRT__heapmin +@ cdecl _heapset(long) MSVCRT__heapset +@ stub _heapused #(ptr ptr) +@ cdecl _heapwalk(ptr) MSVCRT__heapwalk +@ cdecl _hypot(double double) hypot +@ stub _i64toa #(long str long) +@ stub _i64tow #(long wstr long) +@ cdecl _initterm(ptr ptr) MSVCRT__initterm +@ stub -i386 _inp #(long) +@ stub -i386 _inpd #(long) +@ stub -i386 _inpw #(long) +@ extern _iob MSVCRT__iob +@ cdecl _isatty(long) MSVCRT__isatty +@ cdecl _isctype(long long) MSVCRT__isctype +@ stub _ismbbalnum #(long) +@ stub _ismbbalpha #(long) +@ stub _ismbbgraph #(long) +@ stub _ismbbkalnum #(long) +@ cdecl _ismbbkana(long) MSVCRT__ismbbkana +@ stub _ismbbkprint #(long) +@ stub _ismbbkpunct #(long) +@ cdecl _ismbblead(long) MSVCRT__ismbblead +@ stub _ismbbprint #(long) +@ stub _ismbbpunct #(long) +@ cdecl _ismbbtrail(long) MSVCRT__ismbbtrail +@ stub _ismbcalnum #(long) +@ stub _ismbcalpha #(long) +@ stub _ismbcdigit #(long) +@ stub _ismbcgraph #(long) +@ cdecl _ismbchira(long) MSVCRT__ismbchira +@ cdecl _ismbckata(long) MSVCRT__ismbckata +@ stub _ismbcl0 #(long) +@ stub _ismbcl1 #(long) +@ stub _ismbcl2 #(long) +@ stub _ismbclegal #(long) +@ stub _ismbclower #(long) +@ stub _ismbcprint #(long) +@ stub _ismbcpunct #(long) +@ stub _ismbcspace #(long) +@ stub _ismbcsymbol #(long) +@ stub _ismbcupper #(long) +@ cdecl _ismbslead(ptr ptr) MSVCRT__ismbslead +@ cdecl _ismbstrail(ptr ptr) MSVCRT__ismbstrail +@ cdecl _isnan( double ) MSVCRT__isnan +@ forward _itoa ntdll._itoa +@ cdecl _itow(long wstr long) MSVCRT__itow +@ cdecl _j0(double) j0 +@ cdecl _j1(double) j1 +@ cdecl _jn(long double) jn +@ cdecl _kbhit() MSVCRT__kbhit +@ stub _lfind +@ cdecl _loaddll(str) MSVCRT__loaddll +@ cdecl _local_unwind2(ptr long) MSVCRT__local_unwind2 +@ stub _lock +@ stub _locking #(long long long) +@ cdecl _logb( double ) MSVCRT__logb +@ stub _longjmpex +@ cdecl _lrotl(long long) MSVCRT__lrotl +@ cdecl _lrotr(long long) MSVCRT__lrotr +@ cdecl _lsearch(ptr ptr long long ptr) MSVCRT__lsearch +@ cdecl _lseek(long long long) MSVCRT__lseek +@ stub _lseeki64 #(long long long) +@ forward _ltoa ntdll._ltoa +@ forward _ltow ntdll._ltow +@ cdecl _makepath(str str str str str) MSVCRT__makepath +@ cdecl _mbbtombc(long) MSVCRT__mbbtombc +@ stub _mbbtype #(long long) +@ stub _mbcasemap +@ cdecl _mbccpy (str str) strcpy +@ stub _mbcjistojms #(long) +@ stub _mbcjmstojis #(long) +@ cdecl _mbclen(ptr) MSVCRT__mbclen +@ stub _mbctohira #(long) +@ stub _mbctokata #(long) +@ stub _mbctolower #(long) +@ stub _mbctombb #(long) +@ stub _mbctoupper #(long) +@ stub _mbctype +@ stub _mbsbtype #(ptr long) +@ cdecl _mbscat(str str) strcat +@ cdecl _mbschr(str long) MSVCRT__mbschr +@ cdecl _mbscmp(str str) MSVCRT__mbscmp +@ stub _mbscoll #(str str) +@ cdecl _mbscpy(ptr str) strcpy +@ stub _mbscspn #(str str) +@ cdecl _mbsdec(ptr ptr) MSVCRT__mbsdec +@ cdecl _mbsdup(str) MSVCRT__strdup +@ cdecl _mbsicmp(str str) MSVCRT__mbsicmp +@ stub _mbsicoll #(str str) +@ cdecl _mbsinc(str) MSVCRT__mbsinc +@ cdecl _mbslen(str) MSVCRT__mbslen +@ stub _mbslwr #(str) +@ stub _mbsnbcat #(str str long) +@ stub _mbsnbcmp #(str str long) +@ stub _mbsnbcnt #(ptr long) +@ stub _mbsnbcoll #(str str long) +@ stub _mbsnbcpy #(ptr str long) +@ stub _mbsnbicmp #(str str long) +@ stub _mbsnbicoll #(str str long) +@ stub _mbsnbset #(str long long) +@ cdecl _mbsncat(str str long) MSVCRT__mbsncat +@ cdecl _mbsnccnt(str long) MSVCRT__mbsnccnt +@ cdecl _mbsncmp(str str long) MSVCRT__mbsncmp +@ stub _mbsncoll #(ptr str long) +@ cdecl _mbsncpy(str str long) MSVCRT__mbsncpy +@ cdecl _mbsnextc(str) MSVCRT__mbsnextc +@ cdecl _mbsnicmp(str str long) MSVCRT__mbsnicmp +@ stub _mbsnicoll #(str str long) +@ cdecl _mbsninc(str long) MSVCRT__mbsninc +@ cdecl _mbsnset(str long long) MSVCRT__mbsnset +@ stub _mbspbrk #(str str) +@ cdecl _mbsrchr(str long) MSVCRT__mbsrchr +@ stub _mbsrev #(str) +@ cdecl _mbsset(str long) MSVCRT__mbsset +@ stub _mbsspn #(str str) +@ stub _mbsspnp #(str str) +@ cdecl _mbsstr(str str) strstr +@ stub _mbstok #(str str) +@ cdecl _mbstrlen(str) MSVCRT__mbstrlen +@ stub _mbsupr #(str) +@ cdecl _memccpy(ptr ptr long long) memccpy +@ forward _memicmp ntdll._memicmp +@ cdecl _mkdir(str) MSVCRT__mkdir +@ cdecl _mktemp(str) MSVCRT__mktemp +@ cdecl _msize(ptr) MSVCRT__msize +@ cdecl _nextafter(double double) MSVCRT__nextafter +@ cdecl _onexit(ptr) MSVCRT__onexit +@ cdecl _open(str long) MSVCRT__open +@ cdecl _open_osfhandle(long long) MSVCRT__open_osfhandle +@ stub _osver +@ stub _outp #(long long) +@ stub _outpd #(long long) +@ stub _outpw #(long long) +@ stub _pclose #(ptr) +@ extern _pctype MSVCRT__pctype +@ stub _pgmptr +@ stub _pipe #(ptr long long) +@ stub _popen #(str str) +@ cdecl _purecall() MSVCRT__purecall +@ cdecl _putch(long) MSVCRT__putch +@ stub _putenv #(str) +@ cdecl _putw(long ptr) MSVCRT__putw +@ stub _putws #(wstr) +@ stub _pwctype +@ cdecl _read(long ptr long) MSVCRT__read +@ cdecl _rmdir(str) MSVCRT__rmdir +@ cdecl _rmtmp() MSVCRT__rmtmp +@ cdecl _rotl(long long) MSVCRT__rotl +@ cdecl _rotr(long long) MSVCRT__rotr +@ cdecl _safe_fdiv() MSVCRT__safe_fdiv +@ cdecl _safe_fdivr() MSVCRT__safe_fdivr +@ cdecl _safe_fprem() MSVCRT__safe_fprem +@ cdecl _safe_fprem1() MSVCRT__safe_fprem1 +@ cdecl _scalb( double long) MSVCRT__scalb +@ cdecl _searchenv(str str str) MSVCRT__searchenv +@ stub _seh_longjmp_unwind +@ stub _set_error_mode #(long) +@ stub _set_sbh_threshold #(long) +@ stub _seterrormode #(long) +@ cdecl _setjmp(ptr) MSVCRT__setjmp +@ stub _setjmp3 +@ stub _setmaxstdio #(long) +@ cdecl _setmbcp(long) MSVCRT__setmbcp +@ cdecl _setmode(long long) MSVCRT__setmode +@ stub _setsystime #(ptr long) +@ cdecl _sleep(long) MSVCRT__sleep +@ varargs _snprintf(str long str) snprintf +@ stub _snwprintf #(wstr long wstr) varargs +@ stub _sopen +@ stub _spawnl #(str str) varargs +@ stub _spawnle #(str str) varargs +@ stub _spawnlp #(str str) varargs +@ stub _spawnlpe #(str str) varargs +@ cdecl _spawnv(str str) MSVCRT__spawnv +@ cdecl _spawnve(str str str) MSVCRT__spawnve +@ cdecl _spawnvp(str str) MSVCRT__spawnvp +@ cdecl _spawnvpe(str str str) MSVCRT__spawnvpe +@ cdecl _splitpath(str str str str str) MSVCRT__splitpath +@ cdecl _stat(str ptr) MSVCRT__stat +@ stub _stati64 #(str ptr) +@ cdecl _statusfp() MSVCRT__statusfp +@ cdecl _strcmpi(str str) strcasecmp +@ cdecl _strdate(str) MSVCRT__strdate +@ cdecl _strdup(str) MSVCRT__strdup +@ cdecl _strerror(long) MSVCRT__strerror +@ cdecl _stricmp(str str) strcasecmp +@ stub _stricoll #(str str) +@ forward _strlwr ntdll._strlwr +@ stub _strncoll #(str str long) +@ cdecl _strnicmp(str str long) strncasecmp +@ stub _strnicoll #(str str long) +@ cdecl _strnset(str long long) MSVCRT__strnset +@ cdecl _strrev(str) MSVCRT__strrev +@ cdecl _strset(str long) MSVCRT__strset +@ cdecl _strtime(str) MSVCRT__strtime +@ forward _strupr ntdll._strupr +@ cdecl _swab(str str long) MSVCRT__swab +@ stub _sys_errlist #() +@ stub _sys_nerr #() +@ cdecl _tell(long) MSVCRT__tell +@ stub _telli64 #(long) +@ cdecl _tempnam(str str) MSVCRT__tempnam +@ stub _timezone #() +@ cdecl _tolower(long) MSVCRT__tolower +@ cdecl _toupper(long) MSVCRT__toupper +@ stub _tzname +@ stub _tzset #() +@ stub _ui64toa #(long str long) +@ stub _ui64tow #(long wstr long) +@ forward _ultoa ntdll._ultoa +@ forward _ultow ntdll._ultow +@ cdecl _umask(long) MSVCRT__umask +@ cdecl _ungetch(long) MSVCRT__ungetch +@ cdecl _unlink(str) MSVCRT__unlink +@ cdecl _unloaddll(long) MSVCRT__unloaddll +@ stub _unlock +@ cdecl _utime(str ptr) MSVCRT__utime +@ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf +@ stub _vsnwprintf #(wstr long wstr long) +@ stub _waccess #(wstr long) +@ stub _wasctime #(ptr) +@ cdecl _wchdir(wstr) MSVCRT__wchdir +@ stub _wchmod #(wstr long) +@ extern _wcmdln MSVCRT__wcmdln +@ stub _wcreat #(wstr long) +@ cdecl _wcsdup(wstr) MSVCRT__wcsdup +@ forward _wcsicmp ntdll._wcsicmp +@ cdecl _wcsicoll(wstr wstr) MSVCRT__wcsicoll +@ stub _wcslwr #(wstr) +@ stub _wcsncoll #(wstr wstr long) +@ forward _wcsnicmp ntdll._wcsnicmp +@ stub _wcsnicoll #(wstr wstr long) +@ cdecl _wcsnset(wstr long long) MSVCRT__wcsnset +@ cdecl _wcsrev(wstr) MSVCRT__wcsrev +@ cdecl _wcsset(wstr long) MSVCRT__wcsset +@ forward _wcsupr ntdll._wcsupr +@ stub _wctime #(ptr) +@ extern _wenviron MSVCRT__wenviron +@ stub _wexecl #(wstr wstr) varargs +@ stub _wexecle #(wstr wstr) varargs +@ stub _wexeclp #(wstr wstr) varargs +@ stub _wexeclpe #(wstr wstr) varargs +@ stub _wexecv #(wstr wstr) +@ stub _wexecve #(wstr wstr wstr) +@ stub _wexecvp #(wstr wstr) +@ stub _wexecvpe #(wstr wstr wstr) +@ stub _wfdopen #(long wstr) +@ cdecl _wfindfirst(wstr ptr) MSVCRT__wfindfirst +@ stub _wfindfirsti64 #(wstr ptr) +@ cdecl _wfindnext(long ptr) MSVCRT__wfindnext +@ stub _wfindnexti64 #(long ptr) +@ stub _wfopen #(wstr wstr) +@ stub _wfreopen #(wstr wstr ptr) +@ stub _wfsopen #(wstr wstr) +@ stub _wfullpath #(wstr wstr long) +@ cdecl _wgetcwd(wstr long) MSVCRT__wgetcwd +@ cdecl _wgetdcwd(long wstr long) MSVCRT__wgetdcwd +@ cdecl _wgetenv(wstr) MSVCRT__wgetenv +@ extern _winmajor MSVCRT__winmajor +@ extern _winminor MSVCRT__winminor +@ extern _winver MSVCRT__winver +@ stub _wmakepath #(wstr wstr wstr wstr wstr) +@ cdecl _wmkdir(wstr) MSVCRT__wmkdir +@ stub _wmktemp #(wstr) +@ stub _wopen #(wstr long) varargs +@ stub _wperror #(wstr) +@ stub _wpgmptr +@ stub _wpopen #(wstr wstr) +@ stub _wputenv #(wstr) +@ stub _wremove #(wstr) +@ stub _wrename #(wstr wstr) +@ cdecl _write(long ptr long) MSVCRT__write +@ cdecl _wrmdir(wstr) MSVCRT__wrmdir +@ stub _wsearchenv #(wstr wstr wstr) +@ stub _wsetlocale #(long wstr) +@ stub _wsopen #(wstr long long) varargs +@ stub _wspawnl #(long wstr wstr) varargs +@ stub _wspawnle #(long wstr wstr) varargs +@ stub _wspawnlp #(long wstr wstr) varargs +@ stub _wspawnlpe #(long wstr wstr) varargs +@ stub _wspawnv #(long wstr wstr) +@ stub _wspawnve #(long wstr wstr wstr) +@ stub _wspawnvp #(long wstr wstr) +@ stub _wspawnvpe #(long wstr wstr wstr) +@ stub _wsplitpath #(wstr wstr wstr wstr wstr) +@ stub _wstat #(wstr ptr) +@ stub _wstati64 #(wstr ptr) +@ stub _wstrdate #(wstr) +@ stub _wstrtime #(wstr) +@ stub _wsystem #(wstr) +@ stub _wtempnam #(wstr wstr) +@ stub _wtmpnam #(wstr) +@ forward _wtoi NTDLL._wtoi +@ stub _wtoi64 #(wstr) +@ forward _wtol NTDLL._wtol +@ stub _wunlink #(wstr) +@ stub _wutime +@ cdecl _y0(double) MSVCRT__y0 +@ cdecl _y1(double) MSVCRT__y1 +@ cdecl _yn(long double ) MSVCRT__yn +@ cdecl abort() MSVCRT_abort +@ cdecl abs(long) abs +@ cdecl acos( double ) acos +@ cdecl asctime(ptr) asctime +@ cdecl asin(double) asin +@ cdecl atan(double) atan +@ cdecl atan2(double double) atan2 +@ cdecl atexit(ptr) MSVCRT_atexit +@ cdecl atof(str) atof +@ cdecl atoi(str) atoi +@ cdecl atol(str) atol +@ cdecl bsearch(ptr ptr long long ptr) bsearch +@ cdecl calloc(long long) MSVCRT_calloc +@ cdecl ceil(double) ceil +@ cdecl clearerr(ptr) MSVCRT_clearerr +@ cdecl clock() MSVCRT_clock +@ cdecl cos(double) cos +@ cdecl cosh(double) cosh +@ cdecl ctime(ptr) ctime +@ cdecl difftime(long long) MSVCRT_difftime +@ cdecl -noimport div(long long) MSVCRT_div +@ cdecl exit(long) MSVCRT_exit +@ cdecl exp(double) exp +@ cdecl fabs(double) fabs +@ cdecl fclose(ptr) MSVCRT_fclose +@ cdecl feof(ptr) MSVCRT_feof +@ cdecl ferror(ptr) MSVCRT_ferror +@ cdecl fflush(ptr) MSVCRT_fflush +@ cdecl fgetc(ptr) MSVCRT_fgetc +@ cdecl fgetpos(ptr ptr) MSVCRT_fgetpos +@ cdecl fgets(str long ptr) MSVCRT_fgets +@ cdecl fgetwc(ptr) MSVCRT_fgetwc +@ stub fgetws #(wstr long ptr) +@ cdecl floor(double) floor +@ cdecl fmod(double double) fmod +@ cdecl fopen(str str) MSVCRT_fopen +@ varargs fprintf(ptr str) MSVCRT_fprintf +@ cdecl fputc(long ptr) MSVCRT_fputc +@ cdecl fputs(str ptr) MSVCRT_fputs +@ cdecl fputwc(long ptr) MSVCRT_fputwc +@ stub fputws #(wstr ptr) +@ cdecl fread() MSVCRT_fread +@ cdecl free() MSVCRT_free +@ cdecl freopen(str str ptr) MSVCRT_freopen +@ cdecl frexp(double ptr) frexp +@ varargs fscanf(ptr str) MSVCRT_fscanf +@ cdecl fseek(ptr long long) MSVCRT_fseek +@ cdecl fsetpos(ptr ptr) MSVCRT_fsetpos +@ cdecl ftell(ptr) MSVCRT_ftell +@ stub fwprintf #(ptr wstr) varargs +@ cdecl fwrite(ptr long long ptr) MSVCRT_fwrite +@ stub fwscanf #(ptr wstr) varargs +@ cdecl getc(ptr) MSVCRT_getc +@ cdecl getchar() MSVCRT_getchar +@ cdecl getenv(str) MSVCRT_getenv +@ cdecl gets(str) MSVCRT_gets +@ cdecl getwc(ptr) MSVCRT_getwc +@ cdecl getwchar() MSVCRT_getwchar +@ cdecl gmtime(ptr) gmtime +@ forward is_wctype ntdll.iswctype +@ cdecl isalnum(long) MSVCRT_isalnum +@ cdecl isalpha(long) MSVCRT_isalpha +@ cdecl iscntrl(long) MSVCRT_iscntrl +@ cdecl isdigit(long) MSVCRT_isdigit +@ cdecl isgraph(long) MSVCRT_isgraph +@ cdecl isleadbyte(long) MSVCRT_isleadbyte +@ cdecl islower(long) MSVCRT_islower +@ cdecl isprint(long) MSVCRT_isprint +@ cdecl ispunct(long) MSVCRT_ispunct +@ cdecl isspace(long) MSVCRT_isspace +@ cdecl isupper(long) MSVCRT_isupper +@ cdecl iswalnum(long) MSVCRT_iswalnum +@ forward iswalpha ntdll._iswalpha +@ cdecl iswascii(long) MSVCRT_iswascii +@ cdecl iswcntrl(long) MSVCRT_iswcntrl +@ forward iswctype ntdll._iswctype +@ cdecl iswdigit(long) MSVCRT_iswdigit +@ cdecl iswgraph(long) MSVCRT_iswgraph +@ cdecl iswlower(long) MSVCRT_iswlower +@ cdecl iswprint(long) MSVCRT_iswprint +@ cdecl iswpunct(long) MSVCRT_iswpunct +@ cdecl iswspace(long) MSVCRT_iswspace +@ cdecl iswupper(long) MSVCRT_iswupper +@ cdecl iswxdigit(long) MSVCRT_iswxdigit +@ cdecl isxdigit(long) MSVCRT_isxdigit +@ cdecl labs(long) labs +@ cdecl ldexp( double long) MSVCRT_ldexp +@ cdecl -noimport ldiv(long long) MSVCRT_ldiv +@ stub localeconv #() +@ cdecl localtime(ptr) localtime +@ cdecl log(double) log +@ cdecl log10(double) log10 +@ cdecl longjmp(long long) MSVCRT_longjmp +@ cdecl malloc(long) MSVCRT_malloc +@ stub mblen #(str long) +@ forward mbstowcs ntdll.mbstowcs +@ cdecl mbtowc(wstr str long) MSVCRT_mbtowc +@ cdecl memchr(ptr long long) memchr +@ cdecl memcmp(ptr ptr long) memcmp +@ cdecl memcpy(ptr ptr long) memcpy +@ cdecl memmove(ptr ptr long) memmove +@ cdecl memset(ptr long long) memset +@ cdecl mktime(ptr) mktime +@ cdecl modf(double ptr) modf +@ cdecl perror(str) MSVCRT_perror +@ cdecl pow(double double) pow +@ varargs printf(str) MSVCRT_printf +@ cdecl putc(long ptr) MSVCRT_putc +@ cdecl putchar(long) MSVCRT_putchar +@ cdecl puts(str) MSVCRT_puts +@ stub putwc #(long ptr) +@ stub putwchar #(long) +@ cdecl qsort(ptr long long ptr) qsort +@ stub raise #(long) +@ cdecl rand() MSVCRT_rand +@ cdecl realloc() MSVCRT_realloc +@ cdecl remove(str) MSVCRT_remove +@ cdecl rename(str str) MSVCRT_rename +@ cdecl rewind(ptr) MSVCRT_rewind +@ varargs scanf(str) MSVCRT_scanf +@ cdecl setbuf(ptr ptr) MSVCRT_setbuf +@ cdecl setlocale(long str) MSVCRT_setlocale +@ stub setvbuf #(ptr str long long) +@ cdecl signal(long long) MSVCRT_signal +@ cdecl sin(double) sin +@ cdecl sinh(double) sinh +@ varargs sprintf(str str) sprintf +@ cdecl sqrt(double) sqrt +@ cdecl srand(long) srand +@ varargs sscanf(str str) sscanf +@ cdecl strcat(str str) strcat +@ cdecl strchr(str long) strchr +@ cdecl strcmp(str str) strcmp +@ cdecl strcoll(str str) strcoll +@ cdecl strcpy(ptr str) strcpy +@ cdecl strcspn(str str) strcspn +@ cdecl strerror(long) MSVCRT_strerror +@ cdecl strftime(str long str ptr) strftime +@ cdecl strlen(str) strlen +@ cdecl strncat(str str long) strncat +@ cdecl strncmp(str str long) strncmp +@ cdecl strncpy(ptr str long) strncpy +@ cdecl strpbrk(str str) strpbrk +@ cdecl strrchr(str long) strrchr +@ cdecl strspn(str str) strspn +@ cdecl strstr(str str) strstr +@ cdecl strtod(str ptr) strtod +@ cdecl strtok(str str) strtok +@ cdecl strtol(str ptr long) strtol +@ cdecl strtoul(str ptr long) strtoul +@ cdecl strxfrm(ptr str long) strxfrm +@ stub swprintf #(wstr wstr) varargs +@ stub swscanf #(wstr wstr) varargs +@ cdecl system(str) MSVCRT_system +@ cdecl tan(double) tan +@ cdecl tanh(double) tanh +@ cdecl time(ptr) MSVCRT_time +@ cdecl tmpfile() MSVCRT_tmpfile +@ cdecl tmpnam(str) MSVCRT_tmpnam +@ forward towlower ntdll.towlower +@ forward towupper ntdll.towupper +@ stub ungetc #(long ptr) +@ stub ungetwc #(long ptr) +@ cdecl vfprintf(ptr str long) MSVCRT_vfprintf +@ stub vfwprintf #(ptr wstr long) +@ stub vprintf #(str long) +@ cdecl vsprintf(ptr str ptr) vsprintf +@ stub vswprintf #(wstr wstr long) +@ stub vwprintf #(wstr long) +@ forward wcscat ntdll.wcscat +@ forward wcschr ntdll.wcschr +@ forward wcscmp ntdll.wcscmp +@ cdecl wcscoll(wstr wstr) MSVCRT_wcscoll +@ forward wcscpy ntdll.wcscpy +@ forward wcscspn ntdll.wcscspn +@ stub wcsftime #(wstr long wstr ptr) +@ forward wcslen ntdll.wcslen +@ forward wcsncat ntdll.wcsncat +@ forward wcsncmp ntdll.wcsncmp +@ forward wcsncpy ntdll.wcsncpy +@ cdecl wcspbrk(wstr wstr) MSVCRT_wcspbrk +@ forward wcsrchr ntdll.wcsrchr +@ forward wcsspn ntdll.wcsspn +@ forward wcsstr ntdll.wcsstr +@ stub wcstod #(wstr ptr) +@ forward wcstok ntdll.wcstok +@ forward wcstol ntdll.wcstol +@ forward wcstombs ntdll.wcstombs +@ stub wcstoul #(wstr ptr long) +@ stub wcsxfrm #(wstr wstr long) +@ cdecl wctomb(ptr long) MSVCRT_wctomb +@ stub wprintf #(wstr) varargs +@ stub wscanf #(wstr) varargs diff --git a/dlls/msvcrt/process.c b/dlls/msvcrt/process.c new file mode 100644 index 00000000000..9f8ef42d3ae --- /dev/null +++ b/dlls/msvcrt/process.c @@ -0,0 +1,235 @@ +/* + * msvcrt.dll spawn/exec functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + * + * FIXME: + * -File handles need some special handling. Sometimes children get + * open file handles, sometimes not. The docs are confusing + * -No check for maximum path/argument/environment size is done + */ +#include "msvcrt.h" +#include "ms_errno.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* Process creation flags */ +#define _P_WAIT 0 +#define _P_NOWAIT 1 +#define _P_OVERLAY 2 +#define _P_NOWAITO 3 +#define _P_DETACH 4 + +void __cdecl MSVCRT__exit(int); +void __cdecl MSVCRT__searchenv(const char* file, const char* env, char *buf); + +/* FIXME: Check file extenstions for app to run */ +static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e'; +static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't'; +static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd'; +static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm'; + +/* INTERNAL: Spawn a child process */ +static int __MSVCRT__spawn(int flags, const char *exe, char * args, char *env) +{ + STARTUPINFOA si; + PROCESS_INFORMATION pi; + + if (sizeof(HANDLE) != sizeof(int)) + WARN("This call is unsuitable for your architecture\n"); + + if ((unsigned)flags > _P_DETACH) + { + SET_THREAD_VAR(errno,MSVCRT_EINVAL); + return -1; + } + + FIXME(":must dup/kill streams for child process\n"); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + if (!CreateProcessA(exe, args, NULL, NULL, TRUE, + flags == _P_DETACH ? DETACHED_PROCESS : 0, + env, NULL, &si, &pi)) + { + MSVCRT__set_errno(GetLastError()); + return -1; + } + + switch(flags) + { + case _P_WAIT: + WaitForSingleObject(pi.hProcess,-1); /* wait forvever */ + GetExitCodeProcess(pi.hProcess,&pi.dwProcessId); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return (int)pi.dwProcessId; + case _P_DETACH: + CloseHandle(pi.hProcess); + pi.hProcess = 0; + /* fall through */ + case _P_NOWAIT: + case _P_NOWAITO: + CloseHandle(pi.hThread); + return (int)pi.hProcess; + case _P_OVERLAY: + MSVCRT__exit(0); + } + return -1; /* can't reach here */ +} + +/* INTERNAL: Convert argv list to a single 'delim'-seperated string */ +static char * __MSVCRT__argvtos(const char * *arg, char delim) +{ + const char **search = arg; + long size = 0; + char *ret; + + if (!arg && !delim) + return NULL; + + /* get length */ + while(*search) + { + size += strlen(*search) + 1; + search++; + } + + if (!(ret = (char *)MSVCRT_calloc(size + 1, 1))) + return NULL; + + /* fill string */ + search = arg; + size = 0; + while(*search) + { + int strsize = strlen(*search); + memcpy(ret+size,*search,strsize); + ret[size+strsize] = delim; + size += strsize + 1; + search++; + } + return ret; +} + +/********************************************************************* + * _cwait (MSVCRT.@) + */ +int __cdecl MSVCRT__cwait(int *status, int pid, int action) +{ + HANDLE hPid = (HANDLE)pid; + int doserrno; + + action = action; /* Remove warning */ + + if (!WaitForSingleObject(hPid, -1)) /* wait forever */ + { + if (status) + { + DWORD stat; + GetExitCodeProcess(hPid, &stat); + *status = (int)stat; + } + return (int)pid; + } + doserrno = GetLastError(); + + if (doserrno == ERROR_INVALID_HANDLE) + { + SET_THREAD_VAR(errno, MSVCRT_ECHILD); + SET_THREAD_VAR(doserrno,doserrno); + } + else + MSVCRT__set_errno(doserrno); + + return status ? *status = -1 : -1; +} + +/********************************************************************* + * _spawnve (MSVCRT.@) + */ +int __cdecl MSVCRT__spawnve(int flags, const char *name, const char **argv, + const char **envv) +{ + char * args = __MSVCRT__argvtos(argv,' '); + char * envs = __MSVCRT__argvtos(envv,0); + LPCSTR fullname = name; + int ret = -1; + + FIXME(":not translating name %s to locate program\n",fullname); + TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null"); + + if (args) + { + ret = __MSVCRT__spawn(flags, fullname, args, envs); + MSVCRT_free(args); + } + if (envs) + MSVCRT_free(envs); + + return ret; +} + +/********************************************************************* + * _spawnv (MSVCRT.@) + */ +int __cdecl MSVCRT__spawnv(int flags, const char *name, const char **argv) +{ + return MSVCRT__spawnve(flags, name, argv, NULL); +} + +/********************************************************************* + * _spawnvpe (MSVCRT.@) + */ +int __cdecl MSVCRT__spawnvpe(int flags, const char *name, const char **argv, + const char **envv) +{ + char fullname[MAX_PATH]; + MSVCRT__searchenv(name, "PATH", fullname); + return MSVCRT__spawnve(flags, fullname[0] ? fullname : name, argv, envv); +} + +/********************************************************************* + * _spawnvp (MSVCRT.@) + */ +int __cdecl MSVCRT__spawnvp(int flags, const char *name, const char **argv) +{ + return MSVCRT__spawnvpe(flags, name, argv, NULL); +} + +/********************************************************************* + * system (MSVCRT.@) + */ +int __cdecl MSVCRT_system(const char *cmd) +{ + /* FIXME: should probably launch cmd interpreter in COMSPEC */ + return __MSVCRT__spawn(_P_WAIT, cmd, NULL, NULL); +} + +/********************************************************************* + * _loaddll (MSVCRT.@) + */ +int __cdecl MSVCRT__loaddll(const char *dllname) +{ + return LoadLibraryA(dllname); +} + +/********************************************************************* + * _unloaddll (MSVCRT.@) + */ +int __cdecl MSVCRT__unloaddll(int dll) +{ + if (FreeLibrary((HANDLE)dll)) + return 0; + else + { + int err = GetLastError(); + MSVCRT__set_errno(err); + return err; + } +} + diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c new file mode 100644 index 00000000000..1736707635a --- /dev/null +++ b/dlls/msvcrt/string.c @@ -0,0 +1,154 @@ +/* + * MSVCRT string functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* INTERNAL: MSVCRT_malloc() based strndup */ +char * MSVCRT__strndup(const char * buf, unsigned int size) +{ + char* ret; + unsigned int len = strlen(buf), max_len; + + max_len = size <= len? size : len + 1; + + ret = MSVCRT_malloc(max_len); + if (ret) + { + memcpy(ret,buf,max_len); + ret[max_len] = 0; + } + return ret; +} + +/********************************************************************* + * _strdec (MSVCRT.@) + */ +char * __cdecl MSVCRT__strdec(const char * str1, const char * str2) +{ + /* Hmm. While the docs suggest that the following should work... */ + /* return (str2<=str1?0:str2-1); */ + /* ...Version 2.50.4170 (NT) from win98 constantly decrements! */ + str1 = str1; /* remove warning */ + return (char *)str2-1; +} + +/********************************************************************* + * _strdup (MSVCRT.@) + */ +char * __cdecl MSVCRT__strdup(const char * str) +{ + char * ret = MSVCRT_malloc(strlen(str)+1); + if (ret) strcpy( ret, str ); + return ret; +} + +/********************************************************************* + * _strinc (MSVCRT.@) + */ +char * __cdecl MSVCRT__strinc(const char * str) +{ + return (char*)str+1; +} + +/********************************************************************* + * _strnextc (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__strnextc(const char * str) +{ + return (unsigned int)*str; +} + +/********************************************************************* + * _strninc (MSVCRT.@) + * + * Return a pointer to the 'n'th character in a string + */ +char * __cdecl MSVCRT__strninc(char * str, unsigned int n) +{ + return str + n; +} + +/********************************************************************* + * _strnset (MSVCRT.@) + */ +char * __cdecl MSVCRT__strnset(char * str, int value, unsigned int len) +{ + if (len > 0 && str) + while (*str && len--) + *str++ = value; + return str; +} + +/********************************************************************* + * _strrev (MSVCRT.@) + */ +char * __cdecl MSVCRT__strrev (char * str) +{ + char * p1; + char * p2; + + if (str && *str) + for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) + { + *p1 ^= *p2; + *p2 ^= *p1; + *p1 ^= *p2; + } + + return str; +} + +/********************************************************************* + * _strset (MSVCRT.@) + */ +char * __cdecl MSVCRT__strset (char * str, int value) +{ + char *ptr = str; + while (*ptr) + *ptr++ = value; + + return str; +} + +/********************************************************************* + * _strncnt (MSVCRT.@) + */ +unsigned int __cdecl MSVCRT__strncnt(char * str, unsigned int max) +{ + unsigned int len = strlen(str); + return (len > max? max : len); +} + +/********************************************************************* + * _strspnp (MSVCRT.@) + */ +char * __cdecl MSVCRT__strspnp(char * str1, char * str2) +{ + str1 += strspn(str1,str2); + return *str1? str1 : 0; +} + +/********************************************************************* + * _swab (MSVCRT.@) + */ +void __cdecl MSVCRT__swab(char * src, char * dst, int len) +{ + if (len > 1) + { + len = (unsigned)len >> 1; + + while (len--) { + *dst++ = src[1]; + *dst++ = *src++; + src++; + } + } +} diff --git a/dlls/msvcrt/thread.c b/dlls/msvcrt/thread.c new file mode 100644 index 00000000000..cf84b048adf --- /dev/null +++ b/dlls/msvcrt/thread.c @@ -0,0 +1,34 @@ +/* + * msvcrt.dll thread functions + * + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + + +/********************************************************************* + * _beginthreadex (MSVCRT.@) + */ +unsigned long __cdecl MSVCRT__beginthreadex(void *sec, + unsigned int stack, + LPTHREAD_START_ROUTINE start, + void *arg, unsigned flag, + unsigned int*addr) +{ + TRACE("(%p,%d,%p,%p,%d,%p)\n",sec, stack,start, arg,flag,addr); + /* FIXME */ + return CreateThread( sec, stack, (LPTHREAD_START_ROUTINE)start, arg,flag,(LPDWORD)addr); +} + +/********************************************************************* + * _endthreadex (MSVCRT.@) + */ +void __cdecl MSVCRT__endthreadex(unsigned int retval) +{ + TRACE("(%d)\n",retval); + /* FIXME */ + ExitThread(retval); +} + diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c new file mode 100644 index 00000000000..4240f96abb6 --- /dev/null +++ b/dlls/msvcrt/time.c @@ -0,0 +1,99 @@ +/* + * msvcrt.dll date/time functions + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + */ +#include +#include +#include "msvcrt.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +typedef struct __MSVCRT_timeb +{ + time_t time; + unsigned short millitm; + short timezone; + short dstflag; +} MSVCRT_timeb; + + +/* INTERNAL: Return formatted current time/date */ +char * MSVCRT_get_current_time(char * out, const char * format) +{ + static const time_t bad_time = (time_t)-1; + time_t t; + struct tm *_tm = NULL; + char *retval = NULL; + + if (time(&t) != bad_time && (_tm = localtime(&t)) && + strftime(out,9,format,_tm) == 8) + retval = out; + if (_tm) + MSVCRT_free(_tm); + return retval; +} + +/********************************************************************** + * _strdate (MSVCRT.@) + */ +char * __cdecl MSVCRT__strdate (char * date) +{ + return MSVCRT_get_current_time(date,"%m/%d/%y"); +} + +/********************************************************************* + * _strtime (MSVCRT.@) + */ +char * __cdecl MSVCRT__strtime (char * date) +{ + return MSVCRT_get_current_time(date,"%H:%M:%S"); +} + +/********************************************************************* + * clock (MSVCRT.@) + */ +clock_t __cdecl MSVCRT_clock(void) +{ + struct tms alltimes; + clock_t res; + + times(&alltimes); + res = alltimes.tms_utime + alltimes.tms_stime + + alltimes.tms_cutime + alltimes.tms_cstime; + /* FIXME: We need some symbolic representation for CLOCKS_PER_SEC, + * 10 holds only for Windows/Linux_i86) + */ + return 10*res; +} + +/********************************************************************* + * difftime (MSVCRT.@) + */ +double __cdecl MSVCRT_difftime (time_t time1, time_t time2) +{ + return (double)(time1 - time2); +} + +/********************************************************************* + * time (MSVCRT.@) + */ +time_t __cdecl MSVCRT_time(time_t *buf) +{ + time_t curtime = time(NULL); + return buf ? *buf = curtime : curtime; +} + +/********************************************************************* + * _ftime (MSVCRT.@) + */ +void __cdecl MSVCRT__ftime (MSVCRT_timeb *buf) +{ + buf->time = MSVCRT_time(NULL); + buf->millitm = 0; /* FIXME */ + buf->timezone = 0; + buf->dstflag = 0; +} diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c new file mode 100644 index 00000000000..5a8116839a5 --- /dev/null +++ b/dlls/msvcrt/wcs.c @@ -0,0 +1,245 @@ +/* + * msvcrt.dll wide-char functions + * + * Copyright 1999 Alexandre Julliard + * Copyright 2000 Jon Griffiths + */ +#include "msvcrt.h" +#include "winnls.h" +#include "wine/unicode.h" + +DEFAULT_DEBUG_CHANNEL(msvcrt); + +/* INTERNAL: MSVCRT_malloc() based wstrndup */ +LPWSTR MSVCRT__wstrndup(LPCWSTR buf, unsigned int size) +{ + WCHAR* ret; + unsigned int len = strlenW(buf), max_len; + + max_len = size <= len? size : len + 1; + + ret = MSVCRT_malloc(max_len * sizeof (WCHAR)); + if (ret) + { + memcpy(ret,buf,max_len * sizeof (WCHAR)); + ret[max_len] = 0; + } + return ret; +} + +/********************************************************************* + * MSVCRT__wcsdup (MSVCRT.@) + */ +LPWSTR __cdecl MSVCRT__wcsdup( LPCWSTR str ) +{ + LPWSTR ret = NULL; + if (str) + { + int size = (strlenW(str) + 1) * sizeof(WCHAR); + ret = MSVCRT_malloc( size ); + if (ret) memcpy( ret, str, size ); + } + return ret; +} + +/********************************************************************* + * MSVCRT__wcsicoll (MSVCRT.@) + */ +INT __cdecl MSVCRT__wcsicoll( LPCWSTR str1, LPCWSTR str2 ) +{ + /* FIXME: handle collates */ + return strcmpiW( str1, str2 ); +} + +/********************************************************************* + * MSVCRT__wcsnset (MSVCRT.@) + */ +LPWSTR __cdecl MSVCRT__wcsnset( LPWSTR str, WCHAR c, INT n ) +{ + LPWSTR ret = str; + while ((n-- > 0) && *str) *str++ = c; + return ret; +} + +/********************************************************************* + * MSVCRT__wcsrev (MSVCRT.@) + */ +LPWSTR __cdecl MSVCRT__wcsrev( LPWSTR str ) +{ + LPWSTR ret = str; + LPWSTR end = str + strlenW(str) - 1; + while (end > str) + { + WCHAR t = *end; + *end-- = *str; + *str++ = t; + } + return ret; +} + +/********************************************************************* + * MSVCRT__wcsset (MSVCRT.@) + */ +LPWSTR __cdecl MSVCRT__wcsset( LPWSTR str, WCHAR c ) +{ + LPWSTR ret = str; + while (*str) *str++ = c; + return ret; +} + +/********************************************************************* + * MSVCRT_wcscoll (MSVCRT.@) + */ +DWORD __cdecl MSVCRT_wcscoll( LPCWSTR str1, LPCWSTR str2 ) +{ + /* FIXME: handle collates */ + return strcmpW( str1, str2 ); +} + +/********************************************************************* + * MSVCRT_wcspbrk (MSVCRT.@) + */ +LPWSTR __cdecl MSVCRT_wcspbrk( LPCWSTR str, LPCWSTR accept ) +{ + LPCWSTR p; + while (*str) + { + for (p = accept; *p; p++) if (*p == *str) return (LPWSTR)str; + str++; + } + return NULL; +} + +/********************************************************************* + * MSVCRT_wctomb (MSVCRT.@) + */ +INT __cdecl MSVCRT_wctomb( LPSTR dst, WCHAR ch ) +{ + return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL ); +} + +/********************************************************************* + * MSVCRT_iswalnum (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswalnum( WCHAR wc ) +{ + return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER); +} + +/********************************************************************* + * MSVCRT_iswalpha (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswalpha( WCHAR wc ) +{ + return get_char_typeW(wc) & (C1_ALPHA|C1_LOWER|C1_UPPER); +} + +/********************************************************************* + * MSVCRT_iswcntrl (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswcntrl( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_CNTRL; +} + +/********************************************************************* + * MSVCRT_iswdigit (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswdigit( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_DIGIT; +} + +/********************************************************************* + * MSVCRT_iswgraph (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswgraph( WCHAR wc ) +{ + return get_char_typeW(wc) & (C1_ALPHA|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER); +} + +/********************************************************************* + * MSVCRT_iswlower (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswlower( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_LOWER; +} + +/********************************************************************* + * MSVCRT_iswprint (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswprint( WCHAR wc ) +{ + return get_char_typeW(wc) & (C1_ALPHA|C1_BLANK|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER); +} + +/********************************************************************* + * MSVCRT_iswpunct (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswpunct( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_PUNCT; +} + +/********************************************************************* + * MSVCRT_iswspace (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswspace( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_SPACE; +} + +/********************************************************************* + * MSVCRT_iswupper (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswupper( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_UPPER; +} + +/********************************************************************* + * MSVCRT_iswxdigit (MSVCRT.@) + */ +INT __cdecl MSVCRT_iswxdigit( WCHAR wc ) +{ + return get_char_typeW(wc) & C1_XDIGIT; +} + +extern LPSTR __cdecl _itoa( long , LPSTR , INT); +extern LPSTR __cdecl _ultoa( long , LPSTR , INT); +extern LPSTR __cdecl _ltoa( long , LPSTR , INT); + +/********************************************************************* + * _itow (MSVCRT.@) + */ +WCHAR* __cdecl MSVCRT__itow(int value,WCHAR* out,int base) +{ + char buf[64]; + _itoa(value, buf, base); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buf, -1, out, 128); + return out; +} + +/********************************************************************* + * _ltow (MSVCRT.@) + */ +WCHAR* __cdecl MSVCRT__ltow(long value,WCHAR* out,int base) +{ + char buf[128]; + _ltoa(value, buf, base); + MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buf, -1, out, 128); + return out; +} + +/********************************************************************* + * _ultow (MSVCRT.@) + */ +WCHAR* __cdecl MSVCRT__ultow(unsigned long value,WCHAR* out,int base) +{ + char buf[128]; + _ultoa(value, buf, base); + MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, buf, -1, out, 128); + return out; +} + diff --git a/documentation/samples/config b/documentation/samples/config index d7e9c7741d5..f5116ae90ea 100644 --- a/documentation/samples/config +++ b/documentation/samples/config @@ -93,6 +93,7 @@ WINE REGISTRY Version 2 "dsound" = "builtin, native" "mmsystem" = "builtin" "winmm" = "builtin" +"msvcrt" = "native, builtin" "msvideo" = "builtin, native" "msvfw32" = "builtin, native" "mcicda.drv" = "builtin, native" diff --git a/loader/loadorder.c b/loader/loadorder.c index 5d5e0fcecbd..c03f128873b 100644 --- a/loader/loadorder.c +++ b/loader/loadorder.c @@ -43,6 +43,7 @@ static struct tagDllOverride { {"advapi32,crtdll,ntdll", "builtin,native"}, {"lz32,lzexpand", "builtin,native"}, {"version,ver", "builtin,native"}, + {"msvcrt", "native,builtin"}, /* "new" interface */ {"comdlg32,commdlg", "builtin,native"}, {"shell32,shell", "builtin,native"},