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
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);
......@@ -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,
* 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;
}
......@@ -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);
}
......@@ -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
*
* Batch file conditional.
......@@ -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;
}
}
......
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