[CMD] Improve the situations when the console title can be changed.
[reactos.git] / base / shell / cmd / cmd.c
index 40cddc3..27b5bf5 100644 (file)
@@ -81,7 +81,7 @@
  *        added showcmds function to show commands and options available
  *
  *    07-Aug-1998 (John P Price <linux-guru@gcfl.net>)
- *        Fixed carrage return output to better match MSDOS with echo
+ *        Fixed carriage return output to better match MSDOS with echo
  *        on or off. (marked with "JPP 19980708")
  *
  *    07-Dec-1998 (Eric Kohl)
  *
  *    06-jul-2005 (Magnus Olsen <magnus@greatlord.com>)
  *        translate '%errorlevel%' to the internal value.
- *        Add proper memmory alloc ProcessInput, the error
- *        handling for memmory handling need to be improve
+ *        Add proper memory alloc ProcessInput, the error
+ *        handling for memory handling need to be improve
  */
 
 #include "precomp.h"
 #include <reactos/buildno.h>
 #include <reactos/version.h>
 
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(StatCode)  ((NTSTATUS)(StatCode) >= 0)
-#endif
-
 typedef NTSTATUS (WINAPI *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS,
                                                           PVOID, ULONG, PULONG);
 typedef NTSTATUS (WINAPI *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG);
 
-BOOL bExit = FALSE;       /* indicates EXIT was typed */
-BOOL bCanExit = TRUE;     /* indicates if this shell is exitable */
+BOOL bExit = FALSE;       /* Indicates EXIT was typed */
+BOOL bCanExit = TRUE;     /* Indicates if this shell is exitable */
 BOOL bCtrlBreak = FALSE;  /* Ctrl-Break or Ctrl-C hit */
 BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */
+static BOOL fSingleCommand = 0; /* When we are executing something passed on the command line after /C or /K */
 INT  nErrorLevel = 0;     /* Errorlevel of last launched external program */
 CRITICAL_SECTION ChildProcessRunningLock;
-BOOL bUnicodeOutput = FALSE;
 BOOL bDisableBatchEcho = FALSE;
+BOOL bEnableExtensions = TRUE;
 BOOL bDelayedExpansion = FALSE;
 DWORD dwChildProcessId = 0;
-OSVERSIONINFO osvi;
-HANDLE hIn;
-HANDLE hOut;
 LPTSTR lpOriginalEnvironment;
 HANDLE CMD_ModuleHandle;
 
+BOOL bTitleSet = FALSE; /* Indicates whether the console title has been changed and needs to be restored later */
+TCHAR szCurTitle[MAX_PATH];
+
 static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL;
 static NtReadVirtualMemoryProc       NtReadVirtualMemoryPtr = NULL;
 
+/*
+ * Default output file stream translation mode is UTF8, but CMD switches
+ * allow to change it to either UTF16 (/U) or ANSI (/A).
+ */
+CON_STREAM_MODE OutputStreamMode = UTF8Text; // AnsiText;
+
 #ifdef INCLUDE_CMD_COLOR
-WORD wDefColor;           /* default color */
+WORD wDefColor = 0;     /* Default color */
 #endif
 
 /*
@@ -182,7 +185,7 @@ WORD wDefColor;           /* default color */
  * insert commas into a number
  */
 INT
-ConvertULargeInteger(ULONGLONG num, LPTSTR des, UINT len, BOOL bPutSeperator)
+ConvertULargeInteger(ULONGLONG num, LPTSTR des, UINT len, BOOL bPutSeparator)
 {
     TCHAR temp[39];   /* maximum length with nNumberGroups == 1 */
     UINT  n, iTarget;
@@ -193,11 +196,11 @@ ConvertULargeInteger(ULONGLONG num, LPTSTR des, UINT len, BOOL bPutSeperator)
     n = 0;
     iTarget = nNumberGroups;
     if (!nNumberGroups)
-        bPutSeperator = FALSE;
+        bPutSeparator = FALSE;
 
     do
     {
-        if (iTarget == n && bPutSeperator)
+        if (iTarget == n && bPutSeparator)
         {
             iTarget += nNumberGroups + 1;
             temp[38 - n++] = cThousandSeparator;
@@ -301,28 +304,57 @@ HANDLE RunFile(DWORD flags, LPTSTR filename, LPTSTR params,
 }
 
 
+static VOID
+SetConTitle(LPCTSTR pszTitle)
+{
+    TCHAR szNewTitle[MAX_PATH];
+
+    if (!pszTitle)
+        return;
+
+    /* Don't do anything if we run inside a batch file, or we are just running a single command */
+    if (bc || (fSingleCommand == 1))
+        return;
+
+    /* Save the original console title and build a new one */
+    GetConsoleTitle(szCurTitle, ARRAYSIZE(szCurTitle));
+    StringCchPrintf(szNewTitle, ARRAYSIZE(szNewTitle),
+                    _T("%s - %s"), szCurTitle, pszTitle);
+    bTitleSet = TRUE;
+    ConSetTitle(szNewTitle);
+}
+
+static VOID
+ResetConTitle(VOID)
+{
+    /* Restore the original console title */
+    if (!bc && bTitleSet)
+    {
+        ConSetTitle(szCurTitle);
+        bTitleSet = FALSE;
+    }
+}
 
 /*
- * This command (in first) was not found in the command table
+ * This command (in First) was not found in the command table
  *
- * Full  - buffer to hold whole command line
+ * Full  - output buffer to hold whole command line
  * First - first word on command line
  * Rest  - rest of command line
  */
 static INT
 Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
 {
-    TCHAR szFullName[MAX_PATH];
     TCHAR *first, *rest, *dot;
-    TCHAR szWindowTitle[MAX_PATH];
     DWORD dwExitCode = 0;
     TCHAR *FirstEnd;
-    TCHAR szFullCmdLine [CMDLINE_LENGTH];
+    TCHAR szFullName[MAX_PATH];
+    TCHAR szFullCmdLine[CMDLINE_LENGTH];
 
     TRACE ("Execute: \'%s\' \'%s\'\n", debugstr_aw(First), debugstr_aw(Rest));
 
     /* Though it was already parsed once, we have a different set of rules
-       for parsing before we pass to CreateProccess */
+       for parsing before we pass to CreateProcess */
     if (First[0] == _T('/') || (First[0] && First[1] == _T(':')))
     {
         /* Use the entire first word as the program name (no change) */
@@ -342,10 +374,10 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
     }
 
     /* Copy the new first/rest into the buffer */
-    first = Full;
     rest = &Full[FirstEnd - First + 1];
     _tcscpy(rest, FirstEnd);
     _tcscat(rest, Rest);
+    first = Full;
     *FirstEnd = _T('\0');
     _tcscpy(first, First);
 
@@ -354,8 +386,8 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
     {
         BOOL working = TRUE;
         if (!SetCurrentDirectory(first))
-        /* Guess they changed disc or something, handle that gracefully and get to root */
         {
+            /* Guess they changed disc or something, handle that gracefully and get to root */
             TCHAR str[4];
             str[0]=first[0];
             str[1]=_T(':');
@@ -377,7 +409,10 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
         return 1;
     }
 
-    GetConsoleTitle (szWindowTitle, MAX_PATH);
+    /* Set the new console title */
+    FirstEnd = first + (FirstEnd - First); /* Point to the separating NULL in the full built string */
+    *FirstEnd = _T(' ');
+    SetConTitle(Full);
 
     /* check if this is a .BAT or .CMD file */
     dot = _tcsrchr (szFullName, _T('.'));
@@ -385,6 +420,8 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
     {
         while (*rest == _T(' '))
             rest++;
+
+        *FirstEnd = _T('\0');
         TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest));
         dwExitCode = Batch(szFullName, first, rest, Cmd);
     }
@@ -395,7 +432,7 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
         STARTUPINFO stui;
 
         /* build command line for CreateProcess(): FullName + " " + rest */
-        BOOL quoted = !!_tcschr(First, ' ');
+        BOOL quoted = !!_tcschr(First, _T(' '));
         _tcscpy(szFullCmdLine, quoted ? _T("\"") : _T(""));
         _tcsncat(szFullCmdLine, First, CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1);
         _tcsncat(szFullCmdLine, quoted ? _T("\"") : _T(""), CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1);
@@ -409,13 +446,14 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
         TRACE ("[EXEC: %s]\n", debugstr_aw(szFullCmdLine));
 
         /* fill startup info */
-        memset (&stui, 0, sizeof (STARTUPINFO));
-        stui.cb = sizeof (STARTUPINFO);
+        memset(&stui, 0, sizeof(stui));
+        stui.cb = sizeof(stui);
+        stui.lpTitle = Full;
         stui.dwFlags = STARTF_USESHOWWINDOW;
         stui.wShowWindow = SW_SHOWDEFAULT;
 
         /* Set the console to standard mode */
-        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
+        SetConsoleMode(ConStreamGetOSHandle(StdIn),
                        ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
 
         if (CreateProcess(szFullName,
@@ -423,7 +461,7 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
                           NULL,
                           NULL,
                           TRUE,
-                          0,   /* CREATE_NEW_PROCESS_GROUP */
+                          0,
                           NULL,
                           NULL,
                           &stui,
@@ -441,10 +479,13 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
                                     SW_SHOWNORMAL);
         }
 
+        *FirstEnd = _T('\0');
+
         if (prci.hProcess != NULL)
         {
-            if (IsConsoleProcess(prci.hProcess))
+            if (bc != NULL || fSingleCommand != 0 || IsConsoleProcess(prci.hProcess))
             {
+                /* when processing a batch file or starting console processes: execute synchronously */
                 EnterCriticalSection(&ChildProcessRunningLock);
                 dwChildProcessId = prci.dwProcessId;
 
@@ -465,16 +506,35 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
         }
 
         /* Restore our default console mode */
-        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
+        SetConsoleMode(ConStreamGetOSHandle(StdIn),
                        ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
-        SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE),
+        SetConsoleMode(ConStreamGetOSHandle(StdOut),
                        ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
     }
 
-    /* Get code page if it has been changed */
-    InputCodePage= GetConsoleCP();
-    OutputCodePage = GetConsoleOutputCP();
-    SetConsoleTitle(szWindowTitle);
+    /* Update our local codepage cache */
+    {
+        UINT uNewInputCodePage  = GetConsoleCP();
+        UINT uNewOutputCodePage = GetConsoleOutputCP();
+
+        if ((InputCodePage  != uNewInputCodePage) ||
+            (OutputCodePage != uNewOutputCodePage))
+        {
+            /* Update the locale as well */
+            InitLocale();
+        }
+
+        InputCodePage  = uNewInputCodePage;
+        OutputCodePage = uNewOutputCodePage;
+
+        /* Update the streams codepage cache as well */
+        ConStreamSetCacheCodePage(StdIn , InputCodePage );
+        ConStreamSetCacheCodePage(StdOut, OutputCodePage);
+        ConStreamSetCacheCodePage(StdErr, OutputCodePage);
+    }
+
+    /* Restore the original console title */
+    ResetConTitle();
 
     return dwExitCode;
 }
@@ -540,9 +600,19 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
 
             /* Skip over whitespace to rest of line, exclude 'echo' command */
             if (_tcsicmp(cmdptr->name, _T("echo")) != 0)
+            {
                 while (_istspace(*param))
                     param++;
+            }
+
+            /* Set the new console title */
+            SetConTitle(com);
+
             ret = cmdptr->func(param);
+
+            /* Restore the original console title */
+            ResetConTitle();
+
             cmd_free(com);
             return ret;
         }
@@ -558,7 +628,7 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
  * process the command line and execute the appropriate functions
  * full input/output redirection and piping are supported
  */
-INT ParseCommandLine (LPTSTR cmd)
+INT ParseCommandLine(LPTSTR cmd)
 {
     INT Ret = 0;
     PARSED_COMMAND *Cmd = ParseCommand(cmd);
@@ -584,7 +654,7 @@ ExecuteAsync(PARSED_COMMAND *Cmd)
     PROCESS_INFORMATION prci;
 
     /* Get the path to cmd.exe */
-    GetModuleFileName(NULL, CmdPath, MAX_PATH);
+    GetModuleFileName(NULL, CmdPath, ARRAYSIZE(CmdPath));
 
     /* Build the parameter string to pass to cmd.exe */
     ParamsEnd = _stpcpy(CmdParams, _T("/S/D/C\""));
@@ -609,7 +679,7 @@ ExecuteAsync(PARSED_COMMAND *Cmd)
     return prci.hProcess;
 }
 
-static VOID
+static INT
 ExecutePipeline(PARSED_COMMAND *Cmd)
 {
 #ifdef FEATURE_REDIRECTION
@@ -681,7 +751,7 @@ ExecutePipeline(PARSED_COMMAND *Cmd)
 
     while (--nProcesses >= 0)
         CloseHandle(hProcess[nProcesses]);
-    return;
+    return nErrorLevel;
 
 failed:
     if (hInput)
@@ -694,6 +764,8 @@ failed:
     SetStdHandle(STD_INPUT_HANDLE, hOldConIn);
     SetStdHandle(STD_OUTPUT_HANDLE, hOldConOut);
 #endif
+
+    return nErrorLevel;
 }
 
 INT
@@ -744,7 +816,7 @@ ExecuteCommand(PARSED_COMMAND *Cmd)
             Ret = ExecuteCommand(Sub->Next);
         break;
     case C_PIPE:
-        ExecutePipeline(Cmd);
+        Ret = ExecutePipeline(Cmd);
         break;
     case C_IF:
         Ret = ExecuteIf(Cmd);
@@ -1389,11 +1461,15 @@ ReadLine(TCHAR *commandline, BOOL bMore)
             return FALSE;
         }
 
-        if (CheckCtrlBreak(BREAK_INPUT))
-        {
+        if (readline[0] == _T('\0'))
             ConOutChar(_T('\n'));
+
+        if (CheckCtrlBreak(BREAK_INPUT))
             return FALSE;
-        }
+
+        if (readline[0] == _T('\0'))
+            return FALSE;
+
         ip = readline;
     }
     else
@@ -1407,12 +1483,15 @@ ReadLine(TCHAR *commandline, BOOL bMore)
 }
 
 static VOID
-ProcessInput()
+ProcessInput(VOID)
 {
     PARSED_COMMAND *Cmd;
 
     while (!bCanExit || !bExit)
     {
+        /* Reset the Ctrl-Break / Ctrl-C state */
+        bCtrlBreak = FALSE;
+
         Cmd = ParseCommand(NULL);
         if (!Cmd)
             continue;
@@ -1430,26 +1509,16 @@ BOOL WINAPI BreakHandler(DWORD dwCtrlType)
 {
     DWORD           dwWritten;
     INPUT_RECORD    rec;
-    static BOOL SelfGenerated = FALSE;
 
     if ((dwCtrlType != CTRL_C_EVENT) &&
         (dwCtrlType != CTRL_BREAK_EVENT))
     {
         return FALSE;
     }
-    else
-    {
-        if (SelfGenerated)
-        {
-            SelfGenerated = FALSE;
-            return TRUE;
-        }
-    }
 
     if (!TryEnterCriticalSection(&ChildProcessRunningLock))
     {
-        SelfGenerated = TRUE;
-        GenerateConsoleCtrlEvent (dwCtrlType, 0);
+        /* Child process is running and will have received the control event */
         return TRUE;
     }
     else
@@ -1457,6 +1526,8 @@ BOOL WINAPI BreakHandler(DWORD dwCtrlType)
         LeaveCriticalSection(&ChildProcessRunningLock);
     }
 
+    bCtrlBreak = TRUE;
+
     rec.EventType = KEY_EVENT;
     rec.Event.KeyEvent.bKeyDown = TRUE;
     rec.Event.KeyEvent.wRepeatCount = 1;
@@ -1466,29 +1537,28 @@ BOOL WINAPI BreakHandler(DWORD dwCtrlType)
     rec.Event.KeyEvent.uChar.UnicodeChar = _T('C');
     rec.Event.KeyEvent.dwControlKeyState = RIGHT_CTRL_PRESSED;
 
-    WriteConsoleInput(hIn,
+    WriteConsoleInput(ConStreamGetOSHandle(StdIn),
                       &rec,
                       1,
                       &dwWritten);
 
-    bCtrlBreak = TRUE;
     /* FIXME: Handle batch files */
 
-    //ConOutPrintf(_T("^C"));
+    // ConOutPrintf(_T("^C"));
 
     return TRUE;
 }
 
 
-VOID AddBreakHandler (VOID)
+VOID AddBreakHandler(VOID)
 {
-    SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, TRUE);
+    SetConsoleCtrlHandler(BreakHandler, TRUE);
 }
 
 
-VOID RemoveBreakHandler (VOID)
+VOID RemoveBreakHandler(VOID)
 {
-    SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, FALSE);
+    SetConsoleCtrlHandler(BreakHandler, FALSE);
 }
 
 
@@ -1498,7 +1568,7 @@ VOID RemoveBreakHandler (VOID)
  */
 #if 0
 static VOID
-ShowCommands (VOID)
+ShowCommands(VOID)
 {
     /* print command list */
     ConOutResPuts(STRING_CMD_HELP1);
@@ -1526,31 +1596,186 @@ ShowCommands (VOID)
 }
 #endif
 
+
 static VOID
-ExecuteAutoRunFile(HKEY hkeyRoot)
+LoadRegistrySettings(HKEY hKeyRoot)
 {
-    TCHAR autorun[2048];
-    DWORD len = sizeof autorun;
-    HKEY hkey;
+    LONG lRet;
+    HKEY hKey;
+    DWORD dwType, len;
+    /*
+     * Buffer big enough to hold the string L"4294967295",
+     * corresponding to the literal 0xFFFFFFFF (MAX_ULONG) in decimal.
+     */
+    DWORD Buffer[6];
+
+    lRet = RegOpenKeyEx(hKeyRoot,
+                        _T("Software\\Microsoft\\Command Processor"),
+                        0,
+                        KEY_QUERY_VALUE,
+                        &hKey);
+    if (lRet != ERROR_SUCCESS)
+        return;
 
-    if (RegOpenKeyEx(hkeyRoot,
-                     _T("SOFTWARE\\Microsoft\\Command Processor"),
-                     0,
-                     KEY_READ,
-                     &hkey) == ERROR_SUCCESS)
+#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)
     {
-        if (RegQueryValueEx(hkey,
+        /* 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)
+{
+    LONG lRet;
+    HKEY hKey;
+    DWORD dwType, len;
+    TCHAR AutoRun[2048];
+
+    lRet = RegOpenKeyEx(hKeyRoot,
+                        _T("Software\\Microsoft\\Command Processor"),
+                        0,
+                        KEY_QUERY_VALUE,
+                        &hKey);
+    if (lRet != ERROR_SUCCESS)
+        return;
+
+    len = sizeof(AutoRun);
+    lRet = RegQueryValueEx(hKey,
                            _T("AutoRun"),
-                           0,
-                           0,
-                           (LPBYTE)autorun,
-                           &len) == ERROR_SUCCESS)
-        {
-            if (*autorun)
-                ParseCommandLine(autorun);
-        }
-        RegCloseKey(hkey);
+                           NULL,
+                           &dwType,
+                           (LPBYTE)&AutoRun,
+                           &len);
+    if ((lRet == ERROR_SUCCESS) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ))
+    {
+        if (*AutoRun)
+            ParseCommandLine(AutoRun);
     }
+
+    RegCloseKey(hKey);
 }
 
 /* Get the command that comes after a /C or /K switch */
@@ -1606,25 +1831,26 @@ GetCmdLineCommand(TCHAR *commandline, TCHAR *ptr, BOOL AlwaysStrip)
     _tcscpy(commandline, ptr);
 }
 
+
 /*
- * 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 nExitCode;
+
+    HANDLE hIn, hOut;
 
-    //INT len;
     TCHAR *ptr, *cmdLine, option = 0;
     BOOL AlwaysStrip = FALSE;
     BOOL AutoRun = TRUE;
 
-    /* get version information */
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-    GetVersionEx (&osvi);
+    /* Get version information */
+    InitOSVersion();
 
     /* Some people like to run ReactOS cmd.exe on Win98, it helps in the
      * build process. So don't link implicitly against ntdll.dll, load it
@@ -1636,27 +1862,28 @@ Initialize()
         NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
     }
 
-    InitLocale();
+    /* Load the registry settings */
+    LoadRegistrySettings(HKEY_LOCAL_MACHINE);
+    LoadRegistrySettings(HKEY_CURRENT_USER);
 
-    /* get default input and output console handles */
-    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
-    hIn  = GetStdHandle(STD_INPUT_HANDLE);
+    /* Initialize our locale */
+    InitLocale();
 
     /* Initialize prompt support */
     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);
@@ -1666,6 +1893,8 @@ Initialize()
     AddBreakHandler();
 
     /* Set our default console mode */
+    hOut = ConStreamGetOSHandle(StdOut);
+    hIn  = ConStreamGetOSHandle(StdIn);
     SetConsoleMode(hOut, 0); // Reinitialize the console output mode
     SetConsoleMode(hOut, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
     SetConsoleMode(hIn , ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
@@ -1704,11 +1933,12 @@ Initialize()
             }
             else if (option == _T('A'))
             {
-                bUnicodeOutput = FALSE;
+                OutputStreamMode = AnsiText;
             }
             else if (option == _T('C') || option == _T('K') || option == _T('R'))
             {
                 /* Remainder of command line is a command to be run */
+                fSingleCommand = ((option == _T('K')) << 1) | 1;
                 break;
             }
             else if (option == _T('D'))
@@ -1726,29 +1956,63 @@ 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'))
             {
-                bUnicodeOutput = TRUE;
+                OutputStreamMode = UTF16Text;
             }
             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)
+        ConSetScreenColor(ConStreamGetOSHandle(StdOut), wDefColor, TRUE);
+#endif
+
+    /* Reset the output Standard Streams translation modes and codepage caches */
+    // ConStreamSetMode(StdIn , OutputStreamMode, InputCodePage );
+    ConStreamSetMode(StdOut, OutputStreamMode, OutputCodePage);
+    ConStreamSetMode(StdErr, OutputStreamMode, OutputCodePage);
+
     if (!*ptr)
     {
         /* If neither /C or /K was given, display a simple version string */
         ConOutChar(_T('\n'));
         ConOutResPrintf(STRING_REACTOS_VERSION,
-            _T(KERNEL_RELEASE_STR),
-            _T(KERNEL_VERSION_BUILD_STR));
+                        _T(KERNEL_VERSION_STR),
+                        _T(KERNEL_VERSION_BUILD_STR));
         ConOutPuts(_T("(C) Copyright 1998-") _T(COPYRIGHT_YEAR) _T(" ReactOS Team.\n"));
     }
 
@@ -1762,50 +2026,50 @@ Initialize()
     {
         /* Do the /C or /K command */
         GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
-        nExitCode = ParseCommandLine(commandline);
-        if (option != _T('K'))
+        /* nExitCode = */ ParseCommandLine(commandline);
+        if (fSingleCommand == 1)
         {
-            nErrorLevel = nExitCode;
+            // nErrorLevel = nExitCode;
             bExit = TRUE;
         }
+        fSingleCommand = 0;
     }
 }
 
 
-static VOID Cleanup()
+static VOID Cleanup(VOID)
 {
-    /* run cmdexit.bat */
-    if (IsExistingFile (_T("cmdexit.bat")))
+    /* Run cmdexit.bat */
+    if (IsExistingFile(_T("cmdexit.bat")))
     {
         ConErrResPuts(STRING_CMD_ERROR5);
-
-        ParseCommandLine (_T("cmdexit.bat"));
+        ParseCommandLine(_T("cmdexit.bat"));
     }
-    else if (IsExistingFile (_T("\\cmdexit.bat")))
+    else if (IsExistingFile(_T("\\cmdexit.bat")))
     {
-        ConErrResPuts (STRING_CMD_ERROR5);
-        ParseCommandLine (_T("\\cmdexit.bat"));
+        ConErrResPuts(STRING_CMD_ERROR5);
+        ParseCommandLine(_T("\\cmdexit.bat"));
     }
 
-#ifdef FEATURE_DIECTORY_STACK
-    /* destroy directory stack */
-    DestroyDirectoryStack ();
+#ifdef FEATURE_DIRECTORY_STACK
+    /* Destroy directory stack */
+    DestroyDirectoryStack();
 #endif
 
 #ifdef FEATURE_HISTORY
     CleanHistory();
 #endif
 
-    /* free GetEnvVar's buffer */
+    /* Free GetEnvVar's buffer */
     GetEnvVar(NULL);
 
     /* Remove ctrl break handler */
     RemoveBreakHandler();
 
     /* Restore the default console mode */
-    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
+    SetConsoleMode(ConStreamGetOSHandle(StdIn),
                    ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
-    SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE),
+    SetConsoleMode(ConStreamGetOSHandle(StdOut),
                    ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
 
     DeleteCriticalSection(&ChildProcessRunningLock);
@@ -1816,51 +2080,38 @@ 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;
+    InputCodePage  = GetConsoleCP();
+    OutputCodePage = GetConsoleOutputCP();
 
-    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());
-            return(1);
-        }
-        wDefColor = Info.wAttributes;
-        CloseHandle(hConsole);
-    }
+    /* Initialize the Console Standard Streams */
+    ConStreamInit(StdIn , GetStdHandle(STD_INPUT_HANDLE) , /*OutputStreamMode*/ AnsiText, InputCodePage);
+    ConStreamInit(StdOut, GetStdHandle(STD_OUTPUT_HANDLE), OutputStreamMode, OutputCodePage);
+    ConStreamInit(StdErr, GetStdHandle(STD_ERROR_HANDLE) , OutputStreamMode, OutputCodePage);
 
-    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 */