WCMD: implement setlocal/endlocal

Mike McCormack mike at codeweavers.com
Thu Mar 18 20:22:39 CST 2004


ChangeLog:
* implement setlocal/endlocal
-------------- next part --------------
? programs/wcmd/wcmd.exe.spec.c
Index: programs/wcmd/builtins.c
===================================================================
RCS file: /home/wine/wine/programs/wcmd/builtins.c,v
retrieving revision 1.22
diff -u -r1.22 builtins.c
--- programs/wcmd/builtins.c	18 Mar 2004 04:01:32 -0000	1.22
+++ programs/wcmd/builtins.c	19 Mar 2004 01:34:40 -0000
@@ -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[];
@@ -504,6 +512,133 @@
   }
   status = MoveFile (param1, param2);
   if (!status) WCMD_print_error ();
+}
+
+/*****************************************************************************
+ * 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);
 }
 
 /*****************************************************************************
Index: programs/wcmd/wcmd.h
===================================================================
RCS file: /home/wine/wine/programs/wcmd/wcmd.h,v
retrieving revision 1.13
diff -u -r1.13 wcmd.h
--- programs/wcmd/wcmd.h	13 Dec 2003 03:22:02 -0000	1.13
+++ programs/wcmd/wcmd.h	19 Mar 2004 01:34:40 -0000
@@ -35,6 +35,7 @@
 void WCMD_delete (int recurse);
 void WCMD_directory (void);
 void WCMD_echo (const char *);
+void WCMD_endlocal (void);
 void WCMD_enter_paged_mode(void);
 void WCMD_for (char *);
 void WCMD_give_help (char *command);
@@ -53,6 +54,7 @@
 void WCMD_remove_dir (void);
 void WCMD_rename (void);
 void WCMD_run_program (char *command);
+void WCMD_setlocal (const char *command);
 void WCMD_setshow_attrib (void);
 void WCMD_setshow_date (void);
 void WCMD_setshow_default (void);
@@ -130,5 +132,8 @@
 #define WCMD_VER    34
 #define WCMD_VOL    35
 
+#define WCMD_ENDLOCAL 36
+#define WCMD_SETLOCAL 37
+
 /* Must be last in list */
-#define WCMD_EXIT   36
+#define WCMD_EXIT   38
Index: programs/wcmd/wcmdmain.c
===================================================================
RCS file: /home/wine/wine/programs/wcmd/wcmdmain.c,v
retrieving revision 1.40
diff -u -r1.40 wcmdmain.c
--- programs/wcmd/wcmdmain.c	18 Mar 2004 04:01:32 -0000	1.40
+++ programs/wcmd/wcmdmain.c	19 Mar 2004 01:34:40 -0000
@@ -31,7 +31,8 @@
 		"DATE", "DEL", "DIR", "ECHO", "ERASE", "FOR", "GOTO",
 		"HELP", "IF", "LABEL", "MD", "MKDIR", "MOVE", "PATH", "PAUSE",
 		"PROMPT", "REM", "REN", "RENAME", "RD", "RMDIR", "SET", "SHIFT",
-		"TIME", "TITLE", "TYPE", "VERIFY", "VER", "VOL", "EXIT"  };
+                "TIME", "TITLE", "TYPE", "VERIFY", "VER", "VOL", 
+                "ENDLOCAL", "SETLOCAL", "EXIT" };
 
 HINSTANCE hinst;
 DWORD errorlevel;
@@ -426,6 +427,12 @@
       case WCMD_RD:
       case WCMD_RMDIR:
         WCMD_remove_dir ();
+        break;
+      case WCMD_SETLOCAL:
+        WCMD_setlocal(p);
+        break;
+      case WCMD_ENDLOCAL:
+        WCMD_endlocal();
         break;
       case WCMD_SET:
         WCMD_setshow_env (p);


More information about the wine-patches mailing list