Commit 5f8f4f77 authored by Dave Pickles's avatar Dave Pickles Committed by Alexandre Julliard

Added more batch functionality, including the CALL GOTO and SHIFT

commands plus batch command arguments.
parent a72a394d
v0.11 - 20 June 1999
Batch command parameters (and the SHIFT command) added.
GOTO added.
Batch invokation (including CALL) now functions correctly
VERIFY command added as a stub.
v0.10 - 2 June 1999 v0.10 - 2 June 1999
Additional help text and error codes. Additional help text and error codes.
......
...@@ -12,9 +12,10 @@ WHAT'S INCLUDED ...@@ -12,9 +12,10 @@ WHAT'S INCLUDED
WHAT'S MISSING WHAT'S MISSING
- Redirection, shell parameters and pipes - Redirection, shell parameters and pipes
- Command-line qualifiers for most builtin commands - Command-line qualifiers for most builtin commands
- MOVE command (plus the batch-only ones) - MOVE command
- IF and FOR commands
- Wildcards and relative paths in COPY and RENAME - Wildcards and relative paths in COPY and RENAME
- Set functionality in DATE, TIME, ATTRIB, SET, LABEL - Set functionality in DATE, TIME, ATTRIB, LABEL
- Full internationalisation of the text (and commands?). - Full internationalisation of the text (and commands?).
WHAT DOESN'T WORK WHAT DOESN'T WORK
...@@ -37,9 +38,6 @@ free space are computed to 64 bits. ...@@ -37,9 +38,6 @@ free space are computed to 64 bits.
but one does exist in a lower directory. but one does exist in a lower directory.
- Copy, rename, move, need the source and destination to be specified fully - Copy, rename, move, need the source and destination to be specified fully
with an absolute or relative path but no wildcards or partial filenames. with an absolute or relative path but no wildcards or partial filenames.
- Simple batch files work, ie a list of commands as they would be typed. However
invoking a batch file from within another invokes the CALL function, control
returns to the calling batch file when the subfile exits.
WINE OR WIN32 BINARY? WINE OR WIN32 BINARY?
Wcmd can be built as a Wine binary, or (using a Win32 compiler) as a Win32 .EXE Wcmd can be built as a Wine binary, or (using a Win32 compiler) as a Win32 .EXE
......
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
#include "wcmd.h" #include "wcmd.h"
void WCMD_batch_command (HANDLE h, char *command); void WCMD_batch_command (char *line);
char *WCMD_parameter (char *s, int n);
BOOL WCMD_go_to (HANDLE h, char *label);
extern HANDLE STDin, STDout; extern HANDLE STDin, STDout;
extern char nyi[]; extern char nyi[];
...@@ -18,6 +16,7 @@ extern char newline[]; ...@@ -18,6 +16,7 @@ extern char newline[];
extern char version_string[]; extern char version_string[];
extern int echo_mode; extern int echo_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
extern BATCH_CONTEXT *context;
...@@ -28,16 +27,17 @@ extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; ...@@ -28,16 +27,17 @@ extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
* On entry *command includes the complete command line beginning with the name * 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). * 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 * *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. * 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; HANDLE h;
char string[MAX_PATH]; char string[MAX_PATH];
int n; BATCH_CONTEXT *prev_context;
strcpy (string, file); strcpy (string, file);
CharLower (string); CharLower (string);
...@@ -49,69 +49,88 @@ int n; ...@@ -49,69 +49,88 @@ int n;
} }
/* /*
* 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, * Work through the file line by line. Specific batch commands are processed here,
* the rest are handled by the main command processor. * the rest are handled by the main command processor.
*/ */
while (WCMD_fgets (string, sizeof(string), h)) { while (WCMD_fgets (string, sizeof(string), h)) {
n = strlen (string); if (string[0] != ':') { /* Skip over labels */
if (string[n-1] == '\n') string[n-1] = '\0'; WCMD_batch_command (string);
if (string[n-2] == '\r') string[n-2] = '\0'; /* Under Windoze we get CRLF! */ }
WCMD_batch_command (h, string);
} }
CloseHandle (h); 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 * 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; DWORD status;
char cmd[1024]; char cmd[1024];
char *p, *s, *t;
int i;
if (echo_mode && (command[0] != '@')) WCMD_output ("%s", command); if (echo_mode && (line[0] != '@')) WCMD_output ("%s", line);
status = ExpandEnvironmentStrings (command, cmd, sizeof(cmd)); status = ExpandEnvironmentStrings (line, cmd, sizeof(cmd));
if (!status) { if (!status) {
WCMD_print_error (); WCMD_print_error ();
return; 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. * 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. * 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) { char *WCMD_parameter (char *s, int n) {
int i = -1; int i = 0;
static char param[MAX_PATH]; static char param[MAX_PATH];
char *p; char *p;
...@@ -136,6 +155,21 @@ char *p; ...@@ -136,6 +155,21 @@ char *p;
} }
if (*s == '"') s++; if (*s == '"') s++;
break; 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': case '\0':
return param; return param;
default: default:
...@@ -148,6 +182,7 @@ char *p; ...@@ -148,6 +182,7 @@ char *p;
} }
else { else {
param[0] = '\0'; param[0] = '\0';
p = param;
i++; i++;
} }
} }
...@@ -158,7 +193,8 @@ char *p; ...@@ -158,7 +193,8 @@ char *p;
* WCMD_fgets * WCMD_fgets
* *
* Get one line from a batch file. We can't use the native f* functions because * 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) { char *WCMD_fgets (char *s, int n, HANDLE h) {
...@@ -170,10 +206,13 @@ char *p; ...@@ -170,10 +206,13 @@ char *p;
p = s; p = s;
do { do {
status = ReadFile (h, s, 1, &bytes, NULL); 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; if (*s == '\n') bytes = 0;
*++s = '\0'; else if (*s != '\r') {
s++;
n--; n--;
}
*s = '\0';
} while ((bytes == 1) && (n > 1)); } while ((bytes == 1) && (n > 1));
return p; return p;
} }
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
/* /*
* FIXME: * FIXME:
* - No support for redirection, pipes, batch files, shell parameters * - No support for redirection, pipes, shell parameters
* - 32-bit limit on file sizes in DIR command * - 32-bit limit on file sizes in DIR command
* - Lots of functionality missing from builtins * - Lots of functionality missing from builtins
* - Messages etc need international support * - Messages etc need international support
...@@ -25,21 +25,11 @@ extern char nyi[]; ...@@ -25,21 +25,11 @@ extern char nyi[];
extern char newline[]; extern char newline[];
extern char version_string[]; extern char version_string[];
extern char anykey[]; extern char anykey[];
extern int echo_mode; extern int echo_mode, verify_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
extern BATCH_CONTEXT *context;
/****************************************************************************
* WCMD_call
*
* Call another batch file.
*/
void WCMD_call () {
WCMD_output (nyi);
}
/**************************************************************************** /****************************************************************************
* WCMD_clear_screen * WCMD_clear_screen
...@@ -201,8 +191,12 @@ int count; ...@@ -201,8 +191,12 @@ int count;
* Batch file loop processing. * Batch file loop processing.
*/ */
void WCMD_for () { void WCMD_for (char *p) {
if (lstrcmpi (WCMD_parameter (p, 1), "in") || lstrcmpi (WCMD_parameter (p, 3), "do")) {
WCMD_output ("Syntax error\n");
return;
}
WCMD_output (nyi); WCMD_output (nyi);
} }
...@@ -238,6 +232,30 @@ char buffer[2048]; ...@@ -238,6 +232,30 @@ char buffer[2048];
} }
/**************************************************************************** /****************************************************************************
* WCMD_go_to
*
* Batch file jump instruction. Not the most efficient algorithm ;-)
* Prints error message if the specified label cannot be found - the file pointer is
* then at EOF, effectively stopping the batch file.
* FIXME: DOS is supposed to allow labels with spaces - we don't.
*/
void WCMD_goto () {
char string[MAX_PATH];
if (context != NULL) {
SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
while (WCMD_fgets (string, sizeof(string), context -> h)) {
if ((string[0] == ':') && (strcmp (&string[1], param1) == 0)) return;
}
WCMD_output ("Target to GOTO not found\n");
}
return;
}
/****************************************************************************
* WCMD_if * WCMD_if
* *
* Batch file conditional. * Batch file conditional.
...@@ -541,7 +559,7 @@ DWORD count; ...@@ -541,7 +559,7 @@ DWORD count;
void WCMD_shift () { void WCMD_shift () {
WCMD_output (nyi); if (context != NULL) context -> shift_count++;
} }
...@@ -574,12 +592,30 @@ DWORD count; ...@@ -574,12 +592,30 @@ DWORD count;
* WCMD_verify * WCMD_verify
* *
* Display verify flag. * Display verify flag.
* FIXME: We don't actually do anything with the verify flag other than toggle
* it...
*/ */
void WCMD_verify () { void WCMD_verify (char *command) {
WCMD_output (nyi); static char *von = "Verify is ON\n", *voff = "Verify is OFF\n";
int count;
count = strlen(command);
if (count == 0) {
if (verify_mode) WCMD_output (von);
else WCMD_output (voff);
return;
}
if (lstrcmpi(command, "ON") == 0) {
verify_mode = 1;
return;
}
else if (lstrcmpi(command, "OFF") == 0) {
verify_mode = 0;
return;
}
else WCMD_output ("Verify must be ON or OFF\n");
} }
/**************************************************************************** /****************************************************************************
......
...@@ -19,8 +19,7 @@ ...@@ -19,8 +19,7 @@
#include <wincon.h> #include <wincon.h>
#endif /* !WINELIB */ #endif /* !WINELIB */
void WCMD_batch (char *, char *); void WCMD_batch (char *, char *, int);
void WCMD_call (void);
void WCMD_change_tty (void); void WCMD_change_tty (void);
void WCMD_clear_screen (void); void WCMD_clear_screen (void);
void WCMD_copy (void); void WCMD_copy (void);
...@@ -28,8 +27,9 @@ void WCMD_create_dir (void); ...@@ -28,8 +27,9 @@ void WCMD_create_dir (void);
void WCMD_delete (int recurse); void WCMD_delete (int recurse);
void WCMD_directory (void); void WCMD_directory (void);
void WCMD_echo (char *); void WCMD_echo (char *);
void WCMD_for (void); void WCMD_for (char *);
void WCMD_give_help (char *command); void WCMD_give_help (char *command);
void WCMD_goto (void);
void WCMD_if (void); void WCMD_if (void);
void WCMD_move (void); void WCMD_move (void);
void WCMD_output (char *format, ...); void WCMD_output (char *format, ...);
...@@ -50,13 +50,24 @@ void WCMD_setshow_time (void); ...@@ -50,13 +50,24 @@ void WCMD_setshow_time (void);
void WCMD_shift (void); void WCMD_shift (void);
void WCMD_show_prompt (void); void WCMD_show_prompt (void);
void WCMD_type (void); void WCMD_type (void);
void WCMD_verify (void); void WCMD_verify (char *command);
void WCMD_version (void); void WCMD_version (void);
int WCMD_volume (int mode, char *command); int WCMD_volume (int mode, char *command);
char *WCMD_fgets (char *s, int n, HANDLE stream); char *WCMD_fgets (char *s, int n, HANDLE stream);
char *WCMD_parameter (char *s, int n);
char *WCMD_strtrim_leading_spaces (char *string); char *WCMD_strtrim_leading_spaces (char *string);
void WCMD_strtrim_trailing_spaces (char *string); void WCMD_strtrim_trailing_spaces (char *string);
/* Data structure to hold context when executing batch files */
typedef struct {
char *command; /* The command which invoked the batch file */
HANDLE h; /* Handle to the open batch file */
int shift_count; /* Number of SHIFT commands executed */
void *prev_context; /* Pointer to the previous context block */
} BATCH_CONTEXT;
#endif /* !RC_INVOKED */ #endif /* !RC_INVOKED */
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
/* /*
* FIXME: * FIXME:
* - No support for redirection, pipes, batch commands * - No support for redirection, pipes
* - 32-bit limit on file sizes in DIR command * - 32-bit limit on file sizes in DIR command
* - Cannot handle parameters in quotes * - Cannot handle parameters in quotes
* - Lots of functionality missing from builtins * - Lots of functionality missing from builtins
...@@ -31,12 +31,13 @@ char *inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY", ...@@ -31,12 +31,13 @@ char *inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY",
HANDLE STDin, STDout; HANDLE STDin, STDout;
HINSTANCE hinst; HINSTANCE hinst;
int echo_mode = 1; int echo_mode = 1, verify_mode = 0;
char nyi[] = "Not Yet Implemented\n\n"; char nyi[] = "Not Yet Implemented\n\n";
char newline[] = "\n"; char newline[] = "\n";
char version_string[] = "WCMD Version 0.10\n\n"; char version_string[] = "WCMD Version 0.11\n\n";
char anykey[] = "Press any key to continue: "; char anykey[] = "Press any key to continue: ";
char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
BATCH_CONTEXT *context = NULL;
/***************************************************************************** /*****************************************************************************
* Main entry point. This is a console application so we have a main() not a * Main entry point. This is a console application so we have a main() not a
...@@ -198,7 +199,7 @@ DWORD count; ...@@ -198,7 +199,7 @@ DWORD count;
WCMD_setshow_attrib (); WCMD_setshow_attrib ();
break; break;
case WCMD_CALL: case WCMD_CALL:
WCMD_batch (param1, p); WCMD_batch (param1, p, 1);
break; break;
case WCMD_CD: case WCMD_CD:
case WCMD_CHDIR: case WCMD_CHDIR:
...@@ -227,9 +228,10 @@ DWORD count; ...@@ -227,9 +228,10 @@ DWORD count;
WCMD_echo (p); WCMD_echo (p);
break; break;
case WCMD_FOR: case WCMD_FOR:
WCMD_for (); WCMD_for (p);
break; break;
case WCMD_GOTO: case WCMD_GOTO:
WCMD_goto ();
break; break;
case WCMD_HELP: case WCMD_HELP:
WCMD_give_help (p); WCMD_give_help (p);
...@@ -282,7 +284,7 @@ DWORD count; ...@@ -282,7 +284,7 @@ DWORD count;
WCMD_version (); WCMD_version ();
break; break;
case WCMD_VERIFY: case WCMD_VERIFY:
WCMD_verify (); WCMD_verify (p);
break; break;
case WCMD_VOL: case WCMD_VOL:
WCMD_volume (0, p); WCMD_volume (0, p);
...@@ -315,14 +317,14 @@ char filetorun[MAX_PATH]; ...@@ -315,14 +317,14 @@ char filetorun[MAX_PATH];
if (strpbrk (param1, "\\:") == NULL) { /* No explicit path given */ if (strpbrk (param1, "\\:") == NULL) { /* No explicit path given */
if ((strchr (param1, '.') == NULL) || (strstr (param1, ".bat") != NULL)) { if ((strchr (param1, '.') == NULL) || (strstr (param1, ".bat") != NULL)) {
if (SearchPath (NULL, param1, ".bat", sizeof(filetorun), filetorun, NULL)) { if (SearchPath (NULL, param1, ".bat", sizeof(filetorun), filetorun, NULL)) {
WCMD_batch (filetorun, command); WCMD_batch (filetorun, command, 0);
return; return;
} }
} }
} }
else { /* Explicit path given */ else { /* Explicit path given */
if (strstr (param1, ".bat") != NULL) { if (strstr (param1, ".bat") != NULL) {
WCMD_batch (param1, command); WCMD_batch (param1, command, 0);
return; return;
} }
if (strchr (param1, '.') == NULL) { if (strchr (param1, '.') == NULL) {
...@@ -331,7 +333,7 @@ char filetorun[MAX_PATH]; ...@@ -331,7 +333,7 @@ char filetorun[MAX_PATH];
h = CreateFile (filetorun, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); h = CreateFile (filetorun, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE) { if (h != INVALID_HANDLE_VALUE) {
CloseHandle (h); CloseHandle (h);
WCMD_batch (param1, command); WCMD_batch (param1, command, 0);
return; return;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment