From: Eric Pouech eric.pouech@gmail.com
It's shared by all contexts refererring to the same bat/cmd file.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- programs/cmd/batch.c | 79 +++++++++++++++++++++++++++-------------- programs/cmd/builtins.c | 2 +- programs/cmd/wcmd.h | 31 +++++++++------- programs/cmd/wcmdmain.c | 6 ++-- 4 files changed, 74 insertions(+), 44 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 3866831ed68..159b4416a65 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -56,6 +56,53 @@ static RETURN_CODE WCMD_batch_main_loop(void) return return_code; }
+static struct batch_file *find_or_alloc_batch_file(const WCHAR *file) +{ + struct batch_file *batchfile; + struct batch_context *ctx; + + for (ctx = context; ctx; ctx = ctx->prev_context) + { + if (ctx->batch_file && !wcscmp(ctx->batch_file->path_name, file)) + return ctx->batch_file; + } + batchfile = xalloc(sizeof(*batchfile)); + batchfile->ref_count = 0; + batchfile->path_name = xstrdupW(file); + + return batchfile; +} + +static struct batch_context *push_batch_context(WCHAR *command, struct batch_file *batch_file, ULONGLONG pos) +{ + struct batch_context *prev = context; + + context = xalloc(sizeof(struct batch_context)); + context->file_position.QuadPart = pos; + context->command = command; + memset(context->shift_count, 0x00, sizeof(context->shift_count)); + context->prev_context = prev; + context->skip_rest = FALSE; + context->batch_file = batch_file; + batch_file->ref_count++; + + return context; +} + +static struct batch_context *pop_batch_context(struct batch_context *ctx) +{ + struct batch_context *prev = ctx->prev_context; + struct batch_file *batchfile = ctx->batch_file; + if (batchfile && --batchfile->ref_count == 0) + { + free(batchfile->path_name); + free(batchfile); + ctx->batch_file = NULL; + } + free(ctx); + return prev; +} + /**************************************************************************** * WCMD_batch * @@ -74,24 +121,11 @@ static RETURN_CODE WCMD_batch_main_loop(void)
RETURN_CODE WCMD_call_batch(const WCHAR *file, WCHAR *command) { - BATCH_CONTEXT *prev_context; RETURN_CODE return_code = NO_ERROR;
- /* Create a context structure for this batch file. */ - prev_context = context; - context = malloc(sizeof (BATCH_CONTEXT)); - context->file_position.QuadPart = 0; - context->batchfileW = xstrdupW(file); - context->command = command; - memset(context->shift_count, 0x00, sizeof(context->shift_count)); - context->prev_context = prev_context; - context->skip_rest = FALSE; - + context = push_batch_context(command, find_or_alloc_batch_file(file), 0); return_code = WCMD_batch_main_loop(); - - free(context->batchfileW); - free(context); - context = prev_context; + context = pop_batch_context(context);
if (return_code != NO_ERROR && return_code != RETURN_CODE_ABORTED) errorlevel = return_code; @@ -376,7 +410,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->batch_file->path_name); } else if ((*lastModifier >= '0' && *lastModifier <= '9')) { lstrcpyW(outputparam, WCMD_parameter (context -> command, @@ -634,7 +668,6 @@ RETURN_CODE WCMD_call(WCHAR *command) else if (context) { WCHAR gotoLabel[MAX_PATH]; - BATCH_CONTEXT *prev_context;
lstrcpyW(gotoLabel, param1);
@@ -642,14 +675,7 @@ RETURN_CODE WCMD_call(WCHAR *command) as for loop variables do not survive a call */ WCMD_save_for_loop_context(TRUE);
- prev_context = context; - context = malloc(sizeof (BATCH_CONTEXT)); - context->file_position = prev_context->file_position; /* will be overwritten by WCMD_GOTO below */ - context->batchfileW = prev_context->batchfileW; - context->command = buffer; - memset(context->shift_count, 0x00, sizeof(context->shift_count)); - context->prev_context = prev_context; - context->skip_rest = FALSE; + context = push_batch_context(buffer, context->batch_file, context->file_position.QuadPart);
/* FIXME as commands here can temper with param1 global variable (ugly) */ lstrcpyW(param1, gotoLabel); @@ -657,8 +683,7 @@ RETURN_CODE WCMD_call(WCHAR *command)
WCMD_batch_main_loop();
- free(context); - context = prev_context; + context = pop_batch_context(context); return_code = errorlevel;
/* Restore the for loop context */ diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index c2379598976..21f15c32c4a 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1752,7 +1752,7 @@ RETURN_CODE WCMD_goto(void) context->skip_rest = TRUE; return RETURN_CODE_ABORTED; } - h = CreateFileW(context->batchfileW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + h = CreateFileW(context->batch_file->path_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 2731743c27a..5138410e8ab 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -258,23 +258,28 @@ 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 */ +struct batch_file +{ + unsigned ref_count; /* number of BATCH_CONTEXT attached to this */ + WCHAR *path_name; /* Name of self */ +};
-typedef struct _BATCH_CONTEXT +struct batch_context { - WCHAR *command; /* The command which invoked the batch file */ - LARGE_INTEGER file_position; - 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 */ -} BATCH_CONTEXT; + WCHAR *command; /* The command which invoked the batch file */ + LARGE_INTEGER file_position; + 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 */ + struct batch_file *batch_file; /* Reference to the file itself */ +};
/* Data structure to handle building lists during recursive calls */
struct env_stack { - BATCH_CONTEXT *context; + struct batch_context *context; struct env_stack *next; union { @@ -324,7 +329,7 @@ void WCMD_set_for_loop_variable(unsigned varidx, const WCHAR *value); */ extern WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; extern int errorlevel; -extern BATCH_CONTEXT *context; +extern struct batch_context *context; extern BOOL delayedsubst;
static inline BOOL WCMD_is_in_context(const WCHAR *ext) @@ -332,9 +337,9 @@ static inline BOOL WCMD_is_in_context(const WCHAR *ext) size_t c_len, e_len; if (!context) return FALSE; if (!ext) return TRUE; - c_len = wcslen(context->batchfileW); + c_len = wcslen(context->batch_file->path_name); e_len = wcslen(ext); - return (c_len > e_len) && !wcsicmp(&context->batchfileW[c_len - e_len], ext); + return (c_len > e_len) && !wcsicmp(&context->batch_file->path_name[c_len - e_len], ext); }
#endif /* !RC_INVOKED */ diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 674ea8b1025..fbec86a481a 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -53,7 +53,7 @@ typedef struct _SEARCH_CONTEXT extern const WCHAR inbuilt[][10]; extern struct env_stack *pushd_directories;
-BATCH_CONTEXT *context = NULL; +struct batch_context *context = NULL; int errorlevel; WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; BOOL interactive; @@ -3113,7 +3113,7 @@ static WCHAR *fetch_next_line(BOOL feed, BOOL first_line, WCHAR* buffer) if (context) { LARGE_INTEGER zeroli = {.QuadPart = 0}; - HANDLE h = CreateFileW(context->batchfileW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + HANDLE h = CreateFileW(context->batch_file->path_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { @@ -4130,7 +4130,7 @@ RETURN_CODE node_execute(CMD_NODE *node) WCHAR filename[MAX_PATH]; CMD_REDIRECTION *output; HANDLE saved_output; - BATCH_CONTEXT *saved_context = context; + struct batch_context *saved_context = context;
/* pipe LHS & RHS are run outside of any batch context */ context = NULL;