Added more batch functionality, including the CALL GOTO and SHIFT

commands plus batch command arguments.
This commit is contained in:
Dave Pickles 1999-06-26 10:24:08 +00:00 committed by Alexandre Julliard
parent a72a394d04
commit 5f8f4f77f5
6 changed files with 164 additions and 73 deletions

View File

@ -1,3 +1,8 @@
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
Additional help text and error codes.

View File

@ -12,9 +12,10 @@ WHAT'S INCLUDED
WHAT'S MISSING
- Redirection, shell parameters and pipes
- 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
- Set functionality in DATE, TIME, ATTRIB, SET, LABEL
- Set functionality in DATE, TIME, ATTRIB, LABEL
- Full internationalisation of the text (and commands?).
WHAT DOESN'T WORK
@ -37,9 +38,6 @@ free space are computed to 64 bits.
but one does exist in a lower directory.
- Copy, rename, move, need the source and destination to be specified fully
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?
Wcmd can be built as a Wine binary, or (using a Win32 compiler) as a Win32 .EXE

View File

@ -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 newline[];
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 @@ extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
* 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);
@ -48,70 +48,89 @@ int n;
return;
}
/*
* 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 @@ char *p;
}
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 @@ char *p;
}
else {
param[0] = '\0';
p = param;
i++;
}
}
@ -158,7 +193,8 @@ char *p;
* 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 @@ char *p;
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;
}

View File

@ -10,7 +10,7 @@
/*
* 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
* - Lots of functionality missing from builtins
* - Messages etc need international support
@ -25,21 +25,11 @@ extern char nyi[];
extern char newline[];
extern char version_string[];
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 BATCH_CONTEXT *context;
/****************************************************************************
* WCMD_call
*
* Call another batch file.
*/
void WCMD_call () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_clear_screen
@ -201,8 +191,12 @@ int count;
* 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);
}
@ -237,6 +231,30 @@ char buffer[2048];
return;
}
/****************************************************************************
* 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
*
@ -541,7 +559,7 @@ DWORD count;
void WCMD_shift () {
WCMD_output (nyi);
if (context != NULL) context -> shift_count++;
}
@ -574,12 +592,30 @@ DWORD count;
* WCMD_verify
*
* 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");
}
/****************************************************************************

View File

@ -19,8 +19,7 @@
#include <wincon.h>
#endif /* !WINELIB */
void WCMD_batch (char *, char *);
void WCMD_call (void);
void WCMD_batch (char *, char *, int);
void WCMD_change_tty (void);
void WCMD_clear_screen (void);
void WCMD_copy (void);
@ -28,8 +27,9 @@ void WCMD_create_dir (void);
void WCMD_delete (int recurse);
void WCMD_directory (void);
void WCMD_echo (char *);
void WCMD_for (void);
void WCMD_for (char *);
void WCMD_give_help (char *command);
void WCMD_goto (void);
void WCMD_if (void);
void WCMD_move (void);
void WCMD_output (char *format, ...);
@ -50,13 +50,24 @@ void WCMD_setshow_time (void);
void WCMD_shift (void);
void WCMD_show_prompt (void);
void WCMD_type (void);
void WCMD_verify (void);
void WCMD_verify (char *command);
void WCMD_version (void);
int WCMD_volume (int mode, char *command);
char *WCMD_fgets (char *s, int n, HANDLE stream);
char *WCMD_parameter (char *s, int n);
char *WCMD_strtrim_leading_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 */
/*

View File

@ -6,7 +6,7 @@
/*
* FIXME:
* - No support for redirection, pipes, batch commands
* - No support for redirection, pipes
* - 32-bit limit on file sizes in DIR command
* - Cannot handle parameters in quotes
* - Lots of functionality missing from builtins
@ -31,12 +31,13 @@ char *inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY",
HANDLE STDin, STDout;
HINSTANCE hinst;
int echo_mode = 1;
int echo_mode = 1, verify_mode = 0;
char nyi[] = "Not Yet Implemented\n\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 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
@ -198,7 +199,7 @@ DWORD count;
WCMD_setshow_attrib ();
break;
case WCMD_CALL:
WCMD_batch (param1, p);
WCMD_batch (param1, p, 1);
break;
case WCMD_CD:
case WCMD_CHDIR:
@ -227,9 +228,10 @@ DWORD count;
WCMD_echo (p);
break;
case WCMD_FOR:
WCMD_for ();
WCMD_for (p);
break;
case WCMD_GOTO:
WCMD_goto ();
break;
case WCMD_HELP:
WCMD_give_help (p);
@ -282,7 +284,7 @@ DWORD count;
WCMD_version ();
break;
case WCMD_VERIFY:
WCMD_verify ();
WCMD_verify (p);
break;
case WCMD_VOL:
WCMD_volume (0, p);
@ -315,14 +317,14 @@ char filetorun[MAX_PATH];
if (strpbrk (param1, "\\:") == NULL) { /* No explicit path given */
if ((strchr (param1, '.') == NULL) || (strstr (param1, ".bat") != NULL)) {
if (SearchPath (NULL, param1, ".bat", sizeof(filetorun), filetorun, NULL)) {
WCMD_batch (filetorun, command);
WCMD_batch (filetorun, command, 0);
return;
}
}
}
else { /* Explicit path given */
if (strstr (param1, ".bat") != NULL) {
WCMD_batch (param1, command);
WCMD_batch (param1, command, 0);
return;
}
if (strchr (param1, '.') == NULL) {
@ -331,7 +333,7 @@ char filetorun[MAX_PATH];
h = CreateFile (filetorun, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle (h);
WCMD_batch (param1, command);
WCMD_batch (param1, command, 0);
return;
}
}