[PATCH 1/2] programs/cmd: introduce structure BATCH_FILE to hold information about a .cmd file

Eric Pouech eric.pouech at gmail.com
Sat Mar 26 03:51:01 CDT 2022


keeping BATCH_CONTEXT as the execution context of a BATCH_FILE

Signed-off-by: Eric Pouech <eric.pouech at gmail.com>

---
 programs/cmd/batch.c |   48 ++++++++++++++++++++++++++++++++++++++++++------
 programs/cmd/wcmd.h  |   10 ++++++++--
 2 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c
index 9a262c5fec5..ab9b90e48ca 100644
--- a/programs/cmd/batch.c
+++ b/programs/cmd/batch.c
@@ -26,6 +26,40 @@ extern struct env_stack *saved_environment;
 
 WINE_DEFAULT_DEBUG_CHANNEL(cmd);
 
+static BATCH_FILE *linkto_batch_file( const WCHAR *file, HANDLE h )
+{
+    BATCH_FILE *batchfile;
+    BATCH_CONTEXT *ctx;
+    FILETIME last;
+
+    GetFileTime(h, NULL, NULL, &last);
+    for (ctx = context; ctx; ctx = ctx->prev_context)
+    {
+        if (ctx->file && !wcscmp( ctx->file->batchfileW, file ) &&
+            !CompareFileTime( &last, &ctx->file->last_modified ))
+        {
+            ctx->file->ref_count++;
+            return ctx->file;
+        }
+    }
+    batchfile = malloc( sizeof(*batchfile) );
+    batchfile->ref_count = 1;
+    batchfile->batchfileW = heap_strdupW( file );
+    batchfile->last_modified = last;
+
+    return batchfile;
+}
+
+static void unref_batch_file( BATCH_CONTEXT *ctx )
+{
+    BATCH_FILE *batchfile = ctx->file;
+    if (--batchfile->ref_count == 0) {
+        heap_free( batchfile->batchfileW );
+        free( batchfile );
+        ctx->file = NULL;
+    }
+}
+
 /****************************************************************************
  * WCMD_batch
  *
@@ -46,6 +80,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
 {
   HANDLE h = INVALID_HANDLE_VALUE;
   BATCH_CONTEXT *prev_context;
+  BATCH_FILE *batchfile;
 
   if (startLabel == NULL) {
     h = CreateFileW (file, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
@@ -65,14 +100,15 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
  *	Create a context structure for this batch file.
  */
 
+  batchfile = linkto_batch_file( file, h );
   prev_context = context;
-  context = LocalAlloc (LMEM_FIXED, sizeof (BATCH_CONTEXT));
+  context = malloc(sizeof(BATCH_CONTEXT));
   context -> h = h;
-  context->batchfileW = heap_strdupW(file);
   context -> command = command;
   memset(context -> shift_count, 0x00, sizeof(context -> shift_count));
   context -> prev_context = prev_context;
   context -> skip_rest = FALSE;
+  context -> file = batchfile;
 
   /* If processing a call :label, 'goto' the label in question */
   if (startLabel) {
@@ -110,8 +146,8 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
  *	to the caller's caller.
  */
 
-  heap_free(context->batchfileW);
-  LocalFree (context);
+  unref_batch_file( context );
+  free(context);
   if ((prev_context != NULL) && (!called)) {
     WINE_TRACE("Batch completed, but was not 'called' so skipping outer batch too\n");
     prev_context -> skip_rest = TRUE;
@@ -417,7 +453,7 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute)
      whereas if you start applying other modifiers to it, you get the filename
      the batch label is in                                                     */
   if (*lastModifier == '0' && modifierLen > 1) {
-    lstrcpyW(outputparam, context->batchfileW);
+    lstrcpyW(outputparam, context->file->batchfileW);
   } else if ((*lastModifier >= '0' && *lastModifier <= '9')) {
     lstrcpyW(outputparam,
             WCMD_parameter (context -> command,
@@ -675,7 +711,7 @@ void WCMD_call (WCHAR *command) {
       li.QuadPart = 0;
       li.u.LowPart = SetFilePointer(context -> h, li.u.LowPart,
                      &li.u.HighPart, FILE_CURRENT);
-      WCMD_batch (context->batchfileW, command, TRUE, gotoLabel, context->h);
+      WCMD_batch (context->file->batchfileW, command, TRUE, gotoLabel, context->h);
       SetFilePointer(context -> h, li.u.LowPart,
                      &li.u.HighPart, FILE_BEGIN);
 
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 234c253b49a..ebce5359eb8 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -149,16 +149,22 @@ static inline BOOL ends_with_backslash( const WCHAR *path )
 
 int evaluate_if_condition(WCHAR *p, WCHAR **command, int *test, int *negate);
 
-/* Data structure to hold context when executing batch files */
+/* Data structure to store information about a batch file */
+typedef struct _BATCH_FILE {
+  unsigned            ref_count;    /* number of BATCH_CONTEXT attached to this */
+  WCHAR              *batchfileW;   /* Name of self */
+  FILETIME            last_modified;/* last modified date of the file */
+} BATCH_FILE;
 
+/* Data structure to hold context when executing batch files */
 typedef struct _BATCH_CONTEXT {
   WCHAR *command;	/* The command which invoked the batch file */
   HANDLE h;             /* Handle to the open batch file */
-  WCHAR *batchfileW;    /* Name of same */
   int shift_count[10];	/* Offset in terms of shifts for %0 - %9 */
   struct _BATCH_CONTEXT *prev_context; /* Pointer to the previous context block */
   BOOL  skip_rest;      /* Skip the rest of the batch program and exit */
   CMD_LIST *toExecute;  /* Commands left to be executed */
+  BATCH_FILE *file;     /* Reference to the file itself */
 } BATCH_CONTEXT;
 
 /* Data structure to handle building lists during recursive calls */




More information about the wine-devel mailing list