--- /dev/null
+/* $Id$
+ *
+ * dllmain.c
+ *
+ * ReactOS MSVCRT.DLL Compatibility Library
+ */
+
+#include "precomp.h"
+#include <msvcrt/internal/tls.h>
+#include <msvcrt/stdlib.h>
+#include <msvcrt/string.h>
+
+#define NDEBUG
+#include <msvcrt/msvcrtdbg.h>
+
+
+unsigned int _osver = 0;
+unsigned int _winminor = 0;
+unsigned int _winmajor = 0;
+unsigned int _winver = 0;
+
+
+char *_acmdln = NULL; /* pointer to ascii command line */
+wchar_t *_wcmdln = NULL; /* pointer to wide character command line */
+#undef _environ
+#undef _wenviron
+char **_environ = NULL; /* pointer to environment block */
+wchar_t **_wenviron = NULL; /* pointer to environment block */
+char **__initenv = NULL; /* pointer to initial environment block */
+wchar_t **__winitenv = NULL; /* pointer to initial environment block */
+#undef _pgmptr
+char *_pgmptr = NULL; /* pointer to program name */
+int __app_type = 0; //_UNKNOWN_APP; /* application type */
+int __mb_cur_max = 1;
+
+int _commode = _IOCOMMIT;
+
+
+int BlockEnvToEnvironA(void)
+{
+ char *ptr, *environment_strings;
+ char **envptr;
+ int count = 1, len;
+
+ DPRINT("BlockEnvToEnvironA()\n");
+
+ environment_strings = GetEnvironmentStringsA();
+ if (environment_strings == NULL) {
+ return -1;
+ }
+
+ for (ptr = environment_strings; *ptr; ptr += len)
+ {
+ len = strlen(ptr) + 1;
+ /* Skip drive letter settings. */
+ if (*ptr != '=')
+ count++;
+ }
+
+ __initenv = _environ = malloc(count * sizeof(char*));
+ if (_environ)
+ {
+ for (ptr = environment_strings, envptr = _environ; count > 1; ptr += len)
+ {
+ len = strlen(ptr) + 1;
+ /* Skip drive letter settings. */
+ if (*ptr != '=')
+ {
+ if ((*envptr = malloc(len)) == NULL)
+ {
+ for (envptr--; envptr >= _environ; envptr--);
+ free(*envptr);
+ FreeEnvironmentStringsA(environment_strings);
+ free(_environ);
+ __initenv = _environ = NULL;
+ return -1;
+ }
+ memcpy(*envptr++, ptr, len);
+ count--;
+ }
+ }
+ /* Add terminating NULL entry. */
+ *envptr = NULL;
+ }
+
+ FreeEnvironmentStringsA(environment_strings);
+ return _environ ? 0 : -1;
+}
+
+int BlockEnvToEnvironW(void)
+{
+ wchar_t *ptr, *environment_strings;
+ wchar_t **envptr;
+ int count = 1, len;
+
+ DPRINT("BlockEnvToEnvironW()\n");
+
+ environment_strings = GetEnvironmentStringsW();
+ if (environment_strings == NULL) {
+ return -1;
+ }
+
+ for (ptr = environment_strings; *ptr; ptr += len)
+ {
+ len = wcslen(ptr) + 1;
+ /* Skip drive letter settings. */
+ if (*ptr != '=')
+ count++;
+ }
+
+ __winitenv = _wenviron = malloc(count * sizeof(wchar_t*));
+ if (_wenviron)
+ {
+ for (ptr = environment_strings, envptr = _wenviron; count > 1; ptr += len)
+ {
+ len = wcslen(ptr) + 1;
+ /* Skip drive letter settings. */
+ if (*ptr != '=')
+ {
+ if ((*envptr = malloc(len * sizeof(wchar_t))) == NULL)
+ {
+ for (envptr--; envptr >= _wenviron; envptr--);
+ free(*envptr);
+ FreeEnvironmentStringsW(environment_strings);
+ free(_wenviron);
+ __winitenv = _wenviron = NULL;
+ return -1;
+ }
+ memcpy(*envptr++, ptr, len * sizeof(wchar_t));
+ count--;
+ }
+ }
+ /* Add terminating NULL entry. */
+ *envptr = NULL;
+ }
+
+ FreeEnvironmentStringsW(environment_strings);
+ return _wenviron ? 0 : -1;
+}
+
+/**
+ * Internal function to duplicate environment block. Although it's
+ * parameter are defined as char**, it's able to work also with
+ * wide character environment block which are of type wchar_t**.
+ *
+ * @param original_environment
+ * Environment to duplicate.
+ * @param wide
+ * Set to zero for multibyte environments, non-zero otherwise.
+ *
+ * @return Original environment in case of failure, otherwise
+ * pointer to new environment block.
+ */
+char **DuplicateEnvironment(char **original_environment, int wide)
+{
+ int count = 1;
+ char **envptr, **newenvptr, **newenv;
+
+ for (envptr = original_environment; *envptr != NULL; envptr++, count++)
+ ;
+
+ newenvptr = newenv = malloc(count * sizeof(char*));
+ if (newenv == NULL)
+ return original_environment;
+
+ for (envptr = original_environment; count > 1; newenvptr++, count--)
+ {
+ if (wide)
+ *newenvptr = (char*)_wcsdup((wchar_t*)*envptr++);
+ else
+ *newenvptr = _strdup(*envptr++);
+ if (*newenvptr == NULL)
+ {
+ for (newenvptr--; newenvptr >= newenv; newenvptr--);
+ free(*newenvptr);
+ free(newenv);
+ return original_environment;
+ }
+ }
+
+ return newenv;
+}
+
+/**
+ * Internal function to deallocate environment block. Although it's
+ * parameter are defined as char**, it's able to work also with
+ * wide character environment block which are of type wchar_t**.
+ *
+ * @param environment
+ * Environment to free.
+ */
+void FreeEnvironment(char **environment)
+{
+ char **envptr;
+ for (envptr = environment; *envptr != NULL; envptr++)
+ free(*envptr);
+ free(environment);
+}
+
+/**
+ * Internal version of _wputenv and _putenv. It works duplicates the
+ * original envirnments created during initilization if needed to prevent
+ * having spurious pointers floating around. Then it updates the internal
+ * environment tables (_environ and _wenviron) and at last updates the
+ * OS environemnt.
+ *
+ * Note that there can happen situation when the internal [_w]environ
+ * arrays will be updated, but the OS environment update will fail. In
+ * this case we don't undo the changes to the [_w]environ tables to
+ * comply with the Microsoft behaviour (and it's also much easier :-).
+ */
+int SetEnv(const wchar_t *option)
+{
+ wchar_t *epos, *name;
+ wchar_t **wenvptr;
+ wchar_t *woption;
+ char *mboption;
+ int remove, index, count, size, result = 0, found = 0;
+
+ if (option == NULL || (epos = wcschr(option, L'=')) == NULL)
+ return -1;
+ remove = (epos[1] == 0);
+
+ /* Duplicate environment if needed. */
+ if (_environ == __initenv)
+ {
+ if ((_environ = DuplicateEnvironment(_environ, 0)) == __initenv)
+ return -1;
+ }
+ if (_wenviron == __winitenv)
+ {
+ if ((_wenviron = (wchar_t**)DuplicateEnvironment((char**)_wenviron, 1)) ==
+ __winitenv)
+ return -1;
+ }
+
+ /* Create a copy of the option name. */
+ name = malloc((epos - option + 1) * sizeof(wchar_t));
+ if (name == NULL)
+ return -1;
+ memcpy(name, option, (epos - option) * sizeof(wchar_t));
+ name[epos - option] = 0;
+
+ /* Find the option we're trying to modify. */
+ for (index = 0, wenvptr = _wenviron; *wenvptr != NULL; wenvptr++, index++)
+ {
+ if (!_wcsnicmp(*wenvptr, option, epos - option))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (remove)
+ {
+ if (!found)
+ {
+ free(name);
+ return -1;
+ }
+
+ /* Remove the option from wide character environment. */
+ free(*wenvptr);
+ for (count = index; *wenvptr != NULL; wenvptr++, count++)
+ *wenvptr = *(wenvptr + 1);
+ _wenviron = realloc(_wenviron, count * sizeof(wchar_t*));
+
+ /* Remove the option from multibyte environment. We assume
+ * the environments are in sync and the option is at the
+ * same position. */
+ free(_environ[index]);
+ for (; _environ[index] != NULL; index++)
+ _environ[index] = _environ[index + 1];
+ _environ = realloc(_environ, count * sizeof(char*));
+
+ result = SetEnvironmentVariableW(name, NULL) ? 0 : -1;
+ }
+ else
+ {
+ /* Make a copy of the option that we will store in the environment block. */
+ woption = _wcsdup((wchar_t*)option);
+ if (woption == NULL)
+ {
+ free(name);
+ return -1;
+ }
+
+ /* Create a multibyte copy of the option. */
+ size = WideCharToMultiByte(CP_ACP, 0, option, -1, NULL, 0, NULL, NULL);
+ mboption = malloc(size);
+ if (mboption == NULL)
+ {
+ free(name);
+ free(woption);
+ return -1;
+ }
+ WideCharToMultiByte(CP_ACP, 0, option, -1, mboption, size, NULL, NULL);
+
+ if (found)
+ {
+ /* Replace the current entry. */
+ free(*wenvptr);
+ *wenvptr = woption;
+ free(_environ[index]);
+ _environ[index] = mboption;
+ }
+ else
+ {
+ wchar_t **wnewenv;
+ char **mbnewenv;
+
+ /* Get the size of the original environment. */
+ for (count = index; *wenvptr != NULL; wenvptr++, count++)
+ ;
+
+ /* Create a new entry. */
+ if ((wnewenv = realloc(_wenviron, (count + 2) * sizeof(wchar_t*))) == NULL)
+ {
+ free(name);
+ free(mboption);
+ free(woption);
+ return -1;
+ }
+ _wenviron = wnewenv;
+ if ((mbnewenv = realloc(_environ, (count + 2) * sizeof(char*))) == NULL)
+ {
+ free(name);
+ free(mboption);
+ free(woption);
+ return -1;
+ }
+ _environ = mbnewenv;
+
+ /* Set the last entry to our option. */
+ _wenviron[count] = woption;
+ _environ[count] = mboption;
+ _wenviron[count + 1] = NULL;
+ _environ[count + 1] = NULL;
+ }
+
+ /* And finally update the OS environment. */
+ result = SetEnvironmentVariableW(name, epos + 1) ? 0 : -1;
+ }
+ free(name);
+
+ return result;
+}
+
+/*
+ * @implemented
+ */
+int *__p__commode(void) // not exported by NTDLL
+{
+ return &_commode;
+}
+
+/*
+ * @implemented
+ */
+void __set_app_type(int app_type)
+{
+ __app_type = app_type;
+}
+
+/*
+ * @implemented
+ */
+char **__p__acmdln(void)
+{
+ return &_acmdln;
+}
+
+/*
+ * @implemented
+ */
+char ***__p__environ(void)
+{
+ return &_environ;
+}
+
+/*
+ * @implemented
+ */
+wchar_t ***__p__wenviron(void)
+{
+ return &_wenviron;
+}
+
+/*
+ * @implemented
+ */
+char ***__p___initenv(void)
+{
+ return &__initenv;
+}
+
+/*
+ * @implemented
+ */
+wchar_t ***__p___winitenv(void)
+{
+ return &__winitenv;
+}
+
+/*
+ * @implemented
+ */
+int *__p___mb_cur_max(void)
+{
+ return &__mb_cur_max;
+}
+
+/*
+ * @implemented
+ */
+unsigned int *__p__osver(void)
+{
+ return &_osver;
+}
+
+/*
+ * @implemented
+ */
+char **__p__pgmptr(void)
+{
+ return &_pgmptr;
+}
+
+/*
+ * @implemented
+ */
+unsigned int *__p__winmajor(void)
+{
+ return &_winmajor;
+}
+
+/*
+ * @implemented
+ */
+unsigned int *__p__winminor(void)
+{
+ return &_winminor;
+}
+
+/*
+ * @implemented
+ */
+unsigned int *__p__winver(void)
+{
+ return &_winver;
+}
+
+/* EOF */