ReactOS  0.4.15-dev-1033-gd7d716a
parser.c File Reference
#include "precomp.h"
Include dependency graph for parser.c:

Go to the source code of this file.

Macros

#define MSCMD_ECHO_COMMAND_COMPAT
 
#define C_OP_LOWEST   C_MULTI
 
#define C_OP_HIGHEST   C_PIPE
 
#define IF_MAX_UNARY   IF_DEFINED
 
#define IF_MAX_COMPARISON   IF_GEQ
 
#define DUMP(Command, Pad)
 
#define CHAR(Char)
 
#define STRING(String)
 
#define PRINTF(Format, ...)
 
#define RECURSE(Subcommand)
 

Enumerations

enum  {
  TOK_END, TOK_NORMAL, TOK_OPERATOR, TOK_REDIRECTION,
  TOK_BEGIN_BLOCK, TOK_END_BLOCK
}
 

Functions

static BOOL IsSeparator (TCHAR Char)
 
static TCHAR ParseChar (void)
 
VOID ParseErrorEx (IN PCTSTR s)
 
static __inline VOID ParseError (VOID)
 
static int ParseToken (TCHAR ExtraEnd, TCHAR *Separators)
 
static BOOL ParseRedirection (REDIRECTION **List)
 
static PARSED_COMMANDParseCommandOp (int OpType)
 
static PARSED_COMMANDParseBlock (REDIRECTION *RedirList)
 
static PARSED_COMMANDParseIf (void)
 
static PARSED_COMMANDParseFor (void)
 
static PARSED_COMMANDParseRem (void)
 
static DECLSPEC_NOINLINE PARSED_COMMANDParseCommandPart (REDIRECTION *RedirList)
 
static PARSED_COMMANDParsePrimary (void)
 
VOID DumpCommand (PARSED_COMMAND *Cmd, ULONG SpacePad)
 
PARSED_COMMANDParseCommand (LPTSTR Line)
 
static VOID DumpRedir (REDIRECTION *Redirections)
 
VOID EchoCommand (PARSED_COMMAND *Cmd)
 
TCHARUnparse (PARSED_COMMAND *Cmd, TCHAR *Out, TCHAR *OutEnd)
 
VOID FreeCommand (PARSED_COMMAND *Cmd)
 

Variables

BOOLEAN fDumpTokens = FALSE
 
BOOLEAN fDumpParse = FALSE
 
static const TCHAR OpString [][3] = { _T("&"), _T("||"), _T("&&"), _T("|") }
 
static const TCHAR RedirString [][3] = { _T("<"), _T(">"), _T(">>") }
 
static const TCHAR *const IfOperatorString []
 
static TCHAR TempBuf [CMDLINE_LENGTH]
 
BOOL bParseError
 
static BOOL bLineContinuations
 
TCHAR ParseLine [CMDLINE_LENGTH]
 
static TCHARParsePos
 
static TCHAR CurChar
 
static TCHAR CurrentToken [CMDLINE_LENGTH]
 
static int CurrentTokenType
 
static int InsideBlock
 

Macro Definition Documentation

◆ C_OP_HIGHEST

#define C_OP_HIGHEST   C_PIPE

Definition at line 20 of file parser.c.

◆ C_OP_LOWEST

#define C_OP_LOWEST   C_MULTI

Definition at line 19 of file parser.c.

◆ CHAR

#define CHAR (   Char)
Value:
do { \
if (Out == OutEnd) return NULL; \
*Out++ = Char; \
} while (0)
smooth NULL
Definition: ftsmooth.c:416

◆ DUMP

#define DUMP (   Command,
  Pad 
)
Value:
do { \
Cmd = (Command); \
SpacePad = (Pad); \
goto dump; \
} while (0)
char * Pad(char *Str, char PadChar, ULONG Length)
Definition: cabman.cxx:29
struct Command Command
static void dump(const void *ptr, unsigned len)
Definition: msc.c:95

◆ IF_MAX_COMPARISON

#define IF_MAX_COMPARISON   IF_GEQ

◆ IF_MAX_UNARY

#define IF_MAX_UNARY   IF_DEFINED

◆ MSCMD_ECHO_COMMAND_COMPAT

#define MSCMD_ECHO_COMMAND_COMPAT

Definition at line 8 of file parser.c.

◆ PRINTF

#define PRINTF (   Format,
  ... 
)
Value:
do { \
UINT Len = _sntprintf(Out, OutEnd - Out, Format, __VA_ARGS__); \
if (Len > (UINT)(OutEnd - Out)) return NULL; \
Out += Len; \
} while (0)
smooth NULL
Definition: ftsmooth.c:416
#define Len
Definition: deflate.h:82
#define _sntprintf
Definition: xmlstorage.h:201
unsigned int UINT
Definition: ndis.h:50

◆ RECURSE

#define RECURSE (   Subcommand)
Value:
do { \
Out = Unparse(Subcommand, Out, OutEnd); \
if (!Out) return NULL; \
} while (0)
smooth NULL
Definition: ftsmooth.c:416
TCHAR * Unparse(PARSED_COMMAND *Cmd, TCHAR *Out, TCHAR *OutEnd)
Definition: parser.c:1294

◆ STRING

Value:
do { \
if (Out + _tcslen(String) > OutEnd) return NULL; \
Out = _stpcpy(Out, String); \
} while (0)
static WCHAR String[]
Definition: stringtable.c:55
LPTSTR _stpcpy(LPTSTR, LPCTSTR)
Definition: misc.c:460
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
TOK_END 
TOK_NORMAL 
TOK_OPERATOR 
TOK_REDIRECTION 
TOK_BEGIN_BLOCK 
TOK_END_BLOCK 

Definition at line 54 of file parser.c.

Function Documentation

◆ DumpCommand()

VOID DumpCommand ( PARSED_COMMAND Cmd,
ULONG  SpacePad 
)

Definition at line 873 of file parser.c.

874 {
875 /*
876  * This macro is like DumpCommand(Cmd, Pad);
877  * but avoids an extra recursive level.
878  * Note that it can be used ONLY for terminating commands!
879  */
880 #define DUMP(Command, Pad) \
881 do { \
882  Cmd = (Command); \
883  SpacePad = (Pad); \
884  goto dump; \
885 } while (0)
886 
887  PARSED_COMMAND *Sub;
888 
889 dump:
890  /* Space padding */
891  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
892 
893  switch (Cmd->Type)
894  {
895  case C_COMMAND:
896  {
897  /* Generic command name, and Type */
898 #ifndef MSCMD_ECHO_COMMAND_COMPAT
899  ConOutPrintf(_T("Cmd: %s Type: %x"),
900  Cmd->Command.First, Cmd->Type);
901 #else
902  ConOutPrintf(_T("Cmd: %s Type: %x "),
903  Cmd->Command.First, Cmd->Type);
904 #endif
905  /* Arguments */
906  if (Cmd->Command.Rest && *(Cmd->Command.Rest))
907 #ifndef MSCMD_ECHO_COMMAND_COMPAT
908  ConOutPrintf(_T(" Args: `%s'"), Cmd->Command.Rest);
909 #else
910  ConOutPrintf(_T("Args: `%s' "), Cmd->Command.Rest);
911 #endif
912  /* Redirections */
913  DumpRedir(Cmd->Redirections);
914 
915  ConOutChar(_T('\n'));
916  return;
917  }
918 
919  case C_QUIET:
920  {
921 #ifndef MSCMD_ECHO_COMMAND_COMPAT
922  ConOutChar(_T('@'));
923 #else
924  ConOutPuts(_T("@ "));
925 #endif
926  DumpRedir(Cmd->Redirections); // FIXME: Can we have leading redirections??
927  ConOutChar(_T('\n'));
928 
929  /*DumpCommand*/DUMP(Cmd->Subcommands, SpacePad + 2);
930  return;
931  }
932 
933  case C_BLOCK:
934  {
935 #ifndef MSCMD_ECHO_COMMAND_COMPAT
936  ConOutChar(_T('('));
937 #else
938  ConOutPuts(_T("( "));
939 #endif
940  DumpRedir(Cmd->Redirections);
941  ConOutChar(_T('\n'));
942 
943  SpacePad += 2;
944 
945  for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next)
946  {
947 #if defined(MSCMD_ECHO_COMMAND_COMPAT) && defined(MSCMD_PARSER_BUGS)
948  /*
949  * We will emulate Windows' CMD handling of "CRLF" and "&" multi-command
950  * enumeration within parenthesized command blocks.
951  */
952 
953  if (!Sub->Next)
954  {
955  DumpCommand(Sub, SpacePad);
956  continue;
957  }
958 
959  if (Sub->Type != C_MULTI)
960  {
961  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
962  ConOutPuts(_T("CRLF \n"));
963  DumpCommand(Sub, SpacePad);
964  continue;
965  }
966 
967  /* Now, Sub->Type == C_MULTI */
968 
969  Cmd = Sub;
970 
971  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
972  ConOutPrintf(_T("%s \n"), OpString[Cmd->Type - C_OP_LOWEST]);
973  // FIXME: Can we have redirections on these operator-type commands?
974 
975  SpacePad += 2;
976 
977  Cmd = Cmd->Subcommands;
978  DumpCommand(Cmd, SpacePad);
979  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
980  ConOutPuts(_T("CRLF \n"));
981  DumpCommand(Cmd->Next, SpacePad);
982 
983  // NOTE: Next commands will remain indented.
984 
985 #else
986 
987  /*
988  * If this command is followed by another one, first display "CRLF".
989  * This also emulates the CRLF placement "bug" of Windows' CMD
990  * for the last two commands.
991  */
992  if (Sub->Next)
993  {
994  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
995 #ifndef MSCMD_ECHO_COMMAND_COMPAT
996  ConOutPuts(_T("CRLF\n"));
997 #else
998  ConOutPuts(_T("CRLF \n"));
999 #endif
1000  }
1001  DumpCommand(Sub, SpacePad);
1002 
1003 #endif // defined(MSCMD_ECHO_COMMAND_COMPAT) && defined(MSCMD_PARSER_BUGS)
1004  }
1005 
1006  return;
1007  }
1008 
1009  case C_MULTI:
1010  case C_OR:
1011  case C_AND:
1012  case C_PIPE:
1013  {
1014 #ifndef MSCMD_ECHO_COMMAND_COMPAT
1015  ConOutPrintf(_T("%s\n"), OpString[Cmd->Type - C_OP_LOWEST]);
1016 #else
1017  ConOutPrintf(_T("%s \n"), OpString[Cmd->Type - C_OP_LOWEST]);
1018 #endif
1019  // FIXME: Can we have redirections on these operator-type commands?
1020 
1021  SpacePad += 2;
1022 
1023  Sub = Cmd->Subcommands;
1024  DumpCommand(Sub, SpacePad);
1025  /*DumpCommand*/DUMP(Sub->Next, SpacePad);
1026  return;
1027  }
1028 
1029  case C_IF:
1030  {
1031  ConOutPuts(_T("if"));
1032  /* NOTE: IF cannot have leading redirections */
1033 
1034  if (Cmd->If.Flags & IFFLAG_IGNORECASE)
1035  ConOutPuts(_T(" /I"));
1036 
1037  ConOutChar(_T('\n'));
1038 
1039  SpacePad += 2;
1040 
1041  /*
1042  * Show the IF command condition as a command.
1043  * If it is negated, indent the command more.
1044  */
1045  if (Cmd->If.Flags & IFFLAG_NEGATE)
1046  {
1047  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
1048  ConOutPuts(_T("not\n"));
1049  SpacePad += 2;
1050  }
1051 
1052  ConOutPrintf(_T("%*s"), SpacePad, _T(""));
1053 
1054  /*
1055  * Command name:
1056  * - Unary operator: its name is the command name, and its argument is the command argument.
1057  * - Binary operator: its LHS is the command name, its RHS is the command argument.
1058  *
1059  * Type:
1060  * Windows' CMD (Win2k3 / Win7-10) values are as follows:
1061  * CMDEXTVERSION Type: 0x32 / 0x34
1062  * ERRORLEVEL Type: 0x33 / 0x35
1063  * DEFINED Type: 0x34 / 0x36
1064  * EXIST Type: 0x35 / 0x37
1065  * == Type: 0x37 / 0x39 (String Comparison)
1066  *
1067  * For the following command:
1068  * NOT Type: 0x36 / 0x38
1069  * Windows only prints it without any type / redirection.
1070  *
1071  * For the following command:
1072  * EQU, NEQ, etc. Type: 0x38 / 0x3a (Generic Comparison)
1073  * Windows displays it as command of unknown type.
1074  */
1075 #ifndef MSCMD_ECHO_COMMAND_COMPAT
1076  ConOutPrintf(_T("Cmd: %s Type: %x"),
1077  (Cmd->If.Operator <= IF_MAX_UNARY) ?
1078  IfOperatorString[Cmd->If.Operator] :
1079  Cmd->If.LeftArg,
1080  Cmd->If.Operator);
1081 #else
1082  ConOutPrintf(_T("Cmd: %s Type: %x "),
1083  (Cmd->If.Operator <= IF_MAX_UNARY) ?
1084  IfOperatorString[Cmd->If.Operator] :
1085  Cmd->If.LeftArg,
1086  Cmd->If.Operator);
1087 #endif
1088  /* Arguments */
1089 #ifndef MSCMD_ECHO_COMMAND_COMPAT
1090  ConOutPrintf(_T(" Args: `%s'"), Cmd->If.RightArg);
1091 #else
1092  ConOutPrintf(_T("Args: `%s' "), Cmd->If.RightArg);
1093 #endif
1094 
1095  ConOutChar(_T('\n'));
1096 
1097  if (Cmd->If.Flags & IFFLAG_NEGATE)
1098  {
1099  SpacePad -= 2;
1100  }
1101 
1102  Sub = Cmd->Subcommands;
1103  DumpCommand(Sub, SpacePad);
1104  if (Sub->Next)
1105  {
1106  ConOutPrintf(_T("%*s"), SpacePad - 2, _T(""));
1107  ConOutPuts(_T("else\n"));
1108  DumpCommand(Sub->Next, SpacePad);
1109  }
1110  return;
1111  }
1112 
1113  case C_FOR:
1114  {
1115  ConOutPuts(_T("for"));
1116  /* NOTE: FOR cannot have leading redirections */
1117 
1118  if (Cmd->For.Switches & FOR_DIRS) ConOutPuts(_T(" /D"));
1119  if (Cmd->For.Switches & FOR_F) ConOutPuts(_T(" /F"));
1120  if (Cmd->For.Switches & FOR_LOOP) ConOutPuts(_T(" /L"));
1121  if (Cmd->For.Switches & FOR_RECURSIVE) ConOutPuts(_T(" /R"));
1122  if (Cmd->For.Params)
1123  ConOutPrintf(_T(" %s"), Cmd->For.Params);
1124  ConOutPrintf(_T(" %%%c in (%s) do\n"), Cmd->For.Variable, Cmd->For.List);
1125  /*DumpCommand*/DUMP(Cmd->Subcommands, SpacePad + 2);
1126  return;
1127  }
1128 
1129  default:
1130  ConOutPrintf(_T("*** Unknown type: %x\n"), Cmd->Type);
1131  break;
1132  }
1133 
1134 #undef DUMP
1135 }
#define FOR_DIRS
Definition: cmd.h:234
#define IFFLAG_IGNORECASE
Definition: cmd.h:261
VOID ConOutChar(TCHAR c)
Definition: console.c:123
BYTE Type
Definition: cmd.h:354
#define IF_MAX_UNARY
Definition: cmd.h:348
#define ConOutPrintf(szStr,...)
Definition: console.h:42
#define FOR_F
Definition: cmd.h:235
struct _PARSED_COMMAND * Next
Definition: cmd.h:352
#define C_OP_LOWEST
Definition: parser.c:19
Definition: cmd.h:348
#define FOR_LOOP
Definition: cmd.h:236
Definition: cmd.h:348
#define _T(x)
Definition: vfdio.h:22
Definition: cmd.h:348
Definition: cmd.h:348
#define IFFLAG_NEGATE
Definition: cmd.h:260
static const TCHAR *const IfOperatorString[]
Definition: parser.c:25
#define FOR_RECURSIVE
Definition: cmd.h:237
Definition: sacdrv.h:277
Definition: cmd.h:348
#define DUMP(Command, Pad)
Definition: cmd.h:348
VOID DumpCommand(PARSED_COMMAND *Cmd, ULONG SpacePad)
Definition: parser.c:873
static const TCHAR OpString[][3]
Definition: parser.c:21
static VOID DumpRedir(REDIRECTION *Redirections)
Definition: parser.c:855
Definition: cmd.h:348
Definition: cmd.h:348
static void dump(const void *ptr, unsigned len)
Definition: msc.c:95
VOID ConOutPuts(LPTSTR szText)
Definition: tee.c:27

Referenced by ParseCommand().

◆ DumpRedir()

static VOID DumpRedir ( REDIRECTION Redirections)
static

Definition at line 855 of file parser.c.

856 {
857  REDIRECTION* Redir;
858 
859  if (Redirections)
860 #ifndef MSCMD_ECHO_COMMAND_COMPAT
861  ConOutPuts(_T(" Redir: "));
862 #else
863  ConOutPuts(_T("Redir: "));
864 #endif
865  for (Redir = Redirections; Redir; Redir = Redir->Next)
866  {
867  ConOutPrintf(_T(" %x %s%s"), Redir->Number,
868  RedirString[Redir->Mode], Redir->Filename);
869  }
870 }
#define ConOutPrintf(szStr,...)
Definition: console.h:42
REDIR_MODE Mode
Definition: cmd.h:412
BYTE Number
Definition: cmd.h:411
#define _T(x)
Definition: vfdio.h:22
TCHAR Filename[]
Definition: cmd.h:413
static const TCHAR RedirString[][3]
Definition: parser.c:23
struct _REDIRECTION * Next
Definition: cmd.h:409
VOID ConOutPuts(LPTSTR szText)
Definition: tee.c:27

Referenced by DumpCommand().

◆ EchoCommand()

VOID EchoCommand ( PARSED_COMMAND Cmd)

Definition at line 1142 of file parser.c.

1143 {
1144  PARSED_COMMAND *Sub;
1145  REDIRECTION *Redir;
1146 
1147  switch (Cmd->Type)
1148  {
1149  case C_COMMAND:
1150  {
1151  if (SubstituteForVars(Cmd->Command.First, TempBuf))
1152  ConOutPrintf(_T("%s"), TempBuf);
1153  if (SubstituteForVars(Cmd->Command.Rest, TempBuf))
1154  {
1155  ConOutPrintf(_T("%s"), TempBuf);
1156 #ifdef MSCMD_ECHO_COMMAND_COMPAT
1157  /* NOTE: For Windows compatibility, add a trailing space after printing the command parameter, if present */
1158  if (*TempBuf) ConOutChar(_T(' '));
1159 #endif
1160  }
1161  break;
1162  }
1163 
1164  case C_QUIET:
1165  return;
1166 
1167  case C_BLOCK:
1168  {
1169  BOOLEAN bIsFirstCmdCRLF;
1170 
1171  ConOutChar(_T('('));
1172 
1173  Sub = Cmd->Subcommands;
1174 
1175  bIsFirstCmdCRLF = (Sub && Sub->Next);
1176 
1177 #if defined(MSCMD_ECHO_COMMAND_COMPAT) && defined(MSCMD_PARSER_BUGS)
1178  /*
1179  * We will emulate Windows' CMD handling of "CRLF" and "&" multi-command
1180  * enumeration within parenthesized command blocks.
1181  */
1182  bIsFirstCmdCRLF = bIsFirstCmdCRLF && (Sub->Type != C_MULTI);
1183 #endif
1184 
1185  /*
1186  * Single-command block: display all on one line.
1187  * Multi-command block: display commands on separate lines.
1188  */
1189  if (bIsFirstCmdCRLF)
1190  ConOutChar(_T('\n'));
1191 
1192  for (; Sub; Sub = Sub->Next)
1193  {
1194  EchoCommand(Sub);
1195  if (Sub->Next)
1196 #ifdef MSCMD_ECHO_COMMAND_COMPAT
1197  ConOutPuts(_T(" \n "));
1198 #else
1199  ConOutChar(_T('\n'));
1200 #endif
1201  }
1202 
1203  if (bIsFirstCmdCRLF)
1204  ConOutChar(_T('\n'));
1205 
1206 #ifdef MSCMD_ECHO_COMMAND_COMPAT
1207  /* NOTE: For Windows compatibility, add a trailing space after printing the closing parenthesis */
1208  ConOutPuts(_T(") "));
1209 #else
1210  ConOutChar(_T(')'));
1211 #endif
1212  break;
1213  }
1214 
1215  case C_MULTI:
1216  case C_OR:
1217  case C_AND:
1218  case C_PIPE:
1219  {
1220  Sub = Cmd->Subcommands;
1221  EchoCommand(Sub);
1222  ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
1223  EchoCommand(Sub->Next);
1224  break;
1225  }
1226 
1227  case C_IF:
1228  {
1229  ConOutPuts(_T("if"));
1230  if (Cmd->If.Flags & IFFLAG_IGNORECASE)
1231  ConOutPuts(_T(" /I"));
1232  if (Cmd->If.Flags & IFFLAG_NEGATE)
1233  ConOutPuts(_T(" not"));
1234  if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, TempBuf))
1235  ConOutPrintf(_T(" %s"), TempBuf);
1236  ConOutPrintf(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
1237  if (SubstituteForVars(Cmd->If.RightArg, TempBuf))
1238  ConOutPrintf(_T(" %s "), TempBuf);
1239  Sub = Cmd->Subcommands;
1240  EchoCommand(Sub);
1241  if (Sub->Next)
1242  {
1243  ConOutPuts(_T(" else "));
1244  EchoCommand(Sub->Next);
1245  }
1246  break;
1247  }
1248 
1249  case C_FOR:
1250  {
1251  ConOutPuts(_T("for"));
1252  if (Cmd->For.Switches & FOR_DIRS) ConOutPuts(_T(" /D"));
1253  if (Cmd->For.Switches & FOR_F) ConOutPuts(_T(" /F"));
1254  if (Cmd->For.Switches & FOR_LOOP) ConOutPuts(_T(" /L"));
1255  if (Cmd->For.Switches & FOR_RECURSIVE) ConOutPuts(_T(" /R"));
1256  if (Cmd->For.Params)
1257  ConOutPrintf(_T(" %s"), Cmd->For.Params);
1258  if (Cmd->For.List && SubstituteForVars(Cmd->For.List, TempBuf))
1259  ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, TempBuf);
1260  else
1261  ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
1262  EchoCommand(Cmd->Subcommands);
1263  break;
1264  }
1265 
1266  default:
1267  ASSERT(FALSE);
1268  break;
1269  }
1270 
1271  for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
1272  {
1273  if (SubstituteForVars(Redir->Filename, TempBuf))
1274  {
1275 #ifdef MSCMD_ECHO_COMMAND_COMPAT
1276  ConOutPrintf(_T("%c%s%s "),
1277  _T('0') + Redir->Number,
1278  RedirString[Redir->Mode], TempBuf);
1279 #else
1280  ConOutPrintf(_T(" %c%s%s"),
1281  _T('0') + Redir->Number,
1282  RedirString[Redir->Mode], TempBuf);
1283 #endif
1284  }
1285  }
1286 }
#define FOR_DIRS
Definition: cmd.h:234
#define IFFLAG_IGNORECASE
Definition: cmd.h:261
VOID ConOutChar(TCHAR c)
Definition: console.c:123
BYTE Type
Definition: cmd.h:354
Definition: cmd.h:348
#define ConOutPrintf(szStr,...)
Definition: console.h:42
#define FOR_F
Definition: cmd.h:235
struct _PARSED_COMMAND * Next
Definition: cmd.h:352
#define C_OP_LOWEST
Definition: parser.c:19
REDIR_MODE Mode
Definition: cmd.h:412
Definition: cmd.h:348
#define FALSE
Definition: types.h:117
#define FOR_LOOP
Definition: cmd.h:236
unsigned char BOOLEAN
Definition: cmd.h:348
BYTE Number
Definition: cmd.h:411
#define _T(x)
Definition: vfdio.h:22
BOOL SubstituteForVars(IN PCTSTR Src, OUT PTSTR Dest)
Definition: cmd.c:1593
Definition: cmd.h:348
Definition: cmd.h:348
#define IFFLAG_NEGATE
Definition: cmd.h:260
TCHAR Filename[]
Definition: cmd.h:413
static const TCHAR *const IfOperatorString[]
Definition: parser.c:25
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define FOR_RECURSIVE
Definition: cmd.h:237
static const TCHAR RedirString[][3]
Definition: parser.c:23
Definition: sacdrv.h:277
Definition: cmd.h:348
Definition: cmd.h:348
static const TCHAR OpString[][3]
Definition: parser.c:21
struct _REDIRECTION * Next
Definition: cmd.h:409
Definition: cmd.h:348
static TCHAR TempBuf[CMDLINE_LENGTH]
Definition: parser.c:65
Definition: cmd.h:348
VOID EchoCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1142
VOID ConOutPuts(LPTSTR szText)
Definition: tee.c:27

Referenced by ExecuteCommandWithEcho().

◆ FreeCommand()

VOID FreeCommand ( PARSED_COMMAND Cmd)

Definition at line 1420 of file parser.c.

1421 {
1422  if (Cmd->Subcommands)
1423  FreeCommand(Cmd->Subcommands);
1424  if (Cmd->Next)
1425  FreeCommand(Cmd->Next);
1426  FreeRedirection(Cmd->Redirections);
1427  if (Cmd->Type == C_IF)
1428  {
1429  cmd_free(Cmd->If.LeftArg);
1430  cmd_free(Cmd->If.RightArg);
1431  }
1432  else if (Cmd->Type == C_FOR)
1433  {
1434  cmd_free(Cmd->For.Params);
1435  cmd_free(Cmd->For.List);
1436  }
1437  cmd_free(Cmd);
1438 }
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
Definition: sacdrv.h:277
#define cmd_free(ptr)
Definition: cmddbg.h:31
Definition: cmd.h:348
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
Definition: cmd.h:348

Referenced by Batch(), ParseBlock(), ParseCommand(), ParseCommandLine(), ParseCommandOp(), ParseFor(), ParseIf(), and ProcessInput().

◆ IsSeparator()

static BOOL IsSeparator ( TCHAR  Char)
static

Definition at line 49 of file parser.c.

50 {
51  return _istspace(Char) || (Char && _tcschr(STANDARD_SEPS, Char));
52 }
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
#define STANDARD_SEPS
Definition: cmd.h:346
#define _istspace
Definition: tchar.h:1504

Referenced by ParsePrimary(), and ParseToken().

◆ ParseBlock()

static PARSED_COMMAND* ParseBlock ( REDIRECTION RedirList)
static

Definition at line 329 of file parser.c.

330 {
331  PARSED_COMMAND *Cmd, *Sub, **NextPtr;
332 
333  Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
334  if (!Cmd)
335  {
336  WARN("Cannot allocate memory for Cmd!\n");
337  ParseError();
338  FreeRedirection(RedirList);
339  return NULL;
340  }
341  Cmd->Type = C_BLOCK;
342  Cmd->Next = NULL;
343  Cmd->Subcommands = NULL;
344  Cmd->Redirections = RedirList;
345 
346  /* Read the block contents */
347  NextPtr = &Cmd->Subcommands;
348  InsideBlock++;
349  while (1)
350  {
352  if (Sub)
353  {
354  *NextPtr = Sub;
355  NextPtr = &Sub->Next;
356  }
357  else if (bParseError)
358  {
359  InsideBlock--;
360  FreeCommand(Cmd);
361  return NULL;
362  }
363 
365  break;
366 
367  /* Skip past the \n */
368  ParseChar();
369  }
370  InsideBlock--;
371 
372  /* Process any trailing redirections */
374  {
375  if (!ParseRedirection(&Cmd->Redirections))
376  {
377  FreeCommand(Cmd);
378  return NULL;
379  }
380  }
381  return Cmd;
382 }
static int CurrentTokenType
Definition: parser.c:74
#define WARN(fmt,...)
Definition: debug.h:112
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
struct _PARSED_COMMAND * Next
Definition: cmd.h:352
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
#define C_OP_LOWEST
Definition: parser.c:19
static BOOL ParseRedirection(REDIRECTION **List)
Definition: parser.c:257
BOOL bParseError
Definition: parser.c:67
smooth NULL
Definition: ftsmooth.c:416
Definition: cmd.h:348
static TCHAR ParseChar(void)
Definition: parser.c:77
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
#define STANDARD_SEPS
Definition: cmd.h:346
#define cmd_alloc(size)
Definition: cmddbg.h:29
static int InsideBlock
Definition: parser.c:75
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParsePrimary().

◆ ParseChar()

static TCHAR ParseChar ( void  )
static

Definition at line 77 of file parser.c.

78 {
79  TCHAR Char;
80 
81  if (bParseError)
82  return (CurChar = 0);
83 
84 restart:
85  /*
86  * Although CRs can be injected into a line via an environment
87  * variable substitution, the parser ignores them - they won't
88  * even separate tokens.
89  */
90  do
91  {
92  Char = *ParsePos++;
93  }
94  while (Char == _T('\r'));
95 
96  if (!Char)
97  {
98  ParsePos--;
100  {
101  if (!ReadLine(ParseLine, TRUE))
102  {
103  /* ^C pressed, or line was too long */
104  bParseError = TRUE;
105  }
106  else if (*(ParsePos = ParseLine))
107  {
108  goto restart;
109  }
110  }
111  }
112  return (CurChar = Char);
113 }
#define TRUE
Definition: types.h:120
static BOOL bLineContinuations
Definition: parser.c:68
BOOL bParseError
Definition: parser.c:67
void restart(int argc, const char *argv[])
Definition: cmds.c:2115
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
TCHAR ParseLine[CMDLINE_LENGTH]
Definition: parser.c:69
static TCHAR * ParsePos
Definition: parser.c:70
BOOL ReadLine(TCHAR *commandline, BOOL bMore)
Definition: cmd.c:1718
static TCHAR CurChar
Definition: parser.c:71

Referenced by ParseBlock(), ParseFor(), ParsePrimary(), and ParseToken().

◆ ParseCommand()

PARSED_COMMAND* ParseCommand ( LPTSTR  Line)

Definition at line 805 of file parser.c.

806 {
808 
809  if (Line)
810  {
811  if (!SubstituteVars(Line, ParseLine, _T('%')))
812  return NULL;
814  }
815  else
816  {
817  if (!ReadLine(ParseLine, FALSE))
818  return NULL;
820  }
821  bParseError = FALSE;
823  CurChar = _T(' ');
824 
826  if (Cmd)
827  {
828  bIgnoreEcho = FALSE;
829 
830  if (CurrentTokenType != TOK_END)
831  ParseError();
832  if (bParseError)
833  {
834  FreeCommand(Cmd);
835  return NULL;
836  }
837 
838  /* Debugging support */
839  if (fDumpParse)
840  DumpCommand(Cmd, 0);
841  }
842  else
843  {
844  bIgnoreEcho = TRUE;
845  }
846  return Cmd;
847 }
static int CurrentTokenType
Definition: parser.c:74
Definition: parser.c:56
BOOL SubstituteVars(IN PCTSTR Src, OUT PTSTR Dest, IN TCHAR Delim)
Definition: cmd.c:1511
BOOL bIgnoreEcho
Definition: cmd.c:155
#define TRUE
Definition: types.h:120
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
#define C_OP_LOWEST
Definition: parser.c:19
static BOOL bLineContinuations
Definition: parser.c:68
BOOL bParseError
Definition: parser.c:67
#define FALSE
Definition: types.h:117
smooth NULL
Definition: ftsmooth.c:416
#define _T(x)
Definition: vfdio.h:22
TCHAR ParseLine[CMDLINE_LENGTH]
Definition: parser.c:69
static TCHAR * ParsePos
Definition: parser.c:70
BOOL ReadLine(TCHAR *commandline, BOOL bMore)
Definition: cmd.c:1718
Definition: ncftp.h:79
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
static TCHAR CurChar
Definition: parser.c:71
VOID DumpCommand(PARSED_COMMAND *Cmd, ULONG SpacePad)
Definition: parser.c:873
BOOLEAN fDumpParse
Definition: parser.c:17
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by Batch(), ParseCommandLine(), and ProcessInput().

◆ ParseCommandOp()

static PARSED_COMMAND * ParseCommandOp ( int  OpType)
static

Definition at line 755 of file parser.c.

756 {
757  PARSED_COMMAND *Cmd, *Left, *Right;
758 
759  if (OpType == C_OP_HIGHEST)
760  Cmd = ParsePrimary();
761  else
762  Cmd = ParseCommandOp(OpType + 1);
763 
764  if (Cmd && !_tcscmp(CurrentToken, OpString[OpType - C_OP_LOWEST]))
765  {
766  Left = Cmd;
767  Right = ParseCommandOp(OpType);
768  if (!Right)
769  {
770  if (!bParseError)
771  {
772  /* & is allowed to have an empty RHS */
773  if (OpType == C_MULTI)
774  return Left;
775  ParseError();
776  }
777  FreeCommand(Left);
778  return NULL;
779  }
780 
781  Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
782  if (!Cmd)
783  {
784  WARN("Cannot allocate memory for Cmd!\n");
785  ParseError();
786  FreeCommand(Left);
787  FreeCommand(Right);
788  return NULL;
789  }
790  Cmd->Type = OpType;
791  Cmd->Next = NULL;
792  Cmd->Redirections = NULL;
793  Cmd->Subcommands = Left;
794  Left->Next = Right;
795  Right->Next = NULL;
796  }
797 
798  return Cmd;
799 }
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
#define WARN(fmt,...)
Definition: debug.h:112
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
struct _PARSED_COMMAND * Next
Definition: cmd.h:352
#define C_OP_LOWEST
Definition: parser.c:19
BOOL bParseError
Definition: parser.c:67
smooth NULL
Definition: ftsmooth.c:416
Definition: cmd.h:348
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
#define cmd_alloc(size)
Definition: cmddbg.h:29
static const TCHAR OpString[][3]
Definition: parser.c:21
#define C_OP_HIGHEST
Definition: parser.c:20
static __inline VOID ParseError(VOID)
Definition: parser.c:123
static PARSED_COMMAND * ParsePrimary(void)
Definition: parser.c:692

Referenced by ParseBlock(), ParseCommand(), ParseFor(), ParseIf(), and ParsePrimary().

◆ ParseCommandPart()

static DECLSPEC_NOINLINE PARSED_COMMAND* ParseCommandPart ( REDIRECTION RedirList)
static

Definition at line 620 of file parser.c.

621 {
622  TCHAR ParsedLine[CMDLINE_LENGTH];
624  PARSED_COMMAND *(*Func)(void);
625 
626  TCHAR *Pos = _stpcpy(ParsedLine, CurrentToken) + 1;
627  DWORD_PTR TailOffset = Pos - ParsedLine;
628 
629  /* Check for special forms */
630  if ((Func = ParseFor, _tcsicmp(ParsedLine, _T("for")) == 0) ||
631  (Func = ParseIf, _tcsicmp(ParsedLine, _T("if")) == 0) ||
632  (Func = ParseRem, _tcsicmp(ParsedLine, _T("rem")) == 0))
633  {
635  /* Do special parsing only if it's not followed by /? */
636  if (_tcscmp(CurrentToken, _T("/?")) != 0)
637  {
638  if (RedirList)
639  {
640  ParseError();
641  FreeRedirection(RedirList);
642  return NULL;
643  }
644  return Func();
645  }
646  Pos = _stpcpy(Pos, _T(" /?"));
647  }
648 
649  /* Now get the tail */
650  while (1)
651  {
652  ParseToken(0, NULL);
654  {
655  if (Pos + _tcslen(CurrentToken) >= &ParsedLine[CMDLINE_LENGTH])
656  {
657  ParseError();
658  FreeRedirection(RedirList);
659  return NULL;
660  }
662  }
663  else if (CurrentTokenType == TOK_REDIRECTION)
664  {
665  if (!ParseRedirection(&RedirList))
666  return NULL;
667  }
668  else
669  {
670  break;
671  }
672  }
673  *Pos++ = _T('\0');
674 
675  Cmd = cmd_alloc(FIELD_OFFSET(PARSED_COMMAND, Command.First[Pos - ParsedLine]));
676  if (!Cmd)
677  {
678  WARN("Cannot allocate memory for Cmd!\n");
679  ParseError();
680  FreeRedirection(RedirList);
681  return NULL;
682  }
683  Cmd->Type = C_COMMAND;
684  Cmd->Next = NULL;
685  Cmd->Subcommands = NULL;
686  Cmd->Redirections = RedirList;
687  memcpy(Cmd->Command.First, ParsedLine, (Pos - ParsedLine) * sizeof(TCHAR));
688  Cmd->Command.Rest = Cmd->Command.First + TailOffset;
689  return Cmd;
690 }
static int CurrentTokenType
Definition: parser.c:74
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define _tcsicmp
Definition: xmlstorage.h:205
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
#define WARN(fmt,...)
Definition: debug.h:112
ush Pos
Definition: deflate.h:92
#define CMDLINE_LENGTH
Definition: help.h:12
Definition: shell.h:41
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
static PARSED_COMMAND * ParseFor(void)
Definition: parser.c:481
static BOOL ParseRedirection(REDIRECTION **List)
Definition: parser.c:257
LPTSTR _stpcpy(LPTSTR, LPCTSTR)
Definition: misc.c:460
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416
static PARSED_COMMAND * ParseIf(void)
Definition: parser.c:385
char TCHAR
Definition: xmlstorage.h:189
static PARSED_COMMAND * ParseRem(void)
Definition: parser.c:611
#define _T(x)
Definition: vfdio.h:22
Definition: sacdrv.h:277
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define STANDARD_SEPS
Definition: cmd.h:346
uint32_t DWORD_PTR
Definition: typedefs.h:65
#define cmd_alloc(size)
Definition: cmddbg.h:29
void(* Func)(int)
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
Definition: cmd.h:348
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParsePrimary().

◆ ParseError()

static __inline VOID ParseError ( VOID  )
static

Definition at line 123 of file parser.c.

124 {
126 }
static int CurrentTokenType
Definition: parser.c:74
Definition: parser.c:56
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
smooth NULL
Definition: ftsmooth.c:416
VOID ParseErrorEx(IN PCTSTR s)
Definition: parser.c:115

Referenced by ParseBlock(), ParseCommand(), ParseCommandOp(), ParseCommandPart(), ParseFor(), ParseIf(), ParsePrimary(), and ParseRedirection().

◆ ParseErrorEx()

VOID ParseErrorEx ( IN PCTSTR  s)

Definition at line 115 of file parser.c.

116 {
117  /* Only display the first error we encounter */
118  if (!bParseError)
119  error_syntax(s);
120  bParseError = TRUE;
121 }
#define TRUE
Definition: types.h:120
BOOL bParseError
Definition: parser.c:67
GLdouble s
Definition: gl.h:2039
VOID error_syntax(PCTSTR s)
Definition: error.c:152

Referenced by cmd_for(), cmd_if(), GetBatchVar(), and ParseError().

◆ ParseFor()

static PARSED_COMMAND* ParseFor ( void  )
static

Definition at line 481 of file parser.c.

482 {
484  TCHAR* List = TempBuf;
485  TCHAR *Pos = List;
486 
487  Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
488  if (!Cmd)
489  {
490  WARN("Cannot allocate memory for Cmd!\n");
491  ParseError();
492  return NULL;
493  }
494  memset(Cmd, 0, sizeof(PARSED_COMMAND));
495  Cmd->Type = C_FOR;
496 
497  /* Skip the extended FOR syntax if extensions are disabled */
498  if (!bEnableExtensions)
499  goto parseForBody;
500 
501  while (1)
502  {
503  if (_tcsicmp(CurrentToken, _T("/D")) == 0)
504  {
505  Cmd->For.Switches |= FOR_DIRS;
506  }
507  else if (_tcsicmp(CurrentToken, _T("/F")) == 0)
508  {
509  Cmd->For.Switches |= FOR_F;
510  if (!Cmd->For.Params)
511  {
513  if (CurrentToken[0] == _T('/') || CurrentToken[0] == _T('%'))
514  break;
515  Cmd->For.Params = cmd_dup(CurrentToken);
516  }
517  }
518  else if (_tcsicmp(CurrentToken, _T("/L")) == 0)
519  {
520  Cmd->For.Switches |= FOR_LOOP;
521  }
522  else if (_tcsicmp(CurrentToken, _T("/R")) == 0)
523  {
524  Cmd->For.Switches |= FOR_RECURSIVE;
525  if (!Cmd->For.Params)
526  {
528  if (CurrentToken[0] == _T('/') || CurrentToken[0] == _T('%'))
529  break;
531  Cmd->For.Params = cmd_dup(CurrentToken);
532  }
533  }
534  else
535  {
536  break;
537  }
538 
540  }
541 
542  /* Make sure there aren't two different switches specified
543  * at the same time, unless they're /D and /R */
544  if ((Cmd->For.Switches & (Cmd->For.Switches - 1)) != 0
545  && Cmd->For.Switches != (FOR_DIRS | FOR_RECURSIVE))
546  {
547  goto error;
548  }
549 
550 parseForBody:
551 
552  /* Variable name should be % and just one other character */
553  if (CurrentToken[0] != _T('%') || _tcslen(CurrentToken) != 2)
554  goto error;
555  Cmd->For.Variable = CurrentToken[1];
556 
558  if (_tcsicmp(CurrentToken, _T("in")) != 0)
559  goto error;
560 
562  goto error;
563 
564  while (1)
565  {
566  /* Pretend we're inside a block so the tokenizer will stop on ')' */
567  InsideBlock++;
569  InsideBlock--;
570 
572  break;
573 
574  if (CurrentTokenType == TOK_END)
575  {
576  /* Skip past the \n */
577  ParseChar();
578  continue;
579  }
580 
582  goto error;
583 
584  if (Pos != List)
585  *Pos++ = _T(' ');
586 
588  goto error;
590  }
591  *Pos = _T('\0');
592  Cmd->For.List = cmd_dup(List);
593 
595  if (_tcsicmp(CurrentToken, _T("do")) != 0)
596  goto error;
597 
598  Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
599  if (Cmd->Subcommands == NULL)
600  goto error;
601 
602  return Cmd;
603 
604 error:
605  FreeCommand(Cmd);
606  ParseError();
607  return NULL;
608 }
#define FOR_DIRS
Definition: cmd.h:234
static int CurrentTokenType
Definition: parser.c:74
Definition: parser.c:56
#define _tcsicmp
Definition: xmlstorage.h:205
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
#define WARN(fmt,...)
Definition: debug.h:112
ush Pos
Definition: deflate.h:92
#define CMDLINE_LENGTH
Definition: help.h:12
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
static VOID StripQuotes(LPSTR in)
Definition: cmdcons.c:116
#define FOR_F
Definition: cmd.h:235
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
#define C_OP_LOWEST
Definition: parser.c:19
LPTSTR _stpcpy(LPTSTR, LPCTSTR)
Definition: misc.c:460
#define FOR_LOOP
Definition: cmd.h:236
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
LIST_ENTRY List
Definition: psmgr.c:57
DWORD error
Definition: parser.c:105
static TCHAR ParseChar(void)
Definition: parser.c:77
#define FOR_RECURSIVE
Definition: cmd.h:237
BOOL bEnableExtensions
Definition: cmd.c:161
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
#define STANDARD_SEPS
Definition: cmd.h:346
#define cmd_alloc(size)
Definition: cmddbg.h:29
#define cmd_dup(str)
Definition: cmddbg.h:32
static int InsideBlock
Definition: parser.c:75
static TCHAR TempBuf[CMDLINE_LENGTH]
Definition: parser.c:65
Definition: cmd.h:348
#define memset(x, y, z)
Definition: compat.h:39
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParseCommandPart().

◆ ParseIf()

static PARSED_COMMAND* ParseIf ( void  )
static

Definition at line 385 of file parser.c.

386 {
388 
389  Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
390  if (!Cmd)
391  {
392  WARN("Cannot allocate memory for Cmd!\n");
393  ParseError();
394  return NULL;
395  }
396  memset(Cmd, 0, sizeof(PARSED_COMMAND));
397  Cmd->Type = C_IF;
398 
399  if (bEnableExtensions && (_tcsicmp(CurrentToken, _T("/I")) == 0))
400  {
401  Cmd->If.Flags |= IFFLAG_IGNORECASE;
403  }
404  if (_tcsicmp(CurrentToken, _T("not")) == 0)
405  {
406  Cmd->If.Flags |= IFFLAG_NEGATE;
408  }
409 
411  goto error;
412 
413  /* Check for unary operators */
414  for (; Cmd->If.Operator <= IF_MAX_UNARY; Cmd->If.Operator++)
415  {
416  /* Skip the extended operators if the extensions are disabled */
417  if (!bEnableExtensions && (Cmd->If.Operator >= IF_CMDEXTVERSION))
418  continue;
419 
420  if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
421  {
423  goto error;
424  Cmd->If.RightArg = cmd_dup(CurrentToken);
425  goto condition_done;
426  }
427  }
428 
429  /* It must be a two-argument (comparison) operator. It could be ==, so
430  * the equals sign can't be treated as whitespace here. */
431  Cmd->If.LeftArg = cmd_dup(CurrentToken);
432  ParseToken(0, _T(",;"));
433 
434  /* The right argument can come immediately after == */
435  if (_tcsnicmp(CurrentToken, _T("=="), 2) == 0 && CurrentToken[2])
436  {
437  Cmd->If.RightArg = cmd_dup(&CurrentToken[2]);
438  goto condition_done;
439  }
440 
441  // Cmd->If.Operator == IF_MAX_UNARY + 1;
442  for (; Cmd->If.Operator <= IF_MAX_COMPARISON; Cmd->If.Operator++)
443  {
444  /* Skip the extended operators if the extensions are disabled */
445  if (!bEnableExtensions && (Cmd->If.Operator >= IF_EQU)) // (Cmd->If.Operator > IF_STRINGEQ)
446  continue;
447 
448  if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
449  {
451  goto error;
452  Cmd->If.RightArg = cmd_dup(CurrentToken);
453  goto condition_done;
454  }
455  }
456  goto error;
457 
458 condition_done:
459  Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
460  if (Cmd->Subcommands == NULL)
461  goto error;
462  if (_tcsicmp(CurrentToken, _T("else")) == 0)
463  {
464  Cmd->Subcommands->Next = ParseCommandOp(C_OP_LOWEST);
465  if (Cmd->Subcommands->Next == NULL)
466  goto error;
467  }
468 
469  return Cmd;
470 
471 error:
472  FreeCommand(Cmd);
473  ParseError();
474  return NULL;
475 }
static int CurrentTokenType
Definition: parser.c:74
#define _tcsicmp
Definition: xmlstorage.h:205
#define IFFLAG_IGNORECASE
Definition: cmd.h:261
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
#define IF_MAX_UNARY
#define WARN(fmt,...)
Definition: debug.h:112
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1420
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
#define C_OP_LOWEST
Definition: parser.c:19
#define _tcsnicmp
Definition: xmlstorage.h:207
smooth NULL
Definition: ftsmooth.c:416
#define _T(x)
Definition: vfdio.h:22
#define IFFLAG_NEGATE
Definition: cmd.h:260
DWORD error
Definition: parser.c:105
Definition: cmd.h:273
static const TCHAR *const IfOperatorString[]
Definition: parser.c:25
BOOL bEnableExtensions
Definition: cmd.c:161
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
#define STANDARD_SEPS
Definition: cmd.h:346
#define cmd_alloc(size)
Definition: cmddbg.h:29
Definition: cmd.h:348
#define cmd_dup(str)
Definition: cmddbg.h:32
#define IF_MAX_COMPARISON
#define memset(x, y, z)
Definition: compat.h:39
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParseCommandPart().

◆ ParsePrimary()

static PARSED_COMMAND* ParsePrimary ( void  )
static

Definition at line 692 of file parser.c.

693 {
694  REDIRECTION *RedirList = NULL;
695  int Type;
696 
697  while (IsSeparator(CurChar))
698  {
699  if (CurChar == _T('\n'))
700  return NULL;
701  ParseChar();
702  }
703 
704  if (!CurChar)
705  return NULL;
706 
707  if (CurChar == _T(':'))
708  {
709  /* "Ignore" the rest of the line.
710  * (Line continuations will still be parsed, though.) */
711  while (ParseToken(0, NULL) != TOK_END)
712  ;
713  return NULL;
714  }
715 
716  if (CurChar == _T('@'))
717  {
719  ParseChar();
720  Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
721  if (!Cmd)
722  {
723  WARN("Cannot allocate memory for Cmd!\n");
724  ParseError();
725  return NULL;
726  }
727  Cmd->Type = C_QUIET;
728  Cmd->Next = NULL;
729  /* @ acts like a unary operator with low precedence,
730  * so call the top-level parser */
731  Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
732  Cmd->Redirections = NULL;
733  return Cmd;
734  }
735 
736  /* Process leading redirections and get the head of the command */
737  while ((Type = ParseToken(_T('('), STANDARD_SEPS)) == TOK_REDIRECTION)
738  {
739  if (!ParseRedirection(&RedirList))
740  return NULL;
741  }
742 
743  if (Type == TOK_NORMAL)
744  return ParseCommandPart(RedirList);
745  else if (Type == TOK_BEGIN_BLOCK)
746  return ParseBlock(RedirList);
747  else if (Type == TOK_END_BLOCK && !RedirList)
748  return NULL;
749 
750  ParseError();
751  FreeRedirection(RedirList);
752  return NULL;
753 }
static DECLSPEC_NOINLINE PARSED_COMMAND * ParseCommandPart(REDIRECTION *RedirList)
Definition: parser.c:620
Definition: parser.c:56
Type
Definition: Type.h:6
#define WARN(fmt,...)
Definition: debug.h:112
static PARSED_COMMAND * ParseBlock(REDIRECTION *RedirList)
Definition: parser.c:329
Definition: cmd.h:348
static BOOL IsSeparator(TCHAR Char)
Definition: parser.c:49
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
#define C_OP_LOWEST
Definition: parser.c:19
static BOOL ParseRedirection(REDIRECTION **List)
Definition: parser.c:257
smooth NULL
Definition: ftsmooth.c:416
#define _T(x)
Definition: vfdio.h:22
static TCHAR ParseChar(void)
Definition: parser.c:77
Definition: sacdrv.h:277
static PARSED_COMMAND * ParseCommandOp(int OpType)
Definition: parser.c:755
#define STANDARD_SEPS
Definition: cmd.h:346
#define cmd_alloc(size)
Definition: cmddbg.h:29
static TCHAR CurChar
Definition: parser.c:71
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParseCommandOp().

◆ ParseRedirection()

static BOOL ParseRedirection ( REDIRECTION **  List)
static

Definition at line 257 of file parser.c.

258 {
259  TCHAR *Tok = CurrentToken;
260  BYTE Number;
261  REDIR_MODE RedirMode;
262  REDIRECTION *Redir;
263 
264  if (*Tok >= _T('0') && *Tok <= _T('9'))
265  Number = *Tok++ - _T('0');
266  else
267  Number = *Tok == _T('<') ? 0 : 1;
268 
269  if (*Tok++ == _T('<'))
270  {
271  RedirMode = REDIR_READ;
272  if (*Tok == _T('<'))
273  goto fail;
274  }
275  else
276  {
277  RedirMode = REDIR_WRITE;
278  if (*Tok == _T('>'))
279  {
280  RedirMode = REDIR_APPEND;
281  Tok++;
282  }
283  }
284 
285  if (!*Tok)
286  {
287  /* The file name was not part of this token, so it'll be the next one */
289  goto fail;
290  Tok = CurrentToken;
291  }
292 
293  /* If a redirection for this handle number already exists, delete it */
294  while ((Redir = *List))
295  {
296  if (Redir->Number == Number)
297  {
298  *List = Redir->Next;
299  cmd_free(Redir);
300  continue;
301  }
302  List = &Redir->Next;
303  }
304 
305  Redir = cmd_alloc(FIELD_OFFSET(REDIRECTION, Filename[_tcslen(Tok) + 1]));
306  if (!Redir)
307  {
308  WARN("Cannot allocate memory for Redir!\n");
309  goto fail;
310  }
311  Redir->Next = NULL;
313  Redir->Number = Number;
314  Redir->Mode = RedirMode;
315  _tcscpy(Redir->Filename, Tok);
316  *List = Redir;
317  return TRUE;
318 
319 fail:
320  ParseError();
322  *List = NULL;
323  return FALSE;
324 }
enum _REDIR_MODE REDIR_MODE
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
#define TRUE
Definition: types.h:120
#define WARN(fmt,...)
Definition: debug.h:112
#define INVALID_HANDLE_VALUE
Definition: compat.h:479
_TCHAR * _tcscpy(_TCHAR *to, const _TCHAR *from)
Definition: tcscpy.h:8
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
IN PVCB IN PBCB OUT PDIRENT IN USHORT IN POEM_STRING Filename
Definition: fatprocs.h:934
REDIR_MODE Mode
Definition: cmd.h:412
HANDLE OldHandle
Definition: cmd.h:410
#define FALSE
Definition: types.h:117
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416
BYTE Number
Definition: cmd.h:411
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
LIST_ENTRY List
Definition: psmgr.c:57
TCHAR Filename[]
Definition: cmd.h:413
#define STANDARD_SEPS
Definition: cmd.h:346
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
unsigned char BYTE
Definition: xxhash.c:193
#define cmd_alloc(size)
Definition: cmddbg.h:29
#define cmd_free(ptr)
Definition: cmddbg.h:31
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
struct _REDIRECTION * Next
Definition: cmd.h:409
static __inline VOID ParseError(VOID)
Definition: parser.c:123

Referenced by ParseBlock(), ParseCommandPart(), and ParsePrimary().

◆ ParseRem()

static PARSED_COMMAND* ParseRem ( void  )
static

Definition at line 611 of file parser.c.

612 {
613  /* "Ignore" the rest of the line.
614  * (Line continuations will still be parsed, though.) */
615  while (ParseToken(0, NULL) != TOK_END)
616  ;
617  return NULL;
618 }
Definition: parser.c:56
static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
Definition: parser.c:132
smooth NULL
Definition: ftsmooth.c:416

Referenced by ParseCommandPart().

◆ ParseToken()

static int ParseToken ( TCHAR  ExtraEnd,
TCHAR Separators 
)
static

Definition at line 132 of file parser.c.

133 {
135  TCHAR Char;
136  int Type;
137  BOOL bInQuote = FALSE;
138 
139  for (Char = CurChar; Char && Char != _T('\n'); Char = ParseChar())
140  {
141  bInQuote ^= (Char == _T('"'));
142  if (!bInQuote)
143  {
144  if (Separators != NULL)
145  {
146  if (_istspace(Char) || _tcschr(Separators, Char))
147  {
148  /* Skip leading separators */
149  if (Out == CurrentToken)
150  continue;
151  break;
152  }
153  }
154 
155  /* Check for numbered redirection */
156  if ((Char >= _T('0') && Char <= _T('9') &&
157  (ParsePos == &ParseLine[1] || IsSeparator(ParsePos[-2]))
158  && (*ParsePos == _T('<') || *ParsePos == _T('>'))))
159  {
160  break;
161  }
162 
163  if (Char == ExtraEnd)
164  break;
165  if (InsideBlock && Char == _T(')'))
166  break;
167  if (_tcschr(_T("&|<>"), Char))
168  break;
169 
170  if (Char == _T('^'))
171  {
172  Char = ParseChar();
173  /* Eat up a \n, allowing line continuation */
174  if (Char == _T('\n'))
175  Char = ParseChar();
176  /* Next character is a forced literal */
177  }
178  }
179  if (Out == &CurrentToken[CMDLINE_LENGTH - 1])
180  break;
181  *Out++ = Char;
182  }
183 
184  /* Check if we got at least one character before reaching a special one.
185  * If so, return them and leave the special for the next call. */
186  if (Out != CurrentToken)
187  {
188  Type = TOK_NORMAL;
189  }
190  else if (Char == _T('('))
191  {
193  *Out++ = Char;
194  ParseChar();
195  }
196  else if (Char == _T(')'))
197  {
199  *Out++ = Char;
200  ParseChar();
201  }
202  else if (Char == _T('&') || Char == _T('|'))
203  {
204  Type = TOK_OPERATOR;
205  *Out++ = Char;
206  Char = ParseChar();
207  /* check for && or || */
208  if (Char == Out[-1])
209  {
210  *Out++ = Char;
211  ParseChar();
212  }
213  }
214  else if ((Char >= _T('0') && Char <= _T('9'))
215  || (Char == _T('<') || Char == _T('>')))
216  {
218  if (Char >= _T('0') && Char <= _T('9'))
219  {
220  *Out++ = Char;
221  Char = ParseChar();
222  }
223  *Out++ = Char;
224  Char = ParseChar();
225  if (Char == Out[-1])
226  {
227  /* Strangely, the tokenizer allows << as well as >>... (it
228  * will cause an error when trying to parse it though) */
229  *Out++ = Char;
230  Char = ParseChar();
231  }
232  if (Char == _T('&'))
233  {
234  *Out++ = Char;
235  while (IsSeparator(Char = ParseChar()))
236  ;
237  if (Char >= _T('0') && Char <= _T('9'))
238  {
239  *Out++ = Char;
240  ParseChar();
241  }
242  }
243  }
244  else
245  {
246  Type = TOK_END;
247  }
248  *Out = _T('\0');
249 
250  /* Debugging support */
251  if (fDumpTokens)
252  ConOutPrintf(_T("ParseToken: (%d) '%s'\n"), Type, CurrentToken);
253 
254  return (CurrentTokenType = Type);
255 }
static int CurrentTokenType
Definition: parser.c:74
Definition: parser.c:56
Type
Definition: Type.h:6
static TCHAR CurrentToken[CMDLINE_LENGTH]
Definition: parser.c:73
#define CMDLINE_LENGTH
Definition: help.h:12
#define ConOutPrintf(szStr,...)
Definition: console.h:42
static BOOL IsSeparator(TCHAR Char)
Definition: parser.c:49
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
smooth NULL
Definition: ftsmooth.c:416
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
TCHAR ParseLine[CMDLINE_LENGTH]
Definition: parser.c:69
static TCHAR * ParsePos
Definition: parser.c:70
static TCHAR ParseChar(void)
Definition: parser.c:77
static TCHAR CurChar
Definition: parser.c:71
BOOLEAN fDumpTokens
Definition: parser.c:16
static int InsideBlock
Definition: parser.c:75
#define _istspace
Definition: tchar.h:1504

Referenced by ParseBlock(), ParseCommandPart(), ParseFor(), ParseIf(), ParsePrimary(), ParseRedirection(), and ParseRem().

◆ Unparse()

TCHAR* Unparse ( PARSED_COMMAND Cmd,
TCHAR Out,
TCHAR OutEnd 
)

Definition at line 1294 of file parser.c.

1295 {
1296  PARSED_COMMAND *Sub;
1297  REDIRECTION *Redir;
1298 
1299 /*
1300  * Since this function has the annoying requirement that it must avoid
1301  * overflowing the supplied buffer, define some helper macros to make
1302  * this less painful.
1303  */
1304 #define CHAR(Char) \
1305 do { \
1306  if (Out == OutEnd) return NULL; \
1307  *Out++ = Char; \
1308 } while (0)
1309 #define STRING(String) \
1310 do { \
1311  if (Out + _tcslen(String) > OutEnd) return NULL; \
1312  Out = _stpcpy(Out, String); \
1313 } while (0)
1314 #define PRINTF(Format, ...) \
1315 do { \
1316  UINT Len = _sntprintf(Out, OutEnd - Out, Format, __VA_ARGS__); \
1317  if (Len > (UINT)(OutEnd - Out)) return NULL; \
1318  Out += Len; \
1319 } while (0)
1320 #define RECURSE(Subcommand) \
1321 do { \
1322  Out = Unparse(Subcommand, Out, OutEnd); \
1323  if (!Out) return NULL; \
1324 } while (0)
1325 
1326  switch (Cmd->Type)
1327  {
1328  case C_COMMAND:
1329  /* This is fragile since there could be special characters, but
1330  * Windows doesn't bother escaping them, so for compatibility
1331  * we probably shouldn't do it either */
1332  if (!SubstituteForVars(Cmd->Command.First, TempBuf)) return NULL;
1333  STRING(TempBuf);
1334  if (!SubstituteForVars(Cmd->Command.Rest, TempBuf)) return NULL;
1335  STRING(TempBuf);
1336  break;
1337 
1338  case C_QUIET:
1339  CHAR(_T('@'));
1340  RECURSE(Cmd->Subcommands);
1341  break;
1342 
1343  case C_BLOCK:
1344  CHAR(_T('('));
1345  for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next)
1346  {
1347  RECURSE(Sub);
1348  if (Sub->Next)
1349  CHAR(_T('&'));
1350  }
1351  CHAR(_T(')'));
1352  break;
1353 
1354  case C_MULTI:
1355  case C_OR:
1356  case C_AND:
1357  case C_PIPE:
1358  Sub = Cmd->Subcommands;
1359  RECURSE(Sub);
1360  PRINTF(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
1361  RECURSE(Sub->Next);
1362  break;
1363 
1364  case C_IF:
1365  STRING(_T("if"));
1366  if (Cmd->If.Flags & IFFLAG_IGNORECASE)
1367  STRING(_T(" /I"));
1368  if (Cmd->If.Flags & IFFLAG_NEGATE)
1369  STRING(_T(" not"));
1370  if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, TempBuf))
1371  PRINTF(_T(" %s"), TempBuf);
1372  PRINTF(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
1373  if (!SubstituteForVars(Cmd->If.RightArg, TempBuf)) return NULL;
1374  PRINTF(_T(" %s "), TempBuf);
1375  Sub = Cmd->Subcommands;
1376  RECURSE(Sub);
1377  if (Sub->Next)
1378  {
1379  STRING(_T(" else "));
1380  RECURSE(Sub->Next);
1381  }
1382  break;
1383 
1384  case C_FOR:
1385  STRING(_T("for"));
1386  if (Cmd->For.Switches & FOR_DIRS) STRING(_T(" /D"));
1387  if (Cmd->For.Switches & FOR_F) STRING(_T(" /F"));
1388  if (Cmd->For.Switches & FOR_LOOP) STRING(_T(" /L"));
1389  if (Cmd->For.Switches & FOR_RECURSIVE) STRING(_T(" /R"));
1390  if (Cmd->For.Params)
1391  PRINTF(_T(" %s"), Cmd->For.Params);
1392  if (Cmd->For.List && SubstituteForVars(Cmd->For.List, TempBuf))
1393  PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, TempBuf);
1394  else
1395  PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
1396  RECURSE(Cmd->Subcommands);
1397  break;
1398 
1399  default:
1400  ASSERT(FALSE);
1401  break;
1402  }
1403 
1404  for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
1405  {
1406  if (!SubstituteForVars(Redir->Filename, TempBuf))
1407  return NULL;
1408  PRINTF(_T(" %c%s%s"), _T('0') + Redir->Number,
1409  RedirString[Redir->Mode], TempBuf);
1410  }
1411  return Out;
1412 
1413 #undef CHAR
1414 #undef STRING
1415 #undef PRINTF
1416 #undef RECURSE
1417 }
#define FOR_DIRS
Definition: cmd.h:234
#define RECURSE(Subcommand)
#define IFFLAG_IGNORECASE
Definition: cmd.h:261
Definition: cmd.h:348
#define FOR_F
Definition: cmd.h:235
struct _PARSED_COMMAND * Next
Definition: cmd.h:352
#define C_OP_LOWEST
Definition: parser.c:19
REDIR_MODE Mode
Definition: cmd.h:412
Definition: cmd.h:348
#define PRINTF(Format,...)
#define FALSE
Definition: types.h:117
#define FOR_LOOP
Definition: cmd.h:236
smooth NULL
Definition: ftsmooth.c:416
Definition: cmd.h:348
BYTE Number
Definition: cmd.h:411
#define _T(x)
Definition: vfdio.h:22
BOOL SubstituteForVars(IN PCTSTR Src, OUT PTSTR Dest)
Definition: cmd.c:1593
Definition: cmd.h:348
Definition: cmd.h:348
#define IFFLAG_NEGATE
Definition: cmd.h:260
TCHAR Filename[]
Definition: cmd.h:413
static const TCHAR *const IfOperatorString[]
Definition: parser.c:25
#define STRING(String)
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define FOR_RECURSIVE
Definition: cmd.h:237
static const TCHAR RedirString[][3]
Definition: parser.c:23
Definition: sacdrv.h:277
Definition: cmd.h:348
Definition: cmd.h:348
static const TCHAR OpString[][3]
Definition: parser.c:21
struct _REDIRECTION * Next
Definition: cmd.h:409
Definition: cmd.h:348
static TCHAR TempBuf[CMDLINE_LENGTH]
Definition: parser.c:65
Definition: cmd.h:348
#define CHAR(Char)

Referenced by ExecuteAsync().

Variable Documentation

◆ bLineContinuations

BOOL bLineContinuations
static

Definition at line 68 of file parser.c.

Referenced by ParseChar(), and ParseCommand().

◆ bParseError

◆ CurChar

◆ CurrentToken

TCHAR CurrentToken[CMDLINE_LENGTH]
static

◆ CurrentTokenType

int CurrentTokenType
static

◆ fDumpParse

BOOLEAN fDumpParse = FALSE

Definition at line 17 of file parser.c.

Referenced by ParseCommand().

◆ fDumpTokens

BOOLEAN fDumpTokens = FALSE

Definition at line 16 of file parser.c.

Referenced by ParseToken().

◆ IfOperatorString

const TCHAR* const IfOperatorString[]
static
Initial value:
=
{
_T("errorlevel"),
_T("exist"),
_T("cmdextversion"),
_T("defined"),
#define IF_MAX_UNARY
_T("=="),
_T("equ"),
_T("neq"),
_T("lss"),
_T("leq"),
_T("gtr"),
_T("geq"),
#define IF_MAX_COMPARISON
}
#define _T(x)
Definition: vfdio.h:22

Definition at line 25 of file parser.c.

Referenced by DumpCommand(), EchoCommand(), ParseIf(), and Unparse().

◆ InsideBlock

int InsideBlock
static

Definition at line 75 of file parser.c.

Referenced by ParseBlock(), ParseFor(), and ParseToken().

◆ OpString

const TCHAR OpString[][3] = { _T("&"), _T("||"), _T("&&"), _T("|") }
static

Definition at line 21 of file parser.c.

Referenced by DumpCommand(), EchoCommand(), ParseCommandOp(), and Unparse().

◆ ParseLine

TCHAR ParseLine[CMDLINE_LENGTH]

Definition at line 69 of file parser.c.

Referenced by Batch(), ParseChar(), ParseCommand(), and ParseToken().

◆ ParsePos

TCHAR* ParsePos
static

Definition at line 70 of file parser.c.

Referenced by ParseChar(), ParseCommand(), and ParseToken().

◆ RedirString

const TCHAR RedirString[][3] = { _T("<"), _T(">"), _T(">>") }
static

Definition at line 23 of file parser.c.

Referenced by DumpRedir(), EchoCommand(), and Unparse().

◆ TempBuf

TCHAR TempBuf[CMDLINE_LENGTH]
static

Definition at line 65 of file parser.c.

Referenced by EchoCommand(), ParseFor(), and Unparse().