[CMD]: Diverse improvements:
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Sep 2017 11:39:08 +0000 (11:39 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 30 Sep 2017 11:39:08 +0000 (11:39 +0000)
- 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

reactos/base/shell/cmd/cmd.c
reactos/base/shell/cmd/cmd.h
reactos/base/shell/cmd/cmdinput.c
reactos/base/shell/cmd/setlocal.c

index acabece..e0a4072 100644 (file)
@@ -162,6 +162,7 @@ INT  nErrorLevel = 0;     /* Errorlevel of last launched external program */
 CRITICAL_SECTION ChildProcessRunningLock;
 BOOL bUnicodeOutput = FALSE;
 BOOL bDisableBatchEcho = FALSE;
+BOOL bEnableExtensions = TRUE;
 BOOL bDelayedExpansion = FALSE;
 BOOL bTitleSet = FALSE;
 DWORD dwChildProcessId = 0;
@@ -174,7 +175,7 @@ static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL;
 static NtReadVirtualMemoryProc       NtReadVirtualMemoryPtr = NULL;
 
 #ifdef INCLUDE_CMD_COLOR
-WORD wDefColor;           /* default color */
+WORD wDefColor = 0;     /* Default color */
 #endif
 
 /*
@@ -1532,14 +1533,164 @@ ShowCommands (VOID)
 }
 #endif
 
+
+static VOID
+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)
+ExecuteAutoRunFile(HKEY hKeyRoot)
 {
     TCHAR autorun[2048];
     DWORD len = sizeof autorun;
     HKEY hkey;
 
-    if (RegOpenKeyEx(hkeyRoot,
+    if (RegOpenKeyEx(hKeyRoot,
                      _T("SOFTWARE\\Microsoft\\Command Processor"),
                      0,
                      KEY_READ,
@@ -1612,18 +1763,45 @@ GetCmdLineCommand(TCHAR *commandline, TCHAR *ptr, BOOL AlwaysStrip)
     _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
-Initialize()
+Initialize(VOID)
 {
     HMODULE NtDllModule;
     TCHAR commandline[CMDLINE_LENGTH];
     TCHAR ModuleName[_MAX_PATH + 1];
     INT nExitCode;
 
-    //INT len;
     TCHAR *ptr, *cmdLine, option = 0;
     BOOL AlwaysStrip = FALSE;
     BOOL AutoRun = TRUE;
@@ -1641,9 +1819,14 @@ Initialize()
         NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
     }
 
+    /* Load the registry settings */
+    LoadRegistrySettings(HKEY_LOCAL_MACHINE);
+    LoadRegistrySettings(HKEY_CURRENT_USER);
+
+    /* Initialize our locale */
     InitLocale();
 
-    /* get default input and output console handles */
+    /* Get default input and output console handles */
     hOut = GetStdHandle(STD_OUTPUT_HANDLE);
     hIn  = GetStdHandle(STD_INPUT_HANDLE);
 
@@ -1651,17 +1834,17 @@ Initialize()
     InitPrompt();
 
 #ifdef FEATURE_DIR_STACK
-    /* initialize directory stack */
+    /* Initialize directory stack */
     InitDirectoryStack();
 #endif
 
 #ifdef FEATURE_HISTORY
-    /*initialize history*/
+    /* Initialize history */
     InitHistory();
 #endif
 
     /* Set COMSPEC environment variable */
-    if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1))
+    if (GetModuleFileName(NULL, ModuleName, ARRAYSIZE(ModuleName)) != 0)
     {
         ModuleName[_MAX_PATH] = _T('\0');
         SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
@@ -1731,9 +1914,8 @@ Initialize()
 #ifdef INCLUDE_CMD_COLOR
             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);
-                SetScreenColor(wDefColor, FALSE);
             }
 #endif
             else if (option == _T('U'))
@@ -1742,11 +1924,41 @@ Initialize()
             }
             else if (option == _T('V'))
             {
+                // FIXME: Check validity of the parameter given to V !
                 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 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 */
     if (IsExistingFile (_T("cmdexit.bat")))
@@ -1823,52 +2035,33 @@ static VOID Cleanup()
  */
 int _tmain(int argc, const TCHAR *argv[])
 {
-    HANDLE hConsole;
     TCHAR startPath[MAX_PATH];
-    CONSOLE_SCREEN_BUFFER_INFO Info;
 
     InitializeCriticalSection(&ChildProcessRunningLock);
     lpOriginalEnvironment = DuplicateEnvironment();
 
-    GetCurrentDirectory(MAX_PATH,startPath);
+    GetCurrentDirectory(ARRAYSIZE(startPath), startPath);
     _tchdir(startPath);
 
     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();
     OutputCodePage = GetConsoleOutputCP();
+
     CMD_ModuleHandle = GetModuleHandle(NULL);
 
-    /* check switches on command-line */
+    /* Perform general initialization, parse switches on command-line */
     Initialize();
 
-    /* call prompt routine */
+    /* Call prompt routine */
     ProcessInput();
 
-    /* do the cleanup */
+    /* Do the cleanup */
     Cleanup();
 
     cmd_free(lpOriginalEnvironment);
 
     cmd_exit(nErrorLevel);
-    return(nErrorLevel);
+    return nErrorLevel;
 }
 
 /* EOF */
index 4496604..5d21b72 100644 (file)
@@ -51,7 +51,7 @@
 /* 16k = max buffer size */
 #define BUFF_SIZE 16384
 
-/* global variables */
+/* Global variables */
 extern HANDLE hOut;
 extern HANDLE hIn;
 extern LPTSTR lpOriginalEnvironment;
@@ -61,6 +61,7 @@ extern BOOL   bCtrlBreak;
 extern BOOL   bIgnoreEcho;
 extern BOOL   bExit;
 extern BOOL   bDisableBatchEcho;
+extern BOOL   bEnableExtensions;
 extern BOOL   bDelayedExpansion;
 extern INT    nErrorLevel;
 extern SHORT  maxx;
@@ -116,6 +117,12 @@ extern HANDLE CMD_ModuleHandle;
 /* Prototypes for CMDINPUT.C */
 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 */
 #define CMD_SPECIAL     1
index b9d4469..6c2971e 100644 (file)
 
 #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 maxy;
 
index 5ad2e41..ae60036 100644 (file)
@@ -12,6 +12,7 @@
 typedef struct _SETLOCAL
 {
     struct _SETLOCAL *Prev;
+    BOOL EnableExtensions;
     BOOL DelayedExpansion;
     LPTSTR Environment;
 } SETLOCAL;
@@ -52,6 +53,7 @@ INT cmd_setlocal(LPTSTR param)
         return 1;
     }
     Saved->Prev = bc->setlocal;
+    Saved->EnableExtensions = bEnableExtensions;
     Saved->DelayedExpansion = bDelayedExpansion;
     Saved->Environment = DuplicateEnvironment();
     if (!Saved->Environment)
@@ -68,9 +70,11 @@ INT cmd_setlocal(LPTSTR param)
     for (i = 0; i < argc; i++)
     {
         if (!_tcsicmp(arg[i], _T("enableextensions")))
-            /* not implemented, ignore */;
+            /* FIXME: not implemented! */
+            bEnableExtensions = TRUE;
         else if (!_tcsicmp(arg[i], _T("disableextensions")))
-            /* not implemented, ignore */;
+            /* FIXME: not implemented! */
+            bEnableExtensions = FALSE;
         else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion")))
             bDelayedExpansion = TRUE;
         else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion")))
@@ -97,6 +101,7 @@ INT cmd_endlocal(LPTSTR param)
         return 0;
     bc->setlocal = Saved->Prev;
 
+    bEnableExtensions = Saved->EnableExtensions;
     bDelayedExpansion = Saved->DelayedExpansion;
 
     /* First, clear out the environment. Since making any changes to the