[CMD] Improve the situations when the console title can be changed.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 3 Jun 2018 00:15:44 +0000 (02:15 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 3 Jun 2018 00:36:39 +0000 (02:36 +0200)
- Introduce two small helpers to change and restore the console title.
- Console title can change even when internal commands are executed.
- Note that when commands are run from within batch files, title is unchanged.
- When "cmd.exe /c command" is run, the console title is unchanged; however
  when "cmd.exe /k command" is run, the console title changes.

base/shell/cmd/cmd.c
base/shell/cmd/title.c

index 974fd3e..27b5bf5 100644 (file)
@@ -149,21 +149,23 @@ typedef NTSTATUS (WINAPI *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLAS
                                                           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 bWaitForCommand = FALSE; /* When we are executing something passed on the commandline after /c or /k */
+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 bDisableBatchEcho = FALSE;
 BOOL bEnableExtensions = TRUE;
 BOOL bDelayedExpansion = FALSE;
-BOOL bTitleSet = FALSE;
 DWORD dwChildProcessId = 0;
 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;
 
@@ -302,23 +304,51 @@ 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];
-    TCHAR szNewTitle[MAX_PATH*2];
     DWORD dwExitCode = 0;
     TCHAR *FirstEnd;
+    TCHAR szFullName[MAX_PATH];
     TCHAR szFullCmdLine[CMDLINE_LENGTH];
 
     TRACE ("Execute: \'%s\' \'%s\'\n", debugstr_aw(First), debugstr_aw(Rest));
@@ -344,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);
 
@@ -356,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(':');
@@ -379,12 +409,10 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
         return 1;
     }
 
-    /* Save the original console title and build a new one */
-    GetConsoleTitle(szWindowTitle, ARRAYSIZE(szWindowTitle));
-    bTitleSet = FALSE;
-    StringCchPrintf(szNewTitle, ARRAYSIZE(szNewTitle),
-                    _T("%s - %s%s"), szWindowTitle, First, Rest);
-    ConSetTitle(szNewTitle);
+    /* 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('.'));
@@ -392,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);
     }
@@ -402,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);
@@ -416,8 +446,9 @@ 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;
 
@@ -448,9 +479,11 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
                                     SW_SHOWNORMAL);
         }
 
+        *FirstEnd = _T('\0');
+
         if (prci.hProcess != NULL)
         {
-            if (bc != NULL || bWaitForCommand || IsConsoleProcess(prci.hProcess))
+            if (bc != NULL || fSingleCommand != 0 || IsConsoleProcess(prci.hProcess))
             {
                 /* when processing a batch file or starting console processes: execute synchronously */
                 EnterCriticalSection(&ChildProcessRunningLock);
@@ -501,8 +534,7 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
     }
 
     /* Restore the original console title */
-    if (!bTitleSet)
-        ConSetTitle(szWindowTitle);
+    ResetConTitle();
 
     return dwExitCode;
 }
@@ -568,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;
         }
@@ -1896,6 +1938,7 @@ Initialize(VOID)
             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'))
@@ -1983,14 +2026,13 @@ Initialize(VOID)
     {
         /* Do the /C or /K command */
         GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
-        bWaitForCommand = TRUE;
         /* nExitCode = */ ParseCommandLine(commandline);
-        bWaitForCommand = FALSE;
-        if (option != _T('K'))
+        if (fSingleCommand == 1)
         {
             // nErrorLevel = nExitCode;
             bExit = TRUE;
         }
+        fSingleCommand = 0;
     }
 }
 
index 66738f8..2370aa7 100644 (file)
@@ -28,7 +28,8 @@ INT cmd_title(LPTSTR param)
         return 0;
     }
 
-    bTitleSet = TRUE;
+    /* Set the new console title, and tell CMD to not reset it */
+    bTitleSet = FALSE;
     return ConSetTitle(param);
 }