diff --git a/programs/wcmd/builtins.c b/programs/wcmd/builtins.c index 760de85dfa3..060fc21b37d 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[]; @@ -506,6 +514,133 @@ int status; 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); +} + /***************************************************************************** * WCMD_setshow_attrib * diff --git a/programs/wcmd/wcmd.h b/programs/wcmd/wcmd.h index 88c5a1965ea..09aaa3545d0 100644 --- a/programs/wcmd/wcmd.h +++ b/programs/wcmd/wcmd.h @@ -35,6 +35,7 @@ void WCMD_create_dir (void); 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 @@ int WCMD_read_console (char *string, int str_len); 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 @@ typedef struct { #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 diff --git a/programs/wcmd/wcmdmain.c b/programs/wcmd/wcmdmain.c index 2def204e480..3fd5a74bde6 100644 --- a/programs/wcmd/wcmdmain.c +++ b/programs/wcmd/wcmdmain.c @@ -31,7 +31,8 @@ const char *inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY", "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; @@ -427,6 +428,12 @@ void WCMD_process_command (char *command) 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); break;