Jason Edmeades : cmd.exe: Add support for call :label and goto :label.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Feb 26 07:59:29 CST 2007


Module: wine
Branch: master
Commit: 327d7ef9e60446e7c421cab15baabee610421c9d
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=327d7ef9e60446e7c421cab15baabee610421c9d

Author: Jason Edmeades <us at edmeades.me.uk>
Date:   Fri Feb 23 22:19:25 2007 +0000

cmd.exe: Add support for call :label and goto :label.

---

 programs/cmd/batch.c    |   86 +++++++++++++++++++++++++++++++++++++---------
 programs/cmd/builtins.c |    6 +++-
 programs/cmd/wcmd.h     |    3 +-
 programs/cmd/wcmdmain.c |   12 +++---
 4 files changed, 82 insertions(+), 25 deletions(-)

diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c
index 1a9d9e1..045046c 100644
--- a/programs/cmd/batch.c
+++ b/programs/cmd/batch.c
@@ -42,9 +42,12 @@ extern DWORD errorlevel;
  *
  * We need to handle recursion correctly, since one batch program might call another.
  * So parameters for this batch file are held in a BATCH_CONTEXT structure.
+ *
+ * To support call within the same batch program, another input parameter is
+ * a label to goto once opened.
  */
 
-void WCMD_batch (char *file, char *command, int called) {
+void WCMD_batch (char *file, char *command, int called, char *startLabel, HANDLE pgmHandle) {
 
 #define WCMD_BATCH_EXT_SIZE 5
 
@@ -55,27 +58,33 @@ char extension_exe[WCMD_BATCH_EXT_SIZE] = ".exe";
 unsigned int  i;
 BATCH_CONTEXT *prev_context;
 
-  for(i=0; (i<(sizeof(extension_batch)/WCMD_BATCH_EXT_SIZE)) && 
-           (h == INVALID_HANDLE_VALUE); i++) {
-  strcpy (string, file);
-  CharLower (string);
-    if (strstr (string, extension_batch[i]) == NULL) strcat (string, extension_batch[i]);
-  h = CreateFile (string, GENERIC_READ, FILE_SHARE_READ,
-                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-  }
-  if (h == INVALID_HANDLE_VALUE) {
+  if (startLabel == NULL) {
+    for(i=0; (i<(sizeof(extension_batch)/WCMD_BATCH_EXT_SIZE)) &&
+             (h == INVALID_HANDLE_VALUE); i++) {
     strcpy (string, file);
     CharLower (string);
-    if (strstr (string, extension_exe) == NULL) strcat (string, extension_exe);
+      if (strstr (string, extension_batch[i]) == NULL) strcat (string, extension_batch[i]);
     h = CreateFile (string, GENERIC_READ, FILE_SHARE_READ,
                     NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (h != INVALID_HANDLE_VALUE) {
-      WCMD_run_program (command, 0);
-    } else {
-      SetLastError (ERROR_FILE_NOT_FOUND);
-      WCMD_print_error ();
     }
-    return;
+    if (h == INVALID_HANDLE_VALUE) {
+      strcpy (string, file);
+      CharLower (string);
+      if (strstr (string, extension_exe) == NULL) strcat (string, extension_exe);
+      h = CreateFile (string, GENERIC_READ, FILE_SHARE_READ,
+                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (h != INVALID_HANDLE_VALUE) {
+        WCMD_run_program (command, 0);
+      } else {
+        SetLastError (ERROR_FILE_NOT_FOUND);
+        WCMD_print_error ();
+      }
+      return;
+    }
+  } else {
+    DuplicateHandle(GetCurrentProcess(), pgmHandle,
+                    GetCurrentProcess(), &h,
+                    0, FALSE, DUPLICATE_SAME_ACCESS);
   }
 
 /*
@@ -90,6 +99,12 @@ BATCH_CONTEXT *prev_context;
   context -> prev_context = prev_context;
   context -> skip_rest = FALSE;
 
+  /* If processing a call :label, 'goto' the label in question */
+  if (startLabel) {
+    strcpy(param1, startLabel);
+    WCMD_goto();
+  }
+
 /*
  * 	Work through the file line by line. Specific batch commands are processed here,
  * 	the rest are handled by the main command processor.
@@ -695,3 +710,40 @@ void WCMD_HandleTildaModifiers(char **start, char *forVariable) {
   strcat(*start, pos);
   free(pos);
 }
+
+/*******************************************************************
+ * WCMD_call - processes a batch call statement
+ *
+ *	If there is a leading ':', calls within this batch program
+ *	otherwise launches another program.
+ */
+void WCMD_call (char *command) {
+
+  /* Run other program if no leading ':' */
+  if (*command != ':') {
+    WCMD_run_program(command, 1);
+  } else {
+
+    char gotoLabel[MAX_PATH];
+
+    strcpy(gotoLabel, param1);
+
+    if (context) {
+
+      LARGE_INTEGER li;
+
+      /* Save the current file position, call the same file,
+         restore position                                    */
+      li.QuadPart = 0;
+      li.LowPart = SetFilePointer(context -> h, li.LowPart,
+                     &li.HighPart, FILE_CURRENT);
+
+      WCMD_batch (param1, command, 1, gotoLabel, context->h);
+
+      SetFilePointer(context -> h, li.LowPart,
+                     &li.HighPart, FILE_BEGIN);
+    } else {
+      printf("Cannot call batch label outside of a batch script\n");
+    }
+  }
+}
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 346591a..9a8b513 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -434,6 +434,7 @@ char string[MAX_PATH];
     return;
   }
   if (context != NULL) {
+    char *paramStart = param1;
 
     /* Handle special :EOF label */
     if (lstrcmpi (":eof", param1) == 0) {
@@ -441,9 +442,12 @@ char string[MAX_PATH];
       return;
     }
 
+    /* Support goto :label as well as goto label */
+    if (*paramStart == ':') paramStart++;
+
     SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
     while (WCMD_fgets (string, sizeof(string), context -> h)) {
-      if ((string[0] == ':') && (lstrcmpi (&string[1], param1) == 0)) return;
+      if ((string[0] == ':') && (lstrcmpi (&string[1], paramStart) == 0)) return;
     }
     WCMD_output ("Target to GOTO not found\n");
   }
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 07d1649..4391d7c 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -27,7 +27,8 @@
 #include <stdio.h>
 #include <ctype.h>
 
-void WCMD_batch (char *, char *, int);
+void WCMD_batch (char *, char *, int, char *, HANDLE);
+void WCMD_call (char *command);
 void WCMD_change_tty (void);
 void WCMD_clear_screen (void);
 void WCMD_copy (void);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 84d1c04..17b75f3 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -265,7 +265,7 @@ int main (int argc, char *argv[])
   if (h != INVALID_HANDLE_VALUE) {
     CloseHandle (h);
 #if 0
-    WCMD_batch_command (string);
+    WCMD_batch ((char *)"\\autoexec.bat", (char *)"\\autoexec.bat", 0, NULL, INVALID_HANDLE_VALUE);
 #endif
   }
 
@@ -422,7 +422,7 @@ void WCMD_process_command (char *command)
         WCMD_setshow_attrib ();
         break;
       case WCMD_CALL:
-        WCMD_run_program (p, 1);
+        WCMD_call (p);
         break;
       case WCMD_CD:
       case WCMD_CHDIR:
@@ -628,14 +628,14 @@ char filetorun[MAX_PATH];
     if (!ext || !strcasecmp( ext, ".bat"))
     {
       if (SearchPath (NULL, param1, ".bat", sizeof(filetorun), filetorun, NULL)) {
-        WCMD_batch (filetorun, command, called);
+        WCMD_batch (filetorun, command, called, NULL, INVALID_HANDLE_VALUE);
         return;
       }
     }
     if (!ext || !strcasecmp( ext, ".cmd"))
     {
       if (SearchPath (NULL, param1, ".cmd", sizeof(filetorun), filetorun, NULL)) {
-        WCMD_batch (filetorun, command, called);
+        WCMD_batch (filetorun, command, called, NULL, INVALID_HANDLE_VALUE);
         return;
       }
     }
@@ -644,7 +644,7 @@ char filetorun[MAX_PATH];
     char *ext = strrchr( param1, '.' );
     if (ext && (!strcasecmp( ext, ".bat" ) || !strcasecmp( ext, ".cmd" )))
     {
-      WCMD_batch (param1, command, called);
+      WCMD_batch (param1, command, called, NULL, INVALID_HANDLE_VALUE);
       return;
     }
 
@@ -657,7 +657,7 @@ char filetorun[MAX_PATH];
                       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
       if (h != INVALID_HANDLE_VALUE) {
         CloseHandle (h);
-        WCMD_batch (param1, command, called);
+        WCMD_batch (param1, command, called, NULL, INVALID_HANDLE_VALUE);
         return;
       }
     }




More information about the wine-cvs mailing list