Implement setlocal/endlocal.

diff --git a/programs/wcmd/builtins.c b/programs/wcmd/builtins.c
index 760de85..060fc21 100644
--- a/programs/wcmd/builtins.c
+++ b/programs/wcmd/builtins.c
@@ -36,6 +36,14 @@
 
 void WCMD_execute (char *orig_command, char *parameter, char *substitution);
 
+struct env_stack
+{
+  struct env_stack *next;
+  WCHAR *strings;
+};
+
+struct env_stack *saved_environment;
+
 extern HINSTANCE hinst;
 extern char *inbuilt[];
 extern char nyi[];
@@ -507,6 +515,133 @@
 }
 
 /*****************************************************************************
+ * WCMD_dupenv
+ *
+ * Make a copy of the environment.
+ */
+WCHAR *WCMD_dupenv( const WCHAR *env )
+{
+  WCHAR *env_copy;
+  int len;
+
+  if( !env )
+    return NULL;
+
+  len = 0;
+  while ( env[len] )
+    len += (lstrlenW(&env[len]) + 1);
+
+  env_copy = LocalAlloc (LMEM_FIXED, (len+1) * sizeof (WCHAR) );
+  if (!env_copy)
+  {
+    WCMD_output ("out of memory\n");
+    return env_copy;
+  }
+  memcpy (env_copy, env, len*sizeof (WCHAR));
+  env_copy[len] = 0;
+
+  return env_copy;
+}
+
+/*****************************************************************************
+ * WCMD_setlocal
+ *
+ *  setlocal pushes the environment onto a stack
+ *  Save the environment as unicode so we don't screw anything up.
+ */
+void WCMD_setlocal (const char *s) {
+  WCHAR *env;
+  struct env_stack *env_copy;
+
+  /* DISABLEEXTENSIONS ignored */
+
+  env_copy = LocalAlloc (LMEM_FIXED, sizeof (struct env_stack));
+  if( !env_copy )
+  {
+    WCMD_output ("out of memory\n");
+    return;
+  }
+
+  env = GetEnvironmentStringsW ();
+
+  env_copy->strings = WCMD_dupenv (env);
+  if (env_copy->strings)
+  {
+    env_copy->next = saved_environment;
+    saved_environment = env_copy;
+  }
+  else
+    LocalFree (env_copy);
+
+  FreeEnvironmentStringsW (env);
+}
+
+/*****************************************************************************
+ * WCMD_strchrW
+ */
+inline WCHAR *WCMD_strchrW(WCHAR *str, WCHAR ch)
+{
+   while(*str)
+   {
+     if(*str == ch)
+       return str;
+     str++;
+   }
+   return NULL;
+}
+
+/*****************************************************************************
+ * WCMD_endlocal
+ *
+ *  endlocal pops the environment off a stack
+ */
+void WCMD_endlocal (void) {
+  WCHAR *env, *old, *p;
+  struct env_stack *temp;
+  int len, n;
+
+  if (!saved_environment)
+    return;
+
+  /* pop the old environment from the stack */
+  temp = saved_environment;
+  saved_environment = temp->next;
+
+  /* delete the current environment, totally */
+  env = GetEnvironmentStringsW ();
+  old = WCMD_dupenv (GetEnvironmentStringsW ());
+  len = 0;
+  while (old[len]) {
+    n = lstrlenW(&old[len]) + 1;
+    p = WCMD_strchrW(&old[len], '=');
+    if (p)
+    {
+      *p++ = 0;
+      SetEnvironmentVariableW (&old[len], NULL);
+    }
+    len += n;
+  }
+  LocalFree (old);
+  FreeEnvironmentStringsW (env);
+  
+  /* restore old environment */
+  env = temp->strings;
+  len = 0;
+  while (env[len]) {
+    n = lstrlenW(&env[len]) + 1;
+    p = WCMD_strchrW(&env[len], '=');
+    if (p)
+    {
+      *p++ = 0;
+      SetEnvironmentVariableW (&env[len], p);
+    }
+    len += n;
+  }
+  LocalFree (env);
+  LocalFree (temp);
+}
+
+/*****************************************************************************
  * WCMD_setshow_attrib
  *
  * Display and optionally sets DOS attributes on a file or directory