[CMD]: Diverse improvements:

- Add pre-support for "enable extensions".
- Load CMD settings at startup from the registry (from HKLM and HKCU
  Software\\Microsoft\\Command Processor reg key), as done by Windows' CMD.EXE.
- Add support for CMD.EXE /E(:OFF), /X, /Y command-line switches.
- Correctly set the console colors when using CMD.EXE /T: switch.
- Start support for two control characters for the completion: the standard CompletionChar
  and the PathCompletionChar (if one desires to autocomplete *just* directory
  names -- or associated -- but not everything), as Windows' CMD.EXE offers.

svn path=/trunk/; revision=75997
This commit is contained in:
Hermès Bélusca-Maïto 2017-09-30 11:39:08 +00:00
parent 7d6b5d99a6
commit cd45987d1a
4 changed files with 256 additions and 41 deletions

View file

@ -162,6 +162,7 @@ INT nErrorLevel = 0; /* Errorlevel of last launched external program */
CRITICAL_SECTION ChildProcessRunningLock; CRITICAL_SECTION ChildProcessRunningLock;
BOOL bUnicodeOutput = FALSE; BOOL bUnicodeOutput = FALSE;
BOOL bDisableBatchEcho = FALSE; BOOL bDisableBatchEcho = FALSE;
BOOL bEnableExtensions = TRUE;
BOOL bDelayedExpansion = FALSE; BOOL bDelayedExpansion = FALSE;
BOOL bTitleSet = FALSE; BOOL bTitleSet = FALSE;
DWORD dwChildProcessId = 0; DWORD dwChildProcessId = 0;
@ -174,7 +175,7 @@ static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL;
static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL; static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL;
#ifdef INCLUDE_CMD_COLOR #ifdef INCLUDE_CMD_COLOR
WORD wDefColor; /* default color */ WORD wDefColor = 0; /* Default color */
#endif #endif
/* /*
@ -1532,14 +1533,164 @@ ShowCommands (VOID)
} }
#endif #endif
static VOID static VOID
ExecuteAutoRunFile(HKEY hkeyRoot) LoadRegistrySettings(HKEY hKeyRoot)
{
LONG lRet;
HKEY hKey;
/*
* Buffer big enough to hold the string L"4294967295",
* corresponding to the literal 0xFFFFFFFF (MAX_ULONG) in decimal.
*/
DWORD Buffer[6];
DWORD dwType, len;
lRet = RegOpenKeyEx(hKeyRoot,
_T("Software\\Microsoft\\Command Processor"),
0,
KEY_QUERY_VALUE,
&hKey);
if (lRet != ERROR_SUCCESS)
return;
#ifdef INCLUDE_CMD_COLOR
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("DefaultColor"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default attributes */
if (dwType == REG_DWORD)
wDefColor = (WORD)*(PDWORD)Buffer;
else if (dwType == REG_SZ)
wDefColor = (WORD)_tcstol((PTSTR)Buffer, NULL, 0);
}
// else, use the default attributes retrieved before.
#endif
#if 0
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("DisableUNCCheck"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default setting */
if (dwType == REG_DWORD)
bDisableUNCCheck = !!*(PDWORD)Buffer;
else if (dwType == REG_SZ)
bDisableUNCCheck = (_ttol((PTSTR)Buffer) == 1);
}
// else, use the default setting set globally.
#endif
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("DelayedExpansion"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default setting */
if (dwType == REG_DWORD)
bDelayedExpansion = !!*(PDWORD)Buffer;
else if (dwType == REG_SZ)
bDelayedExpansion = (_ttol((PTSTR)Buffer) == 1);
}
// else, use the default setting set globally.
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("EnableExtensions"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default setting */
if (dwType == REG_DWORD)
bEnableExtensions = !!*(PDWORD)Buffer;
else if (dwType == REG_SZ)
bEnableExtensions = (_ttol((PTSTR)Buffer) == 1);
}
// else, use the default setting set globally.
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("CompletionChar"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default setting */
if (dwType == REG_DWORD)
AutoCompletionChar = (TCHAR)*(PDWORD)Buffer;
else if (dwType == REG_SZ)
AutoCompletionChar = (TCHAR)_tcstol((PTSTR)Buffer, NULL, 0);
}
// else, use the default setting set globally.
/* Validity check */
if (IS_COMPLETION_DISABLED(AutoCompletionChar))
{
/* Disable autocompletion */
AutoCompletionChar = 0x20;
}
len = sizeof(Buffer);
lRet = RegQueryValueEx(hKey,
_T("PathCompletionChar"),
NULL,
&dwType,
(LPBYTE)&Buffer,
&len);
if (lRet == ERROR_SUCCESS)
{
/* Overwrite the default setting */
if (dwType == REG_DWORD)
PathCompletionChar = (TCHAR)*(PDWORD)Buffer;
else if (dwType == REG_SZ)
PathCompletionChar = (TCHAR)_tcstol((PTSTR)Buffer, NULL, 0);
}
// else, use the default setting set globally.
/* Validity check */
if (IS_COMPLETION_DISABLED(PathCompletionChar))
{
/* Disable autocompletion */
PathCompletionChar = 0x20;
}
/* Adjust completion chars */
if (PathCompletionChar >= 0x20 && AutoCompletionChar < 0x20)
PathCompletionChar = AutoCompletionChar;
else if (AutoCompletionChar >= 0x20 && PathCompletionChar < 0x20)
AutoCompletionChar = PathCompletionChar;
RegCloseKey(hKey);
}
static VOID
ExecuteAutoRunFile(HKEY hKeyRoot)
{ {
TCHAR autorun[2048]; TCHAR autorun[2048];
DWORD len = sizeof autorun; DWORD len = sizeof autorun;
HKEY hkey; HKEY hkey;
if (RegOpenKeyEx(hkeyRoot, if (RegOpenKeyEx(hKeyRoot,
_T("SOFTWARE\\Microsoft\\Command Processor"), _T("SOFTWARE\\Microsoft\\Command Processor"),
0, 0,
KEY_READ, KEY_READ,
@ -1612,18 +1763,45 @@ GetCmdLineCommand(TCHAR *commandline, TCHAR *ptr, BOOL AlwaysStrip)
_tcscpy(commandline, ptr); _tcscpy(commandline, ptr);
} }
#ifdef INCLUDE_CMD_COLOR
BOOL ConGetDefaultAttributes(PWORD pwDefAttr)
{
BOOL Success;
HANDLE hConsole;
CONSOLE_SCREEN_BUFFER_INFO csbi;
/* Do not modify *pwDefAttr if we fail, in which case use default attributes */
hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE; // No default console
Success = GetConsoleScreenBufferInfo(hConsole, &csbi);
if (Success)
*pwDefAttr = csbi.wAttributes;
CloseHandle(hConsole);
return Success;
}
#endif
/* /*
* set up global initializations and process parameters * Set up global initializations and process parameters
*/ */
static VOID static VOID
Initialize() Initialize(VOID)
{ {
HMODULE NtDllModule; HMODULE NtDllModule;
TCHAR commandline[CMDLINE_LENGTH]; TCHAR commandline[CMDLINE_LENGTH];
TCHAR ModuleName[_MAX_PATH + 1]; TCHAR ModuleName[_MAX_PATH + 1];
INT nExitCode; INT nExitCode;
//INT len;
TCHAR *ptr, *cmdLine, option = 0; TCHAR *ptr, *cmdLine, option = 0;
BOOL AlwaysStrip = FALSE; BOOL AlwaysStrip = FALSE;
BOOL AutoRun = TRUE; BOOL AutoRun = TRUE;
@ -1641,9 +1819,14 @@ Initialize()
NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory"); NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
} }
/* Load the registry settings */
LoadRegistrySettings(HKEY_LOCAL_MACHINE);
LoadRegistrySettings(HKEY_CURRENT_USER);
/* Initialize our locale */
InitLocale(); InitLocale();
/* get default input and output console handles */ /* Get default input and output console handles */
hOut = GetStdHandle(STD_OUTPUT_HANDLE); hOut = GetStdHandle(STD_OUTPUT_HANDLE);
hIn = GetStdHandle(STD_INPUT_HANDLE); hIn = GetStdHandle(STD_INPUT_HANDLE);
@ -1651,17 +1834,17 @@ Initialize()
InitPrompt(); InitPrompt();
#ifdef FEATURE_DIR_STACK #ifdef FEATURE_DIR_STACK
/* initialize directory stack */ /* Initialize directory stack */
InitDirectoryStack(); InitDirectoryStack();
#endif #endif
#ifdef FEATURE_HISTORY #ifdef FEATURE_HISTORY
/*initialize history*/ /* Initialize history */
InitHistory(); InitHistory();
#endif #endif
/* Set COMSPEC environment variable */ /* Set COMSPEC environment variable */
if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1)) if (GetModuleFileName(NULL, ModuleName, ARRAYSIZE(ModuleName)) != 0)
{ {
ModuleName[_MAX_PATH] = _T('\0'); ModuleName[_MAX_PATH] = _T('\0');
SetEnvironmentVariable (_T("COMSPEC"), ModuleName); SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
@ -1731,9 +1914,8 @@ Initialize()
#ifdef INCLUDE_CMD_COLOR #ifdef INCLUDE_CMD_COLOR
else if (!_tcsnicmp(ptr, _T("/T:"), 3)) else if (!_tcsnicmp(ptr, _T("/T:"), 3))
{ {
/* process /T (color) argument */ /* Process /T (color) argument; overwrite any previous settings */
wDefColor = (WORD)_tcstoul(&ptr[3], &ptr, 16); wDefColor = (WORD)_tcstoul(&ptr[3], &ptr, 16);
SetScreenColor(wDefColor, FALSE);
} }
#endif #endif
else if (option == _T('U')) else if (option == _T('U'))
@ -1742,11 +1924,41 @@ Initialize()
} }
else if (option == _T('V')) else if (option == _T('V'))
{ {
// FIXME: Check validity of the parameter given to V !
bDelayedExpansion = _tcsnicmp(&ptr[2], _T(":OFF"), 4); bDelayedExpansion = _tcsnicmp(&ptr[2], _T(":OFF"), 4);
} }
else if (option == _T('E'))
{
// FIXME: Check validity of the parameter given to E !
bEnableExtensions = _tcsnicmp(&ptr[2], _T(":OFF"), 4);
}
else if (option == _T('X'))
{
/* '/X' is identical to '/E:ON' */
bEnableExtensions = TRUE;
}
else if (option == _T('Y'))
{
/* '/Y' is identical to '/E:OFF' */
bEnableExtensions = FALSE;
}
} }
} }
#ifdef INCLUDE_CMD_COLOR
if (wDefColor == 0)
{
/*
* If we still do not have the console colour attribute set,
* retrieve the default one.
*/
ConGetDefaultAttributes(&wDefColor);
}
if (wDefColor != 0)
SetScreenColor(wDefColor, FALSE);
#endif
if (!*ptr) if (!*ptr)
{ {
/* If neither /C or /K was given, display a simple version string */ /* If neither /C or /K was given, display a simple version string */
@ -1779,7 +1991,7 @@ Initialize()
} }
static VOID Cleanup() static VOID Cleanup(VOID)
{ {
/* run cmdexit.bat */ /* run cmdexit.bat */
if (IsExistingFile (_T("cmdexit.bat"))) if (IsExistingFile (_T("cmdexit.bat")))
@ -1823,52 +2035,33 @@ static VOID Cleanup()
*/ */
int _tmain(int argc, const TCHAR *argv[]) int _tmain(int argc, const TCHAR *argv[])
{ {
HANDLE hConsole;
TCHAR startPath[MAX_PATH]; TCHAR startPath[MAX_PATH];
CONSOLE_SCREEN_BUFFER_INFO Info;
InitializeCriticalSection(&ChildProcessRunningLock); InitializeCriticalSection(&ChildProcessRunningLock);
lpOriginalEnvironment = DuplicateEnvironment(); lpOriginalEnvironment = DuplicateEnvironment();
GetCurrentDirectory(MAX_PATH,startPath); GetCurrentDirectory(ARRAYSIZE(startPath), startPath);
_tchdir(startPath); _tchdir(startPath);
SetFileApisToOEM(); SetFileApisToOEM();
InputCodePage = 0;
OutputCodePage = 0;
hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hConsole != INVALID_HANDLE_VALUE)
{
if (!GetConsoleScreenBufferInfo(hConsole, &Info))
{
ConErrFormatMessage(GetLastError());
CloseHandle(hConsole);
return(1);
}
wDefColor = Info.wAttributes;
CloseHandle(hConsole);
}
InputCodePage = GetConsoleCP(); InputCodePage = GetConsoleCP();
OutputCodePage = GetConsoleOutputCP(); OutputCodePage = GetConsoleOutputCP();
CMD_ModuleHandle = GetModuleHandle(NULL); CMD_ModuleHandle = GetModuleHandle(NULL);
/* check switches on command-line */ /* Perform general initialization, parse switches on command-line */
Initialize(); Initialize();
/* call prompt routine */ /* Call prompt routine */
ProcessInput(); ProcessInput();
/* do the cleanup */ /* Do the cleanup */
Cleanup(); Cleanup();
cmd_free(lpOriginalEnvironment); cmd_free(lpOriginalEnvironment);
cmd_exit(nErrorLevel); cmd_exit(nErrorLevel);
return(nErrorLevel); return nErrorLevel;
} }
/* EOF */ /* EOF */

View file

@ -51,7 +51,7 @@
/* 16k = max buffer size */ /* 16k = max buffer size */
#define BUFF_SIZE 16384 #define BUFF_SIZE 16384
/* global variables */ /* Global variables */
extern HANDLE hOut; extern HANDLE hOut;
extern HANDLE hIn; extern HANDLE hIn;
extern LPTSTR lpOriginalEnvironment; extern LPTSTR lpOriginalEnvironment;
@ -61,6 +61,7 @@ extern BOOL bCtrlBreak;
extern BOOL bIgnoreEcho; extern BOOL bIgnoreEcho;
extern BOOL bExit; extern BOOL bExit;
extern BOOL bDisableBatchEcho; extern BOOL bDisableBatchEcho;
extern BOOL bEnableExtensions;
extern BOOL bDelayedExpansion; extern BOOL bDelayedExpansion;
extern INT nErrorLevel; extern INT nErrorLevel;
extern SHORT maxx; extern SHORT maxx;
@ -116,6 +117,12 @@ extern HANDLE CMD_ModuleHandle;
/* Prototypes for CMDINPUT.C */ /* Prototypes for CMDINPUT.C */
BOOL ReadCommand (LPTSTR, INT); BOOL ReadCommand (LPTSTR, INT);
extern TCHAR AutoCompletionChar;
extern TCHAR PathCompletionChar;
#define IS_COMPLETION_DISABLED(CompletionCtrl) \
((CompletionCtrl) == 0x00 || (CompletionCtrl) == 0x0D || (CompletionCtrl) >= 0x20)
/* Prototypes for CMDTABLE.C */ /* Prototypes for CMDTABLE.C */
#define CMD_SPECIAL 1 #define CMD_SPECIAL 1

View file

@ -102,6 +102,16 @@
#include "precomp.h" #include "precomp.h"
/*
* See https://technet.microsoft.com/en-us/library/cc978715.aspx
* and https://technet.microsoft.com/en-us/library/cc940805.aspx
* to know the differences between those two settings.
* Values 0x00, 0x0D (carriage return) and 0x20 (space) disable completion.
*/
TCHAR AutoCompletionChar = _T('\t'); // Default is 0x20
TCHAR PathCompletionChar = _T('\t'); // Default is 0x20
SHORT maxx; SHORT maxx;
SHORT maxy; SHORT maxy;

View file

@ -12,6 +12,7 @@
typedef struct _SETLOCAL typedef struct _SETLOCAL
{ {
struct _SETLOCAL *Prev; struct _SETLOCAL *Prev;
BOOL EnableExtensions;
BOOL DelayedExpansion; BOOL DelayedExpansion;
LPTSTR Environment; LPTSTR Environment;
} SETLOCAL; } SETLOCAL;
@ -52,6 +53,7 @@ INT cmd_setlocal(LPTSTR param)
return 1; return 1;
} }
Saved->Prev = bc->setlocal; Saved->Prev = bc->setlocal;
Saved->EnableExtensions = bEnableExtensions;
Saved->DelayedExpansion = bDelayedExpansion; Saved->DelayedExpansion = bDelayedExpansion;
Saved->Environment = DuplicateEnvironment(); Saved->Environment = DuplicateEnvironment();
if (!Saved->Environment) if (!Saved->Environment)
@ -68,9 +70,11 @@ INT cmd_setlocal(LPTSTR param)
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ {
if (!_tcsicmp(arg[i], _T("enableextensions"))) if (!_tcsicmp(arg[i], _T("enableextensions")))
/* not implemented, ignore */; /* FIXME: not implemented! */
bEnableExtensions = TRUE;
else if (!_tcsicmp(arg[i], _T("disableextensions"))) else if (!_tcsicmp(arg[i], _T("disableextensions")))
/* not implemented, ignore */; /* FIXME: not implemented! */
bEnableExtensions = FALSE;
else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion"))) else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion")))
bDelayedExpansion = TRUE; bDelayedExpansion = TRUE;
else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion"))) else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion")))
@ -97,6 +101,7 @@ INT cmd_endlocal(LPTSTR param)
return 0; return 0;
bc->setlocal = Saved->Prev; bc->setlocal = Saved->Prev;
bEnableExtensions = Saved->EnableExtensions;
bDelayedExpansion = Saved->DelayedExpansion; bDelayedExpansion = Saved->DelayedExpansion;
/* First, clear out the environment. Since making any changes to the /* First, clear out the environment. Since making any changes to the