[PATCH 1/2] [cmd] Fix handling of redundant information on goto/labels

Ann and Jason Edmeades jason at edmeades.me.uk
Sun Jun 2 16:56:30 CDT 2013


Handle label and goto commands, ensuring redundant information
left on the line does not affect the processing. Added lots of
tests for edge cases as well.

[Fixes bug 33635]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20130602/8a653ebc/attachment.html>
-------------- next part --------------
From a69789f81ce9f617a1fb805d6fa8531f1544222c Mon Sep 17 00:00:00 2001
From: Jason Edmeades <jason at edmeades.me.uk>
Date: Sun, 2 Jun 2013 00:17:30 +0100
Subject: [PATCH 1/2] [cmd] Fix handling of redundant information on
 goto/labels

Handle label and goto commands, ensuring redundant information
left on the line does not affect the processing. Added lots of
tests for edge cases as well.

[Fixes bug 33635]
---
 programs/cmd/builtins.c                  |   34 ++++++++++++------
 programs/cmd/tests/test_builtins.cmd     |   55 ++++++++++++++++++++++++++++++
 programs/cmd/tests/test_builtins.cmd.exp |    6 ++++
 programs/cmd/wcmdmain.c                  |   22 ++++++------
 4 files changed, 97 insertions(+), 20 deletions(-)

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 1d9fc15..3c06e13 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -2501,7 +2501,8 @@ void WCMD_give_help (const WCHAR *args)
 void WCMD_goto (CMD_LIST **cmdList) {
 
   WCHAR string[MAX_PATH];
-  WCHAR current[MAX_PATH];
+  WCHAR *labelend = NULL;
+  const WCHAR labelEndsW[] = {'>','<','|','&',' ',':','\t','\0'};
 
   /* Do not process any more parts of a processed multipart or multilines command */
   if (cmdList) *cmdList = NULL;
@@ -2521,25 +2522,38 @@ void WCMD_goto (CMD_LIST **cmdList) {
       return;
     }
 
-    /* Support goto :label as well as goto label */
+    /* Support goto :label as well as goto label plus remove trailing chars */
     if (*paramStart == ':') paramStart++;
+    labelend = strpbrkW(paramStart, labelEndsW);
+    if (labelend) *labelend = 0x00;
+    WINE_TRACE("goto label: '%s'\n", wine_dbgstr_w(paramStart));
 
     SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
-    while (WCMD_fgets (string, sizeof(string)/sizeof(WCHAR), context -> h)) {
+    while (*paramStart &&
+           WCMD_fgets (string, sizeof(string)/sizeof(WCHAR), context -> h)) {
       str = string;
-      while (isspaceW (*str)) str++;
+
+      /* Ignore leading whitespace or no-echo character */
+      while (*str=='@' || isspaceW (*str)) str++;
+
+      /* If the first real character is a : then this is a label */
       if (*str == ':') {
-        DWORD index = 0;
         str++;
-        while (((current[index] = str[index])) && (!isspaceW (current[index])))
-            index++;
 
-        /* ignore space at the end */
-        current[index] = 0;
-        if (lstrcmpiW (current, paramStart) == 0) return;
+        /* Skip spaces between : and label */
+        while (isspaceW (*str)) str++;
+        WINE_TRACE("str before brk %s\n", wine_dbgstr_w(str));
+
+        /* Label ends at whitespace or redirection characters */
+        labelend = strpbrkW(str, labelEndsW);
+        if (labelend) *labelend = 0x00;
+        WINE_TRACE("comparing found label %s\n", wine_dbgstr_w(str));
+
+        if (lstrcmpiW (str, paramStart) == 0) return;
       }
     }
     WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOTARGET));
+    context -> skip_rest = TRUE;
   }
   return;
 }
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 54070bc..f3aa1a9 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -2538,17 +2538,72 @@ echo %ErrorLevel% should still be 7
 
 echo ------------ Testing GOTO ------------
 if a==a goto dest1
+echo FAILURE at dest 1
 :dest1
 echo goto with no leading space worked
+if a==a goto :dest1b
+echo FAILURE at dest 1b
+:dest1b
+echo goto with colon and no leading space worked
 if b==b goto dest2
+echo FAILURE at dest 2
  :dest2
 echo goto with a leading space worked
 if c==c goto dest3
+echo FAILURE at dest 3
 	:dest3
 echo goto with a leading tab worked
 if d==d goto dest4
+echo FAILURE at dest 4
 :dest4 at space@
 echo goto with a following space worked
+if e==e goto dest5
+echo FAILURE at dest 5
+:dest5&& echo FAILURE
+echo goto with following amphersands worked
+
+del failure.txt >nul 2>&1
+if f==f goto dest6
+echo FAILURE at dest 6
+:dest6>FAILURE.TXT
+if exist FAILURE.TXT echo FAILURE at dest 6 as file exists
+echo goto with redirections worked
+del FAILURE.TXT >nul 2>&1
+
+:: some text that is ignored | dir >cmd_output | another test
+if exist cmd_output echo FAILURE at dest 6 as file exists
+echo Ignoring double colons worked
+del cmd_output >nul 2>&1
+
+rem goto a label which does not exist issues an error message and
+rem acts the same as goto :EOF, and ensure ::label is never matched
+del testgoto.bat >nul 2>&1
+echo goto :dest7 ^>nul 2^>^&1 >> testgoto.bat
+echo echo FAILURE at dest 7 - Should have not found label and issued an error plus ended the batch>> testgoto.bat
+echo ::dest7>> testgoto.bat
+echo echo FAILURE at dest 7 - Incorrectly went to label >> testgoto.bat
+call testgoto.bat
+del testgoto.bat >nul 2>&1
+
+del testgoto.bat >nul 2>&1
+echo goto ::dest8 ^>nul 2^>^&1 >> testgoto.bat
+echo echo FAILURE at dest 8 - Should have not found label and issued an error plus ended the batch>> testgoto.bat
+echo ::dest8>> testgoto.bat
+echo echo FAILURE at dest 8 - Incorrectly went to label >> testgoto.bat
+call testgoto.bat
+del testgoto.bat >nul 2>&1
+
+if g==g goto dest9
+echo FAILURE at dest 9
+:dest91
+echo FAILURE at dest 91
+@   :     dest9>rubbish
+echo label with mixed whitespace and no echo worked
+
+if h==h goto :dest10:this is ignored
+echo FAILURE at dest 10
+:dest10:this is also ignored
+echo Correctly ignored trailing information
 
 echo ------------ Testing PATH ------------
 set WINE_backup_path=%path%
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index ebfe8cd..dd6ccb5 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -1294,9 +1294,15 @@ errorlevel zero, good at or_broken@errorlevel nonzero, bad
 7 should still be 7
 ------------ Testing GOTO ------------
 goto with no leading space worked
+goto with colon and no leading space worked
 goto with a leading space worked
 goto with a leading tab worked
 goto with a following space worked
+goto with following amphersands worked
+goto with redirections worked
+Ignoring double colons worked
+label with mixed whitespace and no echo worked
+Correctly ignored trailing information
 ------------ Testing PATH ------------
 PATH=original
 PATH=try2
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 95f2995..876bbef 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -1813,7 +1813,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
     static const WCHAR forCmd[] = {'f','o','r'};
     static const WCHAR ifCmd[]  = {'i','f'};
     static const WCHAR ifElse[] = {'e','l','s','e'};
-    BOOL      inRem = FALSE;
+    BOOL      inOneLine = FALSE;
     BOOL      inFor = FALSE;
     BOOL      inIn  = FALSE;
     BOOL      inIf  = FALSE;
@@ -1910,9 +1910,10 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
       if (curStringLen == 0 && curCopyTo == curString) {
         static const WCHAR forDO[] = {'d','o'};
 
-        /* If command starts with 'rem ', ignore any &&, ( etc. */
-        if (WCMD_keyword_ws_found(remCmd, sizeof(remCmd)/sizeof(remCmd[0]), curPos)) {
-          inRem = TRUE;
+        /* If command starts with 'rem ' or identifies a label, ignore any &&, ( etc. */
+        if (WCMD_keyword_ws_found(remCmd, sizeof(remCmd)/sizeof(remCmd[0]), curPos) ||
+            *curPos == ':') {
+          inOneLine = TRUE;
 
         } else if (WCMD_keyword_ws_found(forCmd, sizeof(forCmd)/sizeof(forCmd[0]), curPos)) {
           inFor = TRUE;
@@ -1971,11 +1972,12 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
         }
       }
 
-      /* Nothing 'ends' a REM statement and &&, quotes etc are ineffective,
-         so just use the default processing ie skip character specific
-         matching below                                                    */
-      if (!inRem) thisChar = *curPos;
-      else        thisChar = 'X';  /* Character with no special processing */
+      /* Nothing 'ends' a one line statement (e.g. REM or :labels mean
+         the &&, quotes and redirection etc are ineffective, so just force
+         the use of the default processing by skipping character specific
+         matching below)                                                   */
+      if (!inOneLine) thisChar = *curPos;
+      else            thisChar = 'X';  /* Character with no special processing */
 
       lastWasWhiteSpace = FALSE; /* Will be reset below */
       lastWasCaret = FALSE;
@@ -2225,7 +2227,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
         WCHAR *extraData;
 
         WINE_TRACE("Need to read more data as outstanding brackets or carets\n");
-        inRem = FALSE;
+        inOneLine = FALSE;
         prevDelim = CMD_NONE;
         inQuotes = 0;
         memset(extraSpace, 0x00, (MAXSTRING+1) * sizeof(WCHAR));
-- 
1.7.9.5


More information about the wine-patches mailing list