Added more batch functionality, including the CALL GOTO and SHIFT commands plus batch command arguments.
diff --git a/programs/wcmd/batch.c b/programs/wcmd/batch.c index cba1c3e..2f51b37 100644 --- a/programs/wcmd/batch.c +++ b/programs/wcmd/batch.c
@@ -8,9 +8,7 @@ #include "wcmd.h" -void WCMD_batch_command (HANDLE h, char *command); -char *WCMD_parameter (char *s, int n); -BOOL WCMD_go_to (HANDLE h, char *label); +void WCMD_batch_command (char *line); extern HANDLE STDin, STDout; extern char nyi[]; @@ -18,6 +16,7 @@ extern char version_string[]; extern int echo_mode; extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; +extern BATCH_CONTEXT *context; @@ -28,16 +27,17 @@ * On entry *command includes the complete command line beginning with the name * of the batch file (if a CALL command was entered the CALL has been removed). * *file is the name of the file, which might not exist and may not have the - * .BAT suffix on. + * .BAT suffix on. Called is 1 for a CALL, 0 otherwise. * * 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. */ -void WCMD_batch (char *file, char *command) { +void WCMD_batch (char *file, char *command, int called) { HANDLE h; char string[MAX_PATH]; -int n; +BATCH_CONTEXT *prev_context; strcpy (string, file); CharLower (string); @@ -49,69 +49,88 @@ } /* + * Create a context structure for this batch file. + */ + + prev_context = context; + context = (BATCH_CONTEXT *)LocalAlloc (LMEM_FIXED, sizeof (BATCH_CONTEXT)); + context -> h = h; + context -> command = command; + context -> shift_count = 0; + context -> prev_context = prev_context; + +/* * Work through the file line by line. Specific batch commands are processed here, * the rest are handled by the main command processor. */ while (WCMD_fgets (string, sizeof(string), h)) { - n = strlen (string); - if (string[n-1] == '\n') string[n-1] = '\0'; - if (string[n-2] == '\r') string[n-2] = '\0'; /* Under Windoze we get CRLF! */ - WCMD_batch_command (h, string); + if (string[0] != ':') { /* Skip over labels */ + WCMD_batch_command (string); + } } CloseHandle (h); + +/* + * If invoked by a CALL, we return to the context of our caller. Otherwise return + * to the caller's caller. + */ + + LocalFree ((HANDLE)context); + if ((prev_context != NULL) && (!called)) { + CloseHandle (prev_context -> h); + context = prev_context -> prev_context; + LocalFree ((HANDLE)prev_context); + } + else { + context = prev_context; + } } /**************************************************************************** * WCMD_batch_command * - * Execute one line from a batch file. + * Execute one line from a batch file, expanding parameters. */ -void WCMD_batch_command (HANDLE h, char *command) { +void WCMD_batch_command (char *line) { DWORD status; char cmd[1024]; +char *p, *s, *t; +int i; - if (echo_mode && (command[0] != '@')) WCMD_output ("%s", command); - status = ExpandEnvironmentStrings (command, cmd, sizeof(cmd)); + if (echo_mode && (line[0] != '@')) WCMD_output ("%s", line); + status = ExpandEnvironmentStrings (line, cmd, sizeof(cmd)); if (!status) { WCMD_print_error (); return; } - WCMD_process_command (cmd); + p = cmd; + while ((p = strchr(p, '%'))) { + i = *(p+1) - '0'; + if ((i >= 0) && (i <= 9)) { + s = strdup (p+2); + t = WCMD_parameter (context -> command, i + context -> shift_count); + strcpy (p, t); + strcat (p, s); + free (s); } - -/**************************************************************************** - * WCMD_go_to - * - * Batch file jump instruction. Not the most efficient algorithm ;-) - * Returns FALSE if the specified label cannot be found - the file pointer is - * then at EOF. - */ - -BOOL WCMD_go_to (HANDLE h, char *label) { - -char string[MAX_PATH]; - - SetFilePointer (h, 0, NULL, FILE_BEGIN); - while (WCMD_fgets (string, sizeof(string), h)) { - if ((string[0] == ':') && (strcmp (&string[1], label) == 0)) return TRUE; } - return FALSE; + WCMD_process_command (cmd); } /******************************************************************* * WCMD_parameter - extract a parameter from a command line. * - * Returns the 'n'th space-delimited parameter on the command line. + * Returns the 'n'th space-delimited parameter on the command line (zero-based). * Parameter is in static storage overwritten on the next call. - * Parameters in quotes are handled. + * Parameters in quotes (and brackets) are handled. */ char *WCMD_parameter (char *s, int n) { -int i = -1; +int i = 0; static char param[MAX_PATH]; char *p; @@ -136,6 +155,21 @@ } if (*s == '"') s++; break; + case '(': + s++; + while ((*s != '\0') && (*s != ')')) { + *p++ = *s++; + } + if (i == n) { + *p = '\0'; + return param; + } + else { + param[0] = '\0'; + i++; + } + if (*s == '"') s++; + break; case '\0': return param; default: @@ -148,6 +182,7 @@ } else { param[0] = '\0'; + p = param; i++; } } @@ -158,7 +193,8 @@ * WCMD_fgets * * Get one line from a batch file. We can't use the native f* functions because - * of the filename syntax differences between DOS and Unix. + * of the filename syntax differences between DOS and Unix. Also need to lose + * the LF (or CRLF) from the line. */ char *WCMD_fgets (char *s, int n, HANDLE h) { @@ -170,10 +206,13 @@ p = s; do { status = ReadFile (h, s, 1, &bytes, NULL); - if ((status == 0) || (bytes == 0)) return NULL; + if ((status == 0) || ((bytes == 0) && (s == p))) return NULL; if (*s == '\n') bytes = 0; - *++s = '\0'; + else if (*s != '\r') { + s++; n--; + } + *s = '\0'; } while ((bytes == 1) && (n > 1)); return p; }