[PATCH 2/4] [programs\cmd] call and goto finds the next matching label

Jason Edmeades us at edmeades.me.uk
Wed Jul 4 16:08:39 CDT 2018


Fixes bug#42823

A call or a goto will find the next matching label not the first one in the
file. This means it could be later in the file or it could be earlier in the
file, so make goto (which 'call' also uses) first scan from current file
position to the end of the file, and subsequently from the start of the file
to the wrap point.

Signed-off-by: Jason Edmeades <us at edmeades.me.uk>
---
 programs/cmd/builtins.c                  | 67 +++++++++++++++++-------
 programs/cmd/tests/test_builtins.cmd     | 51 ++++++++++++++++++
 programs/cmd/tests/test_builtins.cmd.exp | 13 +++++
 3 files changed, 113 insertions(+), 18 deletions(-)

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 35b68bd45a..3a0981d222 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -2582,30 +2582,61 @@ void WCMD_goto (CMD_LIST **cmdList) {
     if (labelend) *labelend = 0x00;
     WINE_TRACE("goto label: '%s'\n", wine_dbgstr_w(paramStart));
 
-    SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
-    while (*paramStart &&
-           WCMD_fgets (string, sizeof(string)/sizeof(WCHAR), context -> h)) {
-      str = string;
+    /* Loop through potentially twice - once from current file position
+       through to the end, and second time from start to current file
+       position                                                         */
+    if (*paramStart) {
+        int loop;
+        LARGE_INTEGER startli;
+        for (loop=0; loop<2; loop++) {
+            if (loop==0) {
+              /* On first loop, save the file size */
+              startli.QuadPart = 0;
+              startli.u.LowPart = SetFilePointer(context -> h, startli.u.LowPart,
+                                                 &startli.u.HighPart, FILE_CURRENT);
+            } else {
+              /* On second loop, start at the beginning of the file */
+              WINE_TRACE("Label not found, trying from beginning of file\n");
+              if (loop==1) SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
+            }
 
-      /* Ignore leading whitespace or no-echo character */
-      while (*str=='@' || isspaceW (*str)) str++;
+            while (WCMD_fgets (string, sizeof(string)/sizeof(WCHAR), context -> h)) {
+              str = string;
 
-      /* If the first real character is a : then this is a label */
-      if (*str == ':') {
-        str++;
+              /* Ignore leading whitespace or no-echo character */
+              while (*str=='@' || isspaceW (*str)) str++;
 
-        /* Skip spaces between : and label */
-        while (isspaceW (*str)) str++;
-        WINE_TRACE("str before brk %s\n", wine_dbgstr_w(str));
+              /* If the first real character is a : then this is a label */
+              if (*str == ':') {
+                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));
+                /* Skip spaces between : and label */
+                while (isspaceW (*str)) str++;
+                WINE_TRACE("str before brk %s\n", wine_dbgstr_w(str));
 
-        if (lstrcmpiW (str, paramStart) == 0) return;
-      }
+                /* 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;
+              }
+
+              /* See if we have gone beyond the end point if second time through */
+              if (loop==1) {
+                LARGE_INTEGER curli;
+                curli.QuadPart = 0;
+                curli.u.LowPart = SetFilePointer(context -> h, curli.u.LowPart,
+                                                &curli.u.HighPart, FILE_CURRENT);
+                if (curli.QuadPart > startli.QuadPart) {
+                  WINE_TRACE("Reached wrap point, label not found\n");
+                  break;
+                }
+              }
+            }
+        }
     }
+
     WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOTARGET));
     context -> skip_rest = TRUE;
   }
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 49c2d9e1c4..0a8122c5e3 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -3027,6 +3027,57 @@ echo FAILURE at dest 10
 :dest10:this is also ignored
 echo Correctly ignored trailing information
 
+rem Testing which label is reached when there are many options
+echo Begin:
+set nextlabel=
+call :sub
+set nextlabel=middle
+goto :sub
+
+:sub
+echo ..First sub
+if not "%nextlabel%"=="" goto :%nextlabel%
+goto :EOF
+
+:sub
+echo ..Second sub
+if not "%nextlabel%"=="" goto :%nextlabel%
+goto :EOF
+
+:middle
+echo Middle:
+set nextlabel=
+call :sub
+set nextlabel=nearend
+goto :sub
+
+:sub
+echo ..Third sub
+if not "%nextlabel%"=="" goto :%nextlabel%
+goto :EOF
+
+:nearend
+echo Near end:
+set nextlabel=
+call :sub
+set nextlabel=end
+goto :sub
+
+:sub
+echo ..Fourth sub
+if not "%nextlabel%"=="" goto :%nextlabel%
+goto :EOF
+
+:end
+echo At end:
+set nextlabel=
+call :sub
+set nextlabel=done
+goto :sub
+
+:done
+echo Finished
+
 echo ------------ Testing PATH ------------
 set WINE_backup_path=%path%
 set path=original
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index cfde83b063..7f4f724c3b 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -1582,6 +1582,19 @@ goto with redirections worked
 Ignoring double colons worked
 label with mixed whitespace and no echo worked
 Correctly ignored trailing information
+Begin:
+..First sub
+..First sub
+Middle:
+..Third sub
+..Third sub
+Near end:
+..Fourth sub
+..Fourth sub
+At end:
+..First sub
+..First sub
+Finished
 ------------ Testing PATH ------------
 PATH=original
 PATH=try2
-- 
2.17.1




More information about the wine-devel mailing list