From 1db20bfd33f9c1486a1a662c2f78f45d00caf24b Mon Sep 17 00:00:00 2001
From: Jon Griffiths <jon_p_griffiths@yahoo.com>
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 <math.h>
+#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<end)
+  {
+    if (*current)
+    {
+      TRACE("Call init function %p\n",*current);
+      (**current)();
+      TRACE("returned\n");
+    }
+    current++;
+  }
+  return 0;
+}
+
+/*********************************************************************
+ *		__set_app_type (MSVCRT.@)
+ */
+void __cdecl MSVCRT___set_app_type(int app_type)
+{
+  TRACE("(%d) %s application\n", app_type, app_type == 2 ? "Gui" : "Console");
+  MSVCRT_app_type = app_type;
+}
diff --git a/dlls/msvcrt/dir.c b/dlls/msvcrt/dir.c
new file mode 100644
index 00000000000..84cdb625ed2
--- /dev/null
+++ b/dlls/msvcrt/dir.c
@@ -0,0 +1,780 @@
+/*
+ * msvcrt.dll drive/directory functions
+ *
+ * Copyright 1996,1998 Marcus Meissner
+ * Copyright 1996 Jukka Iivonen
+ * Copyright 1997,2000 Uwe Bonnes
+ * Copyright 2000 Jon Griffiths
+ */
+
+#include <time.h>
+#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 <setjmp.h>
+#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 <time.h>
+#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 <math.h>
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#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 <stdlib.h> /* 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 <stdarg.h>
+
+/* 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 <time.h>
+#include <sys/times.h>
+#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"},
-- 
GitLab