https://git.reactos.org/?p=reactos.git;a=commitdiff;h=26cfadc3529928dad4abb73fe97a2d1dbb935dfd

commit 26cfadc3529928dad4abb73fe97a2d1dbb935dfd
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Wed Jun 10 01:18:41 2020 +0200
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Wed Aug 19 20:35:56 2020 +0200

    [CMD] Make the command echoer Windows-CMD-compatible. CORE-14025
    
    Add a MSCMD_ECHO_COMMAND_COMPAT define to be able to switch back to our
    older but less broken behaviour at compile-time.
    
    - Append a trailing space to commands when those have a parameter,
      as well as after a command-block closing parenthesis.
    
    - Space around redirection strings need to be switched around.
---
 base/shell/cmd/parser.c | 89 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 76 insertions(+), 13 deletions(-)

diff --git a/base/shell/cmd/parser.c b/base/shell/cmd/parser.c
index 0774e92ced1..9f4552aa5ad 100644
--- a/base/shell/cmd/parser.c
+++ b/base/shell/cmd/parser.c
@@ -4,6 +4,9 @@
 
 #include "precomp.h"
 
+/* Enable this define for "buggy" Windows' CMD command echoer compatibility */
+#define MSCMD_ECHO_COMMAND_COMPAT
+
 /*
  * Parser debugging support. These flags are global so that their values can be
  * modified at runtime from a debugger. They correspond to the public Windows'
@@ -1127,48 +1130,85 @@ EchoCommand(PARSED_COMMAND *Cmd)
     switch (Cmd->Type)
     {
     case C_COMMAND:
+    {
         if (SubstituteForVars(Cmd->Command.First, Buf))
             ConOutPrintf(_T("%s"), Buf);
         if (SubstituteForVars(Cmd->Command.Rest, Buf))
+        {
             ConOutPrintf(_T("%s"), Buf);
+#ifdef MSCMD_ECHO_COMMAND_COMPAT
+            /* NOTE: For Windows compatibility, add a trailing space after 
printing the command parameter, if present */
+            if (*Buf) ConOutChar(_T(' '));
+#endif
+        }
         break;
+    }
 
     case C_QUIET:
         return;
 
     case C_BLOCK:
+    {
+        BOOLEAN bIsFirstCmdCRLF;
+
         ConOutChar(_T('('));
+
         Sub = Cmd->Subcommands;
-        if (Sub && !Sub->Next)
+
+        bIsFirstCmdCRLF = (Sub && Sub->Next);
+
+#if defined(MSCMD_ECHO_COMMAND_COMPAT) && defined(MSCMD_PARSER_BUGS)
+        /*
+         * We will emulate Windows' CMD handling of "CRLF" and "&" 
multi-command
+         * enumeration within parenthesized command blocks.
+         */
+        bIsFirstCmdCRLF = bIsFirstCmdCRLF && (Sub->Type != C_MULTI);
+#endif
+
+        /*
+         * Single-command block: display all on one line.
+         * Multi-command block: display commands on separate lines.
+         */
+        if (bIsFirstCmdCRLF)
+            ConOutChar(_T('\n'));
+
+        for (; Sub; Sub = Sub->Next)
         {
-            /* Single-command block: display all on one line */
             EchoCommand(Sub);
-        }
-        else if (Sub)
-        {
-            /* Multi-command block: display parenthesis on separate lines */
-            ConOutChar(_T('\n'));
-            do
-            {
-                EchoCommand(Sub);
+            if (Sub->Next)
+#ifdef MSCMD_ECHO_COMMAND_COMPAT
+                ConOutPuts(_T(" \n "));
+#else
                 ConOutChar(_T('\n'));
-                Sub = Sub->Next;
-            } while (Sub);
+#endif
         }
+
+        if (bIsFirstCmdCRLF)
+            ConOutChar(_T('\n'));
+
+#ifdef MSCMD_ECHO_COMMAND_COMPAT
+        /* NOTE: For Windows compatibility, add a trailing space after 
printing the closing parenthesis */
+        ConOutPuts(_T(") "));
+#else
         ConOutChar(_T(')'));
+#endif
         break;
+    }
 
     case C_MULTI:
     case C_OR:
     case C_AND:
     case C_PIPE:
+    {
         Sub = Cmd->Subcommands;
         EchoCommand(Sub);
         ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
         EchoCommand(Sub->Next);
         break;
+    }
 
     case C_IF:
+    {
         ConOutPuts(_T("if"));
         if (Cmd->If.Flags & IFFLAG_IGNORECASE)
             ConOutPuts(_T(" /I"));
@@ -1187,8 +1227,10 @@ EchoCommand(PARSED_COMMAND *Cmd)
             EchoCommand(Sub->Next);
         }
         break;
+    }
 
     case C_FOR:
+    {
         ConOutPuts(_T("for"));
         if (Cmd->For.Switches & FOR_DIRS)      ConOutPuts(_T(" /D"));
         if (Cmd->For.Switches & FOR_F)         ConOutPuts(_T(" /F"));
@@ -1204,12 +1246,24 @@ EchoCommand(PARSED_COMMAND *Cmd)
         break;
     }
 
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
     for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
     {
         if (SubstituteForVars(Redir->Filename, Buf))
         {
-            ConOutPrintf(_T(" %c%s%s"), _T('0') + Redir->Number,
+#ifdef MSCMD_ECHO_COMMAND_COMPAT
+            ConOutPrintf(_T("%c%s%s "),
+                         _T('0') + Redir->Number,
+                         RedirString[Redir->Mode], Buf);
+#else
+            ConOutPrintf(_T(" %c%s%s"),
+                         _T('0') + Redir->Number,
                          RedirString[Redir->Mode], Buf);
+#endif
         }
     }
 }
@@ -1325,6 +1379,10 @@ do { \
             PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
         RECURSE(Cmd->Subcommands);
         break;
+
+    default:
+        ASSERT(FALSE);
+        break;
     }
 
     for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
@@ -1335,6 +1393,11 @@ do { \
                RedirString[Redir->Mode], Buf);
     }
     return Out;
+
+#undef CHAR
+#undef STRING
+#undef PRINTF
+#undef RECURSE
 }
 
 VOID

Reply via email to