Added more batch functionality, including the CALL GOTO and SHIFT
commands plus batch command arguments.
This commit is contained in:
parent
a72a394d04
commit
5f8f4f77f5
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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_process_command (cmd);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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_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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue