[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.
This commit is contained in:
Hermès Bélusca-Maïto 2020-06-10 01:18:41 +02:00
parent 47ea3f1faa
commit 26cfadc352
No known key found for this signature in database
GPG Key ID: 3B2539C65E7B93D0

View File

@ -4,6 +4,9 @@
#include "precomp.h" #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 * 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' * modified at runtime from a debugger. They correspond to the public Windows'
@ -1127,48 +1130,85 @@ EchoCommand(PARSED_COMMAND *Cmd)
switch (Cmd->Type) switch (Cmd->Type)
{ {
case C_COMMAND: case C_COMMAND:
{
if (SubstituteForVars(Cmd->Command.First, Buf)) if (SubstituteForVars(Cmd->Command.First, Buf))
ConOutPrintf(_T("%s"), Buf); ConOutPrintf(_T("%s"), Buf);
if (SubstituteForVars(Cmd->Command.Rest, Buf)) if (SubstituteForVars(Cmd->Command.Rest, Buf))
{
ConOutPrintf(_T("%s"), 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; break;
}
case C_QUIET: case C_QUIET:
return; return;
case C_BLOCK: case C_BLOCK:
{
BOOLEAN bIsFirstCmdCRLF;
ConOutChar(_T('(')); ConOutChar(_T('('));
Sub = Cmd->Subcommands; Sub = Cmd->Subcommands;
if (Sub && !Sub->Next)
{ bIsFirstCmdCRLF = (Sub && Sub->Next);
/* Single-command block: display all on one line */
EchoCommand(Sub); #if defined(MSCMD_ECHO_COMMAND_COMPAT) && defined(MSCMD_PARSER_BUGS)
} /*
else if (Sub) * We will emulate Windows' CMD handling of "CRLF" and "&" multi-command
{ * enumeration within parenthesized command blocks.
/* Multi-command block: display parenthesis on separate lines */ */
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')); ConOutChar(_T('\n'));
do
{ for (; Sub; Sub = Sub->Next)
EchoCommand(Sub); {
EchoCommand(Sub);
if (Sub->Next)
#ifdef MSCMD_ECHO_COMMAND_COMPAT
ConOutPuts(_T(" \n "));
#else
ConOutChar(_T('\n')); ConOutChar(_T('\n'));
Sub = Sub->Next; #endif
} while (Sub);
} }
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(')')); ConOutChar(_T(')'));
#endif
break; break;
}
case C_MULTI: case C_MULTI:
case C_OR: case C_OR:
case C_AND: case C_AND:
case C_PIPE: case C_PIPE:
{
Sub = Cmd->Subcommands; Sub = Cmd->Subcommands;
EchoCommand(Sub); EchoCommand(Sub);
ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]); ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
EchoCommand(Sub->Next); EchoCommand(Sub->Next);
break; break;
}
case C_IF: case C_IF:
{
ConOutPuts(_T("if")); ConOutPuts(_T("if"));
if (Cmd->If.Flags & IFFLAG_IGNORECASE) if (Cmd->If.Flags & IFFLAG_IGNORECASE)
ConOutPuts(_T(" /I")); ConOutPuts(_T(" /I"));
@ -1187,8 +1227,10 @@ EchoCommand(PARSED_COMMAND *Cmd)
EchoCommand(Sub->Next); EchoCommand(Sub->Next);
} }
break; break;
}
case C_FOR: case C_FOR:
{
ConOutPuts(_T("for")); ConOutPuts(_T("for"));
if (Cmd->For.Switches & FOR_DIRS) ConOutPuts(_T(" /D")); if (Cmd->For.Switches & FOR_DIRS) ConOutPuts(_T(" /D"));
if (Cmd->For.Switches & FOR_F) ConOutPuts(_T(" /F")); if (Cmd->For.Switches & FOR_F) ConOutPuts(_T(" /F"));
@ -1204,12 +1246,24 @@ EchoCommand(PARSED_COMMAND *Cmd)
break; break;
} }
default:
ASSERT(FALSE);
break;
}
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next) for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
{ {
if (SubstituteForVars(Redir->Filename, Buf)) 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); 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); PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
RECURSE(Cmd->Subcommands); RECURSE(Cmd->Subcommands);
break; break;
default:
ASSERT(FALSE);
break;
} }
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next) for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
@ -1335,6 +1393,11 @@ do { \
RedirString[Redir->Mode], Buf); RedirString[Redir->Mode], Buf);
} }
return Out; return Out;
#undef CHAR
#undef STRING
#undef PRINTF
#undef RECURSE
} }
VOID VOID