From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/builtins.c | 26 +++++++++++++++++ programs/cmd/wcmd.h | 4 ++- programs/cmd/wcmdmain.c | 64 +++++++++++++++-------------------------- 3 files changed, 52 insertions(+), 42 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 149d34571e5..c81d83f8c66 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -86,6 +86,7 @@ const WCHAR inbuilt[][10] = { L"MORE", L"CHOICE", L"MKLINK", + L"", L"EXIT" }; static const WCHAR externals[][10] = { @@ -4154,3 +4155,28 @@ RETURN_CODE WCMD_mklink(WCHAR *args) WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), file1); return errorlevel = ERROR_INVALID_FUNCTION; } + +RETURN_CODE WCMD_change_drive(WCHAR drive) +{ + WCHAR envvar[4]; + WCHAR dir[MAX_PATH]; + + /* According to MSDN CreateProcess docs, special env vars record + * the current directory on each drive, in the form =C: + * so see if one specified, and if so go back to it + */ + envvar[0] = L'='; + envvar[1] = drive; + envvar[2] = L':'; + envvar[3] = L'\0'; + + if (GetEnvironmentVariableW(envvar, dir, ARRAY_SIZE(dir)) == 0) + wcscpy(dir, envvar + 1); + WINE_TRACE("Got directory for %lc: as %s\n", drive, wine_dbgstr_w(dir)); + if (!SetCurrentDirectoryW(dir)) + { + WCMD_print_error(); + return errorlevel = ERROR_INVALID_FUNCTION; + } + return NO_ERROR; +} diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index cf51a5e44de..1f9cfa54eda 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -201,6 +201,7 @@ RETURN_CODE WCMD_verify(void); RETURN_CODE WCMD_version(void); RETURN_CODE WCMD_volume(void); RETURN_CODE WCMD_mklink(WCHAR *args); +RETURN_CODE WCMD_change_drive(WCHAR drive);
WCHAR *WCMD_fgets (WCHAR *buf, DWORD n, HANDLE stream); WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, BOOL raw, BOOL wholecmdline); @@ -395,9 +396,10 @@ extern BOOL delayedsubst; #define WCMD_MORE 43 #define WCMD_CHOICE 44 #define WCMD_MKLINK 45 +#define WCMD_CHGDRIVE 46
/* Must be last in list */ -#define WCMD_EXIT 46 +#define WCMD_EXIT 47
/* Some standard messages */ extern WCHAR anykey[]; diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 8a7b5cfbdaa..37953ab19c5 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -644,7 +644,7 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start, WCHAR startchar) }
/* Command line - just ignore this */ - if (context == NULL) return endOfVar+1; + if (context == NULL || startchar == L'!') return endOfVar+1;
/* Batch - replace unknown env var with nothing */ if (colonpos == NULL) @@ -829,7 +829,8 @@ static void handleExpansion(WCHAR *cmd, BOOL atExecute) { p++; } else p+=2; - + } else if (*(p+1) == startchar && startchar == L'!') { + p++; /* Replace %~ modifications if in batch program */ } else if (*(p+1) == '~') { WCMD_HandleTildeModifiers(&p, atExecute); @@ -1767,48 +1768,27 @@ static RETURN_CODE execute_single_command(const WCHAR *command)
TRACE("Command: '%s'\n", wine_dbgstr_w(cmd));
- /* Check if the command entered is internal, and identify which one */ - count = 0; - while (IsCharAlphaNumericW(cmd[count])) { - count++; + /* Changing default drive has to be handled as a special case, anything + * else if it exists after whitespace is ignored + */ + if (cmd[1] == L':' && (!cmd[2] || iswspace(cmd[2]))) { + cmd_index = WCMD_CHGDRIVE; + count = 0; } - for (cmd_index=0; cmd_index<=WCMD_EXIT; cmd_index++) { - if (count && CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, - cmd, count, inbuilt[cmd_index], -1) == CSTR_EQUAL) break; + else + { + /* Check if the command entered is internal, and identify which one */ + count = 0; + while (IsCharAlphaNumericW(cmd[count])) { + count++; + } + for (cmd_index=0; cmd_index<=WCMD_EXIT; cmd_index++) { + if (count && CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, + cmd, count, inbuilt[cmd_index], -1) == CSTR_EQUAL) break; + } } parms_start = WCMD_skip_leading_spaces(&cmd[count]);
-/* - * Changing default drive has to be handled as a special case, anything - * else if it exists after whitespace is ignored - */ - - if (cmd[1] == L':' && (!cmd[2] || iswspace(cmd[2]))) { - WCHAR envvar[5]; - WCHAR dir[MAX_PATH]; - - /* Ignore potential garbage on the same line */ - cmd[2] = L'\0'; - - /* According to MSDN CreateProcess docs, special env vars record - the current directory on each drive, in the form =C: - so see if one specified, and if so go back to it */ - lstrcpyW(envvar, L"="); - lstrcatW(envvar, cmd); - if (GetEnvironmentVariableW(envvar, dir, ARRAY_SIZE(dir)) == 0) { - wsprintfW(cmd, L"%s\", cmd); - WINE_TRACE("No special directory settings, using dir of %s\n", wine_dbgstr_w(cmd)); - } - WINE_TRACE("Got directory %s as %s\n", wine_dbgstr_w(envvar), wine_dbgstr_w(cmd)); - if (!SetCurrentDirectoryW(cmd)) - { - WCMD_print_error(); - return_code = errorlevel = ERROR_INVALID_FUNCTION; - } - else return_code = NO_ERROR; - goto cleanup; - } - WCMD_parse(parms_start, quals, param1, param2); TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2));
@@ -1940,6 +1920,9 @@ static RETURN_CODE execute_single_command(const WCHAR *command) case WCMD_MKLINK: return_code = WCMD_mklink(parms_start); break; + case WCMD_CHGDRIVE: + return_code = WCMD_change_drive(cmd[0]); + break; case WCMD_EXIT: return_code = WCMD_exit(); break; @@ -1949,7 +1932,6 @@ static RETURN_CODE execute_single_command(const WCHAR *command) echo_mode = prev_echo_mode; }
-cleanup: free(cmd); return return_code; }