[12/16] CMD.exe: Unify parsing of batch command and command line
Ann & Jason Edmeades
us at edmeades.me.uk
Mon Feb 19 18:43:42 CST 2007
The two routines were almost identical and one calls the other - the
differences can be accounted for when a context (ie in batch pgm) is
present, and revolve mostly around removing env vars which aren't found and
putting out the prompt if echo is on
-------------- next part --------------
>From nobody Mon Sep 17 00:00:00 2001
From: Jason Edmeades <us at edmeades.me.uk>
Date: Mon Feb 19 18:13:39 2007 +0000
Subject: [PATCH] Unify the parsing of parameters
Previously, cmd had 2 places where env vars were expanded, and this
means duplicating all the code for the special env vars, plus anything
should the %var:xxx% syntax is added. This patch unifys it into a
single routine, handling the difference between the routines depending
on whether a context is present (command line vs batch pgm).
---
programs/cmd/batch.c | 135 -----------------------------------------------
programs/cmd/wcmd.h | 6 ++
programs/cmd/wcmdmain.c | 134 +++++++++++++++++++++++++++++++++++++++++------
3 files changed, 126 insertions(+), 149 deletions(-)
189a91f1c867684c7996006f505c62e79ec9265d
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c
index cdc0e63..b4d3382 100755
--- a/programs/cmd/batch.c
+++ b/programs/cmd/batch.c
@@ -20,17 +20,11 @@
#include "wcmd.h"
-void WCMD_batch_command (char *line);
-void WCMD_HandleTildaModifiers(char **start, char *forVariable);
-
extern int echo_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
extern BATCH_CONTEXT *context;
extern DWORD errorlevel;
-/* msdn specified max for Win XP */
-#define MAXSTRING 8192
-
/****************************************************************************
* WCMD_batch
*
@@ -117,7 +111,7 @@ BATCH_CONTEXT *prev_context;
WCMD_output_asis( "\n");
}
if (string[0] != ':') { /* Skip over labels */
- WCMD_batch_command (string);
+ WCMD_process_command (string);
}
}
CloseHandle (h);
@@ -138,133 +132,6 @@ BATCH_CONTEXT *prev_context;
}
}
-/****************************************************************************
- * WCMD_batch_command
- *
- * Execute one line from a batch file, expanding parameters.
- */
-
-void WCMD_batch_command (char *line) {
-
-DWORD status;
-char cmd1[MAXSTRING],cmd2[MAXSTRING];
-char *p, *s, *t;
-int i;
-
- /* Get working version of command line */
- strcpy(cmd1, line);
-
- /* Expand environment variables in a batch file %{0-9} first */
- /* Then env vars, and if any left (ie use of undefined vars,*/
- /* replace with spaces */
- /* FIXME: Winnt would replace %1%fred%1 with first parm, then */
- /* contents of fred, then the digit 1. Would need to remove */
- /* ExpandEnvStrings to achieve this */
-
- /* Replace use of %0...%9 and errorlevel*/
- p = cmd1;
- while ((p = strchr(p, '%'))) {
- i = *(p+1) - '0';
- if (*(p+1) == '~') {
- WCMD_HandleTildaModifiers(&p, NULL);
- p++;
- } else if ((i >= 0) && (i <= 9)) {
- s = strdup (p+2);
- t = WCMD_parameter (context -> command, i + context -> shift_count, NULL);
- strcpy (p, t);
- strcat (p, s);
- free (s);
- } else if (*(p+1)=='*') {
- char *startOfParms = NULL;
- s = strdup (p+2);
- t = WCMD_parameter (context -> command, 1, &startOfParms);
- if (startOfParms != NULL) strcpy (p, startOfParms);
- else *p = 0x00;
- strcat (p, s);
- free (s);
-
- /* Handle DATE, TIME, ERRORLEVEL and CD replacements allowing */
- /* override if existing env var called that name */
- } else if ((CompareString (LOCALE_USER_DEFAULT,
- NORM_IGNORECASE | SORT_STRINGSORT,
- (p+1), 11, "ERRORLEVEL%", -1) == 2) &&
- (GetEnvironmentVariable("ERRORLEVEL", cmd2, 1) == 0) &&
- (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
- char output[10];
- sprintf(output, "%d", errorlevel);
- s = strdup (p+12);
- strcpy (p, output);
- strcat (p, s);
-
- } else if ((CompareString (LOCALE_USER_DEFAULT,
- NORM_IGNORECASE | SORT_STRINGSORT,
- (p+1), 5, "DATE%", -1) == 2) &&
- (GetEnvironmentVariable("DATE", cmd2, 1) == 0) &&
- (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
-
- GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL,
- NULL, cmd2, MAXSTRING);
- s = strdup (p+6);
- strcpy (p, cmd2);
- strcat (p, s);
-
- } else if ((CompareString (LOCALE_USER_DEFAULT,
- NORM_IGNORECASE | SORT_STRINGSORT,
- (p+1), 5, "TIME%", -1) == 2) &&
- (GetEnvironmentVariable("TIME", cmd2, 1) == 0) &&
- (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
- GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL,
- NULL, cmd2, MAXSTRING);
- s = strdup (p+6);
- strcpy (p, cmd2);
- strcat (p, s);
-
- } else if ((CompareString (LOCALE_USER_DEFAULT,
- NORM_IGNORECASE | SORT_STRINGSORT,
- (p+1), 3, "CD%", -1) == 2) &&
- (GetEnvironmentVariable("CD", cmd2, 1) == 0) &&
- (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
- GetCurrentDirectory (MAXSTRING, cmd2);
- s = strdup (p+4);
- strcpy (p, cmd2);
- strcat (p, s);
-
- } else {
- p++;
- }
- }
-
- /* Now replace environment variables */
- status = ExpandEnvironmentStrings(cmd1, cmd2, sizeof(cmd2));
- if (!status) {
- WCMD_print_error ();
- return;
- }
-
- /* In a batch program, unknown variables are replace by nothing */
- /* so remove any remaining %var% */
- p = cmd2;
- while ((p = strchr(p, '%'))) {
- s = strchr(p+1, '%');
- if (!s) {
- *p=0x00;
- } else {
- t = strdup(s+1);
- strcpy(p, t);
- free(t);
- }
- }
-
- /* Show prompt before batch line IF echo is on */
- if (echo_mode && (line[0] != '@')) {
- WCMD_show_prompt();
- WCMD_output_asis ( cmd2);
- WCMD_output_asis ( "\n");
- }
-
- WCMD_process_command (cmd2);
-}
-
/*******************************************************************
* WCMD_parameter - extract a parameter from a command line.
*
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index cd2ea75..a5089f2 100755
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -77,6 +77,8 @@ char *WCMD_parameter (char *s, int n, ch
char *WCMD_strtrim_leading_spaces (char *string);
void WCMD_strtrim_trailing_spaces (char *string);
void WCMD_opt_s_strip_quotes(char *cmd);
+void WCMD_HandleTildaModifiers(char **start, char *forVariable);
+
/* Data structure to hold context when executing batch files */
@@ -147,3 +149,7 @@ extern const char nyi[];
extern const char newline[];
extern const char version_string[];
extern const char anykey[];
+
+/* msdn specified max for Win XP */
+#define MAXSTRING 8192
+
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 3c3a154..9ffc65d 100755
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -256,7 +256,6 @@ int main (int argc, char *argv[])
HeapFree(GetProcessHeap(), 0, cmd);
}
-#if 0
/*
* If there is an AUTOEXEC.BAT file, try to execute it.
*/
@@ -265,6 +264,7 @@ #if 0
h = CreateFile (string, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle (h);
+#if 0
WCMD_batch ((char *)"\\autoexec.bat", (char *)"\\autoexec.bat", 0, NULL, INVALID_HANDLE_VALUE);
#endif
}
@@ -301,27 +301,104 @@ #endif
void WCMD_process_command (char *command)
{
- char *cmd, *p, *s;
+ char *cmd, *p, *s, *t;
+ char temp[MAXSTRING];
int status, i, len;
DWORD count, creationDisposition;
HANDLE h;
char *whichcmd;
SECURITY_ATTRIBUTES sa;
-
-/*
- * Replace errorlevel with current value (This shrinks in
- * place and hence no need to reallocate the memory yet)
- */
- p = command;
+ char *new_cmd;
+
+ /* Move copy of the command onto the heap so it can be expanded */
+ new_cmd = HeapAlloc( GetProcessHeap(), 0, MAXSTRING );
+ strcpy(new_cmd, command);
+
+ /* For commands in a context (batch program): */
+ /* Expand environment variables in a batch file %{0-9} first */
+ /* including support for any ~ modifiers */
+ /* Additionally: */
+ /* Expand the DATE, TIME, CD and ERRORLEVEL special names */
+ /* allowing environment variable overrides */
+
+ /* FIXME: Winnt would replace %1%fred%1 with first parm, then */
+ /* contents of fred, then the digit 1. Would need to remove */
+ /* ExpandEnvStrings to achieve this */
+ /* NOTE: To support the %PATH:xxx% syntax, also need to do */
+ /* manual expansion of environment variables here */
+
+ p = new_cmd;
while ((p = strchr(p, '%'))) {
- if (CompareString (LOCALE_USER_DEFAULT,
+ i = *(p+1) - '0';
+
+ /* Replace %~ modifications if in batch program */
+ if (context && *(p+1) == '~') {
+ WCMD_HandleTildaModifiers(&p, NULL);
+ p++;
+
+ /* Replace use of %0...%9 if in batch program*/
+ } else if (context && (i >= 0) && (i <= 9)) {
+ s = strdup (p+2);
+ t = WCMD_parameter (context -> command, i + context -> shift_count, NULL);
+ strcpy (p, t);
+ strcat (p, s);
+ free (s);
+
+ /* Replace use of %* if in batch program*/
+ } else if (context && *(p+1)=='*') {
+ char *startOfParms = NULL;
+ s = strdup (p+2);
+ t = WCMD_parameter (context -> command, 1, &startOfParms);
+ if (startOfParms != NULL) strcpy (p, startOfParms);
+ else *p = 0x00;
+ strcat (p, s);
+ free (s);
+
+ /* Handle DATE, TIME, ERRORLEVEL and CD replacements allowing */
+ /* override if existing env var called that name */
+ } else if ((CompareString (LOCALE_USER_DEFAULT,
NORM_IGNORECASE | SORT_STRINGSORT,
- (p+1), 11, "ERRORLEVEL%", -1) == 2) {
- char output[10];
- sprintf(output, "%d", errorlevel);
+ (p+1), 11, "ERRORLEVEL%", -1) == 2) &&
+ (GetEnvironmentVariable("ERRORLEVEL", temp, 1) == 0) &&
+ (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
+ sprintf(temp, "%d", errorlevel);
s = strdup (p+12);
- strcpy (p, output);
+ strcpy (p, temp);
+ strcat (p, s);
+
+ } else if ((CompareString (LOCALE_USER_DEFAULT,
+ NORM_IGNORECASE | SORT_STRINGSORT,
+ (p+1), 5, "DATE%", -1) == 2) &&
+ (GetEnvironmentVariable("DATE", temp, 1) == 0) &&
+ (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
+
+ GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL,
+ NULL, temp, MAXSTRING);
+ s = strdup (p+6);
+ strcpy (p, temp);
+ strcat (p, s);
+
+ } else if ((CompareString (LOCALE_USER_DEFAULT,
+ NORM_IGNORECASE | SORT_STRINGSORT,
+ (p+1), 5, "TIME%", -1) == 2) &&
+ (GetEnvironmentVariable("TIME", temp, 1) == 0) &&
+ (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL,
+ NULL, temp, MAXSTRING);
+ s = strdup (p+6);
+ strcpy (p, temp);
strcat (p, s);
+
+ } else if ((CompareString (LOCALE_USER_DEFAULT,
+ NORM_IGNORECASE | SORT_STRINGSORT,
+ (p+1), 3, "CD%", -1) == 2) &&
+ (GetEnvironmentVariable("CD", temp, 1) == 0) &&
+ (GetLastError() == ERROR_ENVVAR_NOT_FOUND)) {
+ GetCurrentDirectory (MAXSTRING, temp);
+ s = strdup (p+4);
+ strcpy (p, temp);
+ strcat (p, s);
+
} else {
p++;
}
@@ -329,14 +406,41 @@ void WCMD_process_command (char *command
/*
* Expand up environment variables.
+ * FIXME: Move this to above, without reallocating
*/
- len = ExpandEnvironmentStrings (command, NULL, 0);
+ len = ExpandEnvironmentStrings (new_cmd, NULL, 0);
cmd = HeapAlloc( GetProcessHeap(), 0, len );
- status = ExpandEnvironmentStrings (command, cmd, len);
+ status = ExpandEnvironmentStrings (new_cmd, cmd, len);
if (!status) {
WCMD_print_error ();
HeapFree( GetProcessHeap(), 0, cmd );
+ HeapFree( GetProcessHeap(), 0, new_cmd );
return;
+ } else {
+ HeapFree( GetProcessHeap(), 0, new_cmd );
+ }
+
+ /* In a batch program, unknown variables are replace by nothing */
+ /* so remove any remaining %var% */
+ if (context) {
+ p = cmd;
+ while ((p = strchr(p, '%'))) {
+ s = strchr(p+1, '%');
+ if (!s) {
+ *p=0x00;
+ } else {
+ t = strdup(s+1);
+ strcpy(p, t);
+ free(t);
+ }
+ }
+
+ /* Show prompt before batch line IF echo is on and in batch program */
+ if (echo_mode && (cmd[0] != '@')) {
+ WCMD_show_prompt();
+ WCMD_output_asis ( cmd);
+ WCMD_output_asis ( "\n");
+ }
}
/*
--
1.3.0
More information about the wine-patches
mailing list