Added Wine command-line interpreter.

oldstable
Dave Pickles 1999-06-06 15:24:04 +00:00 committed by Alexandre Julliard
parent 5cec819d11
commit 74f440eabf
14 changed files with 2276 additions and 0 deletions

2
configure vendored
View File

@ -5300,6 +5300,7 @@ programs/progman/Makefile
programs/regtest/Makefile
programs/regapi/Makefile
programs/view/Makefile
programs/wcmd/Makefile
programs/winhelp/Makefile
programs/winver/Makefile
rc/Makefile
@ -5469,6 +5470,7 @@ programs/progman/Makefile
programs/regtest/Makefile
programs/regapi/Makefile
programs/view/Makefile
programs/wcmd/Makefile
programs/winhelp/Makefile
programs/winver/Makefile
rc/Makefile

View File

@ -802,6 +802,7 @@ programs/progman/Makefile
programs/regtest/Makefile
programs/regapi/Makefile
programs/view/Makefile
programs/wcmd/Makefile
programs/winhelp/Makefile
programs/winver/Makefile
rc/Makefile

View File

@ -8,6 +8,7 @@ SUBDIRS = \
regapi \
regtest \
view \
wcmd \
winhelp \
winver

View File

@ -0,0 +1,3 @@
Makefile
wcmd
wcmdrc.s

View File

@ -0,0 +1,46 @@
v0.10 - 2 June 1999
Additional help text and error codes.
v0.09 - 5 May 1999
Directory byte counts and disk free space are reported with commas and in 64-bit.
File sizes have commas but are computed in 32 bits.
Handling of DIR /S on non-current path corrected.
DEL with wildcard or directory name works correctly.
v0.08 - 21 Mar 1999
Invoke an AUTOEXEC.BAT file if it exists in the root directory of the startup drive.
v0.07 - 8 Mar 1999
Can now be compiled as a WineLib app (conditional code added).
Additional help text.
Icon added to resources (the Wine-glass).
v0.06 - 23 Feb 1999
Help text moved into resource file to allow localisation.
Simple batch files (without parameters) can be executed.
v0.05 - 17 Feb 1999
Fixed problem with DIR command & long, complex relative paths.
DIR /S and /P implemented.
Date and time in PROMPT localised.
More work on batch files (they are echoed to screen but not executed).
v0.04 - 7 Feb 1999
Command-line qualifiers /c /q /k implemented (as NT's CMD.EXE).
ECHO command implemented, though echo mode is not honoured.
Environment variables in commands (eg %envvar%) expanded.
REN and COPY added, but no wildcard support or relative paths.
Filenames in quotes now handled.
PAUSE command.
Preliminary coding for batch files.
v0.03 - 5 Feb 1999
Added relative path and alternate drive support to DIR, also free disk space
(32-bit only!).
v0.02 - 27 Jan 1999
Added change-drive code.
v0.01 - 25 Jan 1999
Initial version.

View File

@ -0,0 +1,43 @@
DEFS = -DWINELIB
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = none
PROGRAMS = wcmd
ALL_LIBS = $(WINELIB) $(X_LIBS) $(XLIB) $(LIBS)
RCFLAGS = -w32 -h
WRCEXTRA = -A -t -p $*
C_SRCS = \
batch.c \
builtins.c \
directory.c \
wcmdmain.c
RC_SRCS = \
wcmdrc.rc
all: check_wrc $(PROGRAMS)
depend:: $(RC_SRCS:.rc=.h)
@MAKE_RULES@
#this line is needed to prevent winestub.o being linked
WINESTUB =
wcmd: $(OBJS)
$(CC) -o wcmd $(OBJS) $(LDOPTIONS) $(ALL_LIBS)
install: dummy
$(INSTALL_PROGRAM) wcmd $(bindir)/wcmd
uninstall: dummy
$(RM) $(bindir)/wcmd
$(RC_SRCS:.rc=.s): $(WRC)
dummy:
### Dependencies:

View File

@ -0,0 +1,50 @@
WCMD - A Command-Line Interface for WINE
Copyright (C) 1999 D Pickles (davep@nugate.demon.co.uk)
Open Source software published under the Wine Licence and Warranty.
This is an Alpha version and is very much "work in progress".
WHAT'S INCLUDED
- Sources
- A Makefile for compiling with LibWine. Build Wine with "-enable-dll" first.
- A Makefile for Borland C++ (needs editing for directories).
WHAT'S MISSING
- Redirection, shell parameters and pipes
- Command-line qualifiers for most builtin commands
- MOVE command (plus the batch-only ones)
- Wildcards and relative paths in COPY and RENAME
- Set functionality in DATE, TIME, ATTRIB, SET, LABEL
- Full internationalisation of the text (and commands?).
WHAT DOESN'T WORK
- At present it is not possible to launch Windows GDI programs from the command
line. This is result of the way the CreateProcess() API call is implemented in
Wine, and will be fixed in a later Wine release.
- The ATTRIB command reports all files having their Archive flag set, and the
READONLY setting depends on the Unix file permissions. All other flags are
always clear. The Wine attributes API calls map to the Unix stat() function
which cannot handle the other attributes available in DOS.
- Date/timestamps of files in the DIR listing are shown using the current
locale. As there is AFAIK no way to set the locale, they will always appear in
US format.
- Line editing and command recall doesn't work due to missing functionality in
Wine.
- File sizes in the DIR function are all given in 32 bits, though totals and
free space are computed to 64 bits.
- DIR/S fails if there is no matching file in the starting directory, ie
"DIR C:\TEMP\*.c /S" doesn't work if there is no file matching *.c in C:\TEMP
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
image. The Wine binary is simpler to invoke from the U**x command line or from
a GUI such as KDE, however it is not possible to invoke a second shell using the
"WCMD /C filename" syntax. Conversely a Win32 application can be invoked from a
Win32 GUI such as Program Manager but that needs starting under Wine first.

View File

@ -0,0 +1,179 @@
/*
* WCMD - Wine-compatible command line interface - batch interface.
*
* (C) 1999 D A Pickles
*
*/
#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);
extern HANDLE STDin, STDout;
extern char nyi[];
extern char newline[];
extern char version_string[];
extern int echo_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
/****************************************************************************
* WCMD_batch
*
* Open and execute a batch file.
* 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.
*
* We need to handle recursion correctly, since one batch program might call another.
*/
void WCMD_batch (char *file, char *command) {
HANDLE h;
char string[MAX_PATH];
int n;
strcpy (string, file);
CharLower (string);
if (strstr (string, ".bat") == NULL) strcat (string, ".bat");
h = CreateFile (string, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE) {
WCMD_output ("File %s not found\n", string);
return;
}
/*
* 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);
}
CloseHandle (h);
}
/****************************************************************************
* WCMD_batch_command
*
* Execute one line from a batch file.
*/
void WCMD_batch_command (HANDLE h, char *command) {
DWORD status;
char cmd[1024];
if (echo_mode && (command[0] != '@')) WCMD_output ("%s", command);
status = ExpandEnvironmentStrings (command, cmd, sizeof(cmd));
if (!status) {
WCMD_print_error ();
return;
}
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.
* Parameter is in static storage overwritten on the next call.
* Parameters in quotes are handled.
*/
char *WCMD_parameter (char *s, int n) {
int i = -1;
static char param[MAX_PATH];
char *p;
p = param;
while (TRUE) {
switch (*s) {
case ' ':
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:
while ((*s != '\0') && (*s != ' ')) {
*p++ = *s++;
}
if (i == n) {
*p = '\0';
return param;
}
else {
param[0] = '\0';
i++;
}
}
}
}
/****************************************************************************
* 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.
*/
char *WCMD_fgets (char *s, int n, HANDLE h) {
DWORD bytes;
BOOL status;
char *p;
p = s;
do {
status = ReadFile (h, s, 1, &bytes, NULL);
if ((status == 0) || (bytes == 0)) return NULL;
if (*s == '\n') bytes = 0;
*++s = '\0';
n--;
} while ((bytes == 1) && (n > 1));
return p;
}

View File

@ -0,0 +1,645 @@
/*
* WCMD - Wine-compatible command line interface - built-in functions.
*
* (C) 1999 D A Pickles
*
* On entry to each function, global variables quals, param1, param2 contain
* the qualifiers (uppercased and concatenated) and parameters entered, with
* environment-variable and batch parameter substitution already done.
*/
/*
* FIXME:
* - No support for redirection, pipes, batch files, shell parameters
* - 32-bit limit on file sizes in DIR command
* - Lots of functionality missing from builtins
* - Messages etc need international support
*/
#include "wcmd.h"
extern HANDLE STDin, STDout;
extern HINSTANCE hinst;
extern char *inbuilt[];
extern char nyi[];
extern char newline[];
extern char version_string[];
extern char anykey[];
extern int echo_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
/****************************************************************************
* WCMD_call
*
* Call another batch file.
*/
void WCMD_call () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_clear_screen
*
* Clear the terminal screen.
*/
void WCMD_clear_screen () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_change_tty
*
* Change the default i/o device (ie redirect STDin/STDout).
*/
void WCMD_change_tty () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_copy
*
* Copy a file or wildcarded set.
* FIXME: No wildcard support
* FIXME: Needs output file to be fully specified (can't just enter directory)
*/
void WCMD_copy () {
DWORD count;
WIN32_FIND_DATA fd;
HANDLE hff;
BOOL force, status;
static char *overwrite = "Overwrite file (Y/N)?";
char string[8], outpath[MAX_PATH];
if ((strchr(param1,'*') != NULL) && (strchr(param1,'%') != NULL)) {
WCMD_output ("Wildcards not yet supported\n");
return;
}
GetFullPathName (param2, sizeof(outpath), outpath, NULL);
force = (strstr (quals, "/Y") != NULL);
if (!force) {
hff = FindFirstFile (outpath, &fd);
if (hff != INVALID_HANDLE_VALUE) {
FindClose (hff);
WCMD_output (overwrite);
ReadFile (STDin, string, sizeof(string), &count, NULL);
if (toupper(string[0]) == 'Y') force = TRUE;
}
else force = TRUE;
}
if (force) {
status = CopyFile (param1, outpath, FALSE);
if (!status) WCMD_print_error ();
}
}
/****************************************************************************
* WCMD_create_dir
*
* Create a directory.
*/
void WCMD_create_dir () {
if (!CreateDirectory (param1, NULL)) WCMD_print_error ();
}
/****************************************************************************
* WCMD_delete
*
* Delete a file or wildcarded set.
*
*/
void WCMD_delete (int recurse) {
WIN32_FIND_DATA fd;
HANDLE hff;
char fpath[MAX_PATH];
char *p;
hff = FindFirstFile (param1, &fd);
if (hff == INVALID_HANDLE_VALUE) {
WCMD_output ("File Not Found\n");
return;
}
if ((strchr(param1,'*') == NULL) && (strchr(param1,'?') == NULL)
&& (!recurse) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
strcat (param1, "\\*");
WCMD_delete (1);
return;
}
if ((strchr(param1,'*') != NULL) || (strchr(param1,'?') != NULL)) {
strcpy (fpath, param1);
do {
p = strrchr (fpath, '\\');
if (p != NULL) {
*++p = '\0';
strcat (fpath, fd.cFileName);
}
else strcpy (fpath, fd.cFileName);
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (!DeleteFile (fpath)) WCMD_print_error ();
}
} while (FindNextFile(hff, &fd) != 0);
FindClose (hff);
}
else {
if (!DeleteFile (param1)) WCMD_print_error ();
}
}
/****************************************************************************
* WCMD_echo
*
* Echo input to the screen (or not). We don't try to emulate the bugs
* in DOS (try typing "ECHO ON AGAIN" for an example).
*/
void WCMD_echo (char *command) {
static char *eon = "Echo is ON\n", *eoff = "Echo is OFF\n";
int count;
count = strlen(command);
if (count == 0) {
if (echo_mode) WCMD_output (eon);
else WCMD_output (eoff);
return;
}
if ((count == 1) && (command[0] == '.')) {
WCMD_output (newline);
return;
}
if (lstrcmpi(command, "ON") == 0) {
echo_mode = 1;
return;
}
if (lstrcmpi(command, "OFF") == 0) {
echo_mode = 0;
return;
}
WCMD_output (command);
WCMD_output (newline);
}
/****************************************************************************
* WCMD_for
*
* Batch file loop processing.
*/
void WCMD_for () {
WCMD_output (nyi);
}
/**************************************************************************
* WCMD_give_help
*
* Simple on-line help. Help text is stored in the resource file.
*/
void WCMD_give_help (char *command) {
int i;
char buffer[2048];
command = WCMD_strtrim_leading_spaces(command);
if (lstrlen(command) == 0) {
LoadString (hinst, 1000, buffer, sizeof(buffer));
WCMD_output (buffer);
}
else {
for (i=0; i<=WCMD_EXIT; i++) {
if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
param1, -1, inbuilt[i], -1) == 2) {
LoadString (hinst, i, buffer, sizeof(buffer));
WCMD_output (buffer);
return;
}
}
WCMD_output ("No help available for %s\n", param1);
}
return;
}
/****************************************************************************
* WCMD_if
*
* Batch file conditional.
*/
void WCMD_if () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_move
*
* Move a file, directory tree or wildcarded set of files.
*/
void WCMD_move () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_pause
*
* Wait for keyboard input.
*/
void WCMD_pause () {
DWORD count;
char string[32];
WCMD_output (anykey);
ReadFile (STDin, string, sizeof(string), &count, NULL);
}
/****************************************************************************
* WCMD_remove_dir
*
* Delete a directory.
*/
void WCMD_remove_dir () {
if (!RemoveDirectory (param1)) WCMD_print_error ();
}
/****************************************************************************
* WCMD_rename
*
* Rename a file.
* FIXME: Needs input and output files to be fully specified.
*/
void WCMD_rename () {
int status;
static char *dirmsg = "Input file is a directory. Use the MOVE command\n\n";
if ((strchr(param1,'*') != NULL) || (strchr(param1,'%') != NULL)) {
WCMD_output ("Wildcards not yet supported\n");
return;
}
status = GetFileAttributes (param1);
if ((status != -1) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
WCMD_output (dirmsg);
return;
}
status = MoveFile (param1, param2);
if (!status) WCMD_print_error ();
}
/*****************************************************************************
* WCMD_setshow_attrib
*
* Display and optionally sets DOS attributes on a file or directory
*
* FIXME: Wine currently uses the Unix stat() function to get file attributes.
* As a result only the Readonly flag is correctly reported, the Archive bit
* is always set and the rest are not implemented. We do the Right Thing anyway.
*
*/
void WCMD_setshow_attrib () {
DWORD count;
HANDLE hff;
WIN32_FIND_DATA fd;
char flags[9] = {" "};
if (lstrlen(param1) == 0) {
GetCurrentDirectory (sizeof(param1), param1);
strcat (param1, "\\*");
}
hff = FindFirstFile (param1, &fd);
if (hff == INVALID_HANDLE_VALUE) {
WCMD_output ("File Not Found\n");
}
else {
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
flags[0] = 'H';
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
flags[1] = 'S';
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
flags[2] = 'A';
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
flags[3] = 'R';
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
flags[4] = 'T';
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
flags[5] = 'C';
}
WCMD_output ("%s %s\n", flags, fd.cFileName);
for (count=0; count < 8; count++) flags[count] = ' ';
}
} while (FindNextFile(hff, &fd) != 0);
}
FindClose (hff);
}
/*****************************************************************************
* WCMD_setshow_default
*
* Set/Show the current default directory
*/
void WCMD_setshow_default () {
BOOL status;
char string[1024];
if (strlen(param1) == 0) {
GetCurrentDirectory (sizeof(string), string);
strcat (string, "\n");
WCMD_output (string);
}
else {
status = SetCurrentDirectory (param1);
if (!status) {
WCMD_print_error ();
return;
}
}
return;
}
/****************************************************************************
* WCMD_setshow_date
*
* Set/Show the system date
* FIXME: Can't change date yet
*/
void WCMD_setshow_date () {
char curdate[64], buffer[64];
DWORD count;
if (lstrlen(param1) == 0) {
if (GetDateFormat (LOCALE_USER_DEFAULT, 0, NULL, NULL,
curdate, sizeof(curdate))) {
WCMD_output ("Current Date is %s\nEnter new date: ", curdate);
ReadFile (STDin, buffer, sizeof(buffer), &count, NULL);
if (count > 2) {
WCMD_output (nyi);
}
}
else WCMD_print_error ();
}
else {
WCMD_output (nyi);
}
}
/****************************************************************************
* WCMD_setshow_env
*
* Set/Show the environment variables
*
* FIXME: need to sort variables into order for display?
*/
void WCMD_setshow_env (char *s) {
LPVOID env;
char *p;
int status;
if (strlen(param1) == 0) {
env = GetEnvironmentStrings ();
p = (char *) env;
while (*p) {
WCMD_output ("%s\n", p);
p += lstrlen(p) + 1;
}
}
else {
p = strchr (s, '=');
if (p == NULL) {
WCMD_output ("Command Syntax: SET variable=value\n");
return;
}
*p++ = '\0';
status = SetEnvironmentVariable (s, p);
if (!status) WCMD_print_error();
}
WCMD_output (newline);
}
/****************************************************************************
* WCMD_setshow_path
*
* Set/Show the path environment variable
*/
void WCMD_setshow_path () {
char string[1024];
DWORD status;
if (strlen(param1) == 0) {
status = GetEnvironmentVariable ("PATH", string, sizeof(string));
if (status != 0) {
WCMD_output ("PATH=%s\n", string);
}
else {
WCMD_output ("PATH not found\n");
}
}
else {
status = SetEnvironmentVariable ("PATH", param1);
if (!status) WCMD_print_error();
}
}
/****************************************************************************
* WCMD_setshow_prompt
*
* Set or show the command prompt.
*/
void WCMD_setshow_prompt () {
char *s;
if (strlen(param1) == 0) {
SetEnvironmentVariable ("PROMPT", NULL);
}
else {
s = param1;
while ((*s == '=') || (*s == ' ')) s++;
if (strlen(s) == 0) {
SetEnvironmentVariable ("PROMPT", NULL);
}
else SetEnvironmentVariable ("PROMPT", s);
}
}
/****************************************************************************
* WCMD_setshow_time
*
* Set/Show the system time
* FIXME: Can't change time yet
*/
void WCMD_setshow_time () {
char curtime[64], buffer[64];
DWORD count;
if (strlen(param1) == 0) {
if (GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, NULL,
curtime, sizeof(curtime))) {
WCMD_output ("Current Time is %s\nEnter new time: ", curtime);
ReadFile (STDin, buffer, sizeof(buffer), &count, NULL);
if (count > 2) {
WCMD_output (nyi);
}
}
else WCMD_print_error ();
}
else {
WCMD_output (nyi);
}
}
/****************************************************************************
* WCMD_shift
*
* Shift batch parameters.
*/
void WCMD_shift () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_type
*
* Copy a file to standard output.
*/
void WCMD_type () {
HANDLE h;
char buffer[512];
DWORD count;
h = CreateFile (param1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE) {
WCMD_print_error ();
return;
}
while (ReadFile (h, buffer, sizeof(buffer), &count, NULL)) {
if (count == 0) break; /* ReadFile reports success on EOF! */
WriteFile (STDout, buffer, count, &count, NULL);
}
CloseHandle (h);
}
/****************************************************************************
* WCMD_verify
*
* Display verify flag.
*/
void WCMD_verify () {
WCMD_output (nyi);
}
/****************************************************************************
* WCMD_version
*
* Display version info.
*/
void WCMD_version () {
WCMD_output (version_string);
}
/****************************************************************************
* WCMD_volume
*
* Display volume info and/or set volume label. Returns 0 if error.
*/
int WCMD_volume (int mode, char *path) {
DWORD count, serial;
char string[MAX_PATH], label[MAX_PATH], curdir[MAX_PATH];
BOOL status;
static char syntax[] = "Syntax Error\n\n";
if (lstrlen(path) == 0) {
status = GetCurrentDirectory (sizeof(curdir), curdir);
if (!status) {
WCMD_print_error ();
return 0;
}
status = GetVolumeInformation (NULL, label, sizeof(label), &serial, NULL,
NULL, NULL, 0);
}
else {
if ((path[1] != ':') || (lstrlen(path) != 2)) {
WriteFile (STDout, syntax, strlen(syntax), &count, NULL);
return 0;
}
wsprintf (curdir, "%s\\", path);
status = GetVolumeInformation (curdir, label, sizeof(label), &serial, NULL,
NULL, NULL, 0);
}
if (!status) {
WCMD_print_error ();
return 0;
}
WCMD_output ("Volume in drive %c is %s\nVolume Serial Number is %04x-%04x\n\n",
curdir[0], label, HIWORD(serial), LOWORD(serial));
if (mode) {
WCMD_output ("Volume label (11 characters, ENTER for none)?");
ReadFile (STDin, string, sizeof(string), &count, NULL);
if (lstrlen(path) != 0) {
if (!SetVolumeLabel (curdir, string)) WCMD_print_error ();
}
else {
if (!SetVolumeLabel (NULL, string)) WCMD_print_error ();
}
}
return 1;
}

View File

@ -0,0 +1,301 @@
/*
* WCMD - Wine-compatible command line interface - Directory functions.
*
* (C) 1999 D A Pickles
*
* On entry, global variables quals, param1, param2 contain
* the qualifiers (uppercased and concatenated) and parameters entered, with
* environment-variable and batch parameter substitution already done.
*/
/*
* FIXME:
* - 32-bit limit on individual file sizes (directories and free space are 64-bit)
* - DIR /S fails if the starting directory is not the current default.
*/
#include "wcmd.h"
int WCMD_dir_sort (const void *a, const void *b);
void WCMD_list_directory (char *path, int level);
char * WCMD_filesize64 (__int64 n);
char * WCMD_filesize32 (int n);
char * WCMD_strrev (char *buff);
extern HANDLE STDin, STDout;
extern char nyi[];
extern char newline[];
extern char version_string[];
extern char anykey[];
extern int echo_mode;
extern char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
int file_total, dir_total, line_count, page_mode, recurse;
__int64 byte_total;
/*****************************************************************************
* WCMD_directory
*
* List a file directory.
* FIXME: /S switch only works for the current directory
*
*/
void WCMD_directory () {
char path[MAX_PATH], drive[8];
int status;
__int64 free_space;
DWORD spc, bps, fc, capacity;
line_count = 5;
page_mode = (strstr(quals, "/P") != NULL);
recurse = (strstr(quals, "/S") != NULL);
if (param1[0] == '\0') strcpy (param1, ".");
GetFullPathName (param1, sizeof(path), path, NULL);
lstrcpyn (drive, path, 3);
status = WCMD_volume (0, drive);
if (!status) {
return;
}
WCMD_list_directory (path, 0);
lstrcpyn (drive, path, 4);
GetDiskFreeSpace (drive, &spc, &bps, &fc, &capacity);
free_space = bps * spc * fc;
WCMD_output (" %18s bytes free\n\n", WCMD_filesize64 (free_space));
if (recurse) {
WCMD_output ("Total files listed:\n%8d files%25s bytes\n%8d directories\n\n",
file_total, WCMD_filesize64 (byte_total), dir_total);
}
}
/*****************************************************************************
* WCMD_list_directory
*
* List a single file directory. This function (and those below it) can be called
* recursively when the /S switch is used.
*
* FIXME: Assumes individual files are less than 2**32 bytes.
* FIXME: Entries sorted by name only. Should we support DIRCMD??
* FIXME: Assumes 24-line display for the /P qualifier.
* FIXME: Other command qualifiers not supported.
* FIXME: DIR /S FILENAME fails if at least one matching file is not found in the top level.
*/
void WCMD_list_directory (char *search_path, int level) {
char string[1024], datestring[32], timestring[32];
char mem_err[] = "Memory Allocation Error";
char *p;
DWORD count;
WIN32_FIND_DATA *fd;
FILETIME ft;
SYSTEMTIME st;
HANDLE hff;
int status, dir_count, file_count, entry_count, i;
__int64 byte_count;
dir_count = 0;
file_count = 0;
entry_count = 0;
byte_count = 0;
/*
* If the path supplied does not include a wildcard, and the endpoint of the
* path references a directory, we need to list the *contents* of that
* directory not the directory file itself.
*/
if ((strchr(search_path, '*') == NULL) && (strchr(search_path, '%') == NULL)) {
status = GetFileAttributes (search_path);
if ((status != -1) && (status & FILE_ATTRIBUTE_DIRECTORY)) {
if (search_path[strlen(search_path)-1] == '\\') {
strcat (search_path, "*");
}
else {
strcat (search_path, "\\*");
}
}
}
fd = malloc (sizeof(WIN32_FIND_DATA));
hff = FindFirstFile (search_path, fd);
if (hff == INVALID_HANDLE_VALUE) {
WCMD_output ("File Not Found\n");
free (fd);
return;
}
do {
entry_count++;
fd = realloc (fd, (entry_count+1)*sizeof(WIN32_FIND_DATA));
if (fd == NULL) {
FindClose (hff);
WCMD_output (mem_err);
return;
}
} while (FindNextFile(hff, (fd+entry_count)) != 0);
FindClose (hff);
qsort (fd, entry_count, sizeof(WIN32_FIND_DATA), WCMD_dir_sort);
if (level != 0) WCMD_output ("\n\n");
WCMD_output ("Directory of %s\n\n", search_path);
if (page_mode) {
line_count += 2;
if (line_count > 23) {
line_count = 0;
WCMD_output (anykey);
ReadFile (STDin, string, sizeof(string), &count, NULL);
}
}
for (i=0; i<entry_count; i++) {
FileTimeToLocalFileTime (&(fd+i)->ftLastWriteTime, &ft);
FileTimeToSystemTime (&ft, &st);
GetDateFormat (0, DATE_SHORTDATE, &st, NULL, datestring,
sizeof(datestring));
GetTimeFormat (0, TIME_NOSECONDS, &st,
NULL, timestring, sizeof(timestring));
if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
dir_count++;
WCMD_output ("%8s %8s <DIR> %s\n",
datestring, timestring, (fd+i)->cFileName);
}
else {
file_count++;
byte_count += (fd+i)->nFileSizeLow;
WCMD_output ("%8s %8s %10s %s\n",
datestring, timestring,
WCMD_filesize32((fd+i)->nFileSizeLow), (fd+i)->cFileName);
}
if (page_mode) {
if (++line_count > 23) {
line_count = 0;
WCMD_output (anykey);
ReadFile (STDin, string, sizeof(string), &count, NULL);
}
}
}
if (file_count == 1) {
WCMD_output (" 1 file %25s bytes\n", WCMD_filesize64 (byte_count));
}
else {
WCMD_output ("%8d files %24s bytes\n", file_count, WCMD_filesize64 (byte_count));
}
if (page_mode) {
if (++line_count > 23) {
line_count = 0;
WCMD_output (anykey);
ReadFile (STDin, string, sizeof(string), &count, NULL);
}
}
byte_total = byte_total + byte_count;
file_total = file_total + file_count;
dir_total = dir_total + dir_count;
if (dir_count == 1) WCMD_output ("1 directory ");
else WCMD_output ("%8d directories", dir_count);
if (page_mode) {
if (++line_count > 23) {
line_count = 0;
WCMD_output (anykey);
ReadFile (STDin, string, sizeof(string), &count, NULL);
}
}
for (i=0; i<entry_count; i++) {
if ((recurse) &&
((fd+i)->cFileName[0] != '.') &&
((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
// GetFullPathName ((fd+i)->cFileName, sizeof(string), string, NULL);
p = strrchr (search_path, '\\');
lstrcpyn (string, search_path, (p-search_path+2));
lstrcat (string, (fd+i)->cFileName);
lstrcat (string, p);
WCMD_list_directory (string, 1);
}
}
free (fd);
return;
}
/*****************************************************************************
* WCMD_filesize64
*
* Convert a 64-bit number into a character string, with commas every three digits.
* Result is returned in a static string overwritten with each call.
* FIXME: There must be a better algorithm!
*/
char * WCMD_filesize64 (__int64 n) {
__int64 q;
int r, i;
char *p;
static char buff[32];
p = buff;
i = -3;
do {
if ((++i)%3 == 1) *p++ = ',';
q = n / 10;
r = n - (q * 10);
*p++ = r + '0';
*p = '\0';
n = q;
} while (n != 0);
WCMD_strrev (buff);
return buff;
}
/*****************************************************************************
* WCMD_filesize32
*
* Convert a 32-bit number into a character string, with commas every three digits.
* Result is returned in a static string overwritten with each call.
* FIXME: There must be a better algorithm!
*/
char * WCMD_filesize32 (int n) {
int r, i;
char *p, *q;
static char buff1[16], buff2[16];
wsprintf (buff1, "%i", n);
r = lstrlen (buff1);
WCMD_strrev (buff1);
p = buff1;
q = buff2;
for (i=0; i<r; i++) {
if ((i-2)%3 == 1) *q++ = ',';
*q++ = *p++;
}
*q = '\0';
WCMD_strrev (buff2);
return buff2;
}
/*****************************************************************************
* WCMD_strrev
*
* Reverse a character string in-place (strrev() is not available under unixen :-( ).
*/
char * WCMD_strrev (char *buff) {
int r, i;
char b;
r = lstrlen (buff);
for (i=0; i<r/2; i++) {
b = buff[i];
buff[i] = buff[r-i-1];
buff[r-i-1] = b;
}
return (buff);
}
int WCMD_dir_sort (const void *a, const void *b) {
return (lstrcmpi(((WIN32_FIND_DATA *)a)->cFileName,
((WIN32_FIND_DATA *)b)->cFileName));
}

View File

@ -0,0 +1,47 @@
#-----------------------------------------------------------------------------
VERSION = BCB.01
#-----------------------------------------------------------------------------
!ifndef BCB
BCB = $(MAKEDIR)\..
!endif
PROJECT = wcmd.exe
OBJFILES = builtins.obj wcmdmain.obj directory.obj batch.obj
RESFILES = wcmdrc.rc
RESDEPEN = $(RESFILES)
LIBFILES =
DEFFILE =
#-----------------------------------------------------------------------------
CFLAG1 = -c
CFLAG2 = -H=C:\BC\PROJECTS\CMD.CSM -nC:\BC\PROJECTS\CMD \
-IC:\BC\INCLUDE;C:\BC\PROJECTS\CMD
PFLAGS = -U$(BCB)\lib\obj -jph -m
RFLAGS = -I$(BCB)\include;C:\BC\INCLUDE;C:\BC\PROJECTS\CMD
LFLAGS = -ap -Tpe -c -x -L$(BCB)\lib;$(BCB)\lib\obj;C:\BC\LIB
IFLAGS = -i
LINKER = tlink32
#-----------------------------------------------------------------------------
ALLOBJ = c0x32.obj $(OBJFILES)
ALLRES = $(RESFILES)
ALLLIB = $(LIBFILES) noeh32.lib import32.lib cw32mt.lib
# ---------------------------------------------------------------------------
.autodepend
$(PROJECT): $(OBJFILES) $(RESDEPEN) $(DEFFILE)
$(BCB)\BIN\$(LINKER) @&&!
$(LFLAGS) +
$(ALLOBJ), +
$(PROJECT),, +
$(ALLLIB), +
$(DEFFILE), +
$(ALLRES)
!
.cpp.obj:
$(BCB)\BIN\bcc32 $(CFLAG1) $(CFLAG2) -o$* $*
.c.obj:
$(BCB)\BIN\bcc32 $(CFLAG1) $(CFLAG2) -o$* $**
.rc.res:
$(BCB)\BIN\brcc32 $(RFLAGS) $<
#-----------------------------------------------------------------------------

View File

@ -0,0 +1,108 @@
/*
* WCMD - Wine-compatible command line interface.
*
* (C) 1999 D A Pickles
*/
#define IDI_ICON1 1
#include <windows.h>
#ifndef RC_INVOKED
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#ifdef WINELIB
#include <winbase.h>
#include <wincon.h>
#endif /* !WINELIB */
void WCMD_batch (char *, char *);
void WCMD_call (void);
void WCMD_change_tty (void);
void WCMD_clear_screen (void);
void WCMD_copy (void);
void WCMD_create_dir (void);
void WCMD_delete (int recurse);
void WCMD_directory (void);
void WCMD_echo (char *);
void WCMD_for (void);
void WCMD_give_help (char *command);
void WCMD_if (void);
void WCMD_move (void);
void WCMD_output (char *format, ...);
void WCMD_parse (char *s, char *q, char *p1, char *p2);
void WCMD_pause (void);
void WCMD_print_error (void);
void WCMD_process_command (char *command);
void WCMD_remove_dir (void);
void WCMD_rename (void);
void WCMD_run_program (char *command);
void WCMD_setshow_attrib (void);
void WCMD_setshow_date (void);
void WCMD_setshow_default (void);
void WCMD_setshow_env (char *command);
void WCMD_setshow_path (void);
void WCMD_setshow_prompt (void);
void WCMD_setshow_time (void);
void WCMD_shift (void);
void WCMD_show_prompt (void);
void WCMD_type (void);
void WCMD_verify (void);
void WCMD_version (void);
int WCMD_volume (int mode, char *command);
char *WCMD_fgets (char *s, int n, HANDLE stream);
char *WCMD_strtrim_leading_spaces (char *string);
void WCMD_strtrim_trailing_spaces (char *string);
#endif /* !RC_INVOKED */
/*
* Serial nos of builtin commands. These constants must be in step with
* the list of strings defined in WCMD.C, and WCMD_EXIT *must* always be
* the last one.
*
* Yes it *would* be nice to use an enumeration here, but the Resource
* Compiler won't accept resource IDs from enumerations :-(
*/
#define WCMD_ATTRIB 0
#define WCMD_CALL 1
#define WCMD_CD 2
#define WCMD_CHDIR 3
#define WCMD_CLS 4
#define WCMD_COPY 5
#define WCMD_CTTY 6
#define WCMD_DATE 7
#define WCMD_DEL 8
#define WCMD_DIR 9
#define WCMD_ECHO 10
#define WCMD_ERASE 11
#define WCMD_FOR 12
#define WCMD_GOTO 13
#define WCMD_HELP 14
#define WCMD_IF 15
#define WCMD_LABEL 16
#define WCMD_MD 17
#define WCMD_MKDIR 18
#define WCMD_MOVE 19
#define WCMD_PATH 20
#define WCMD_PAUSE 21
#define WCMD_PROMPT 22
#define WCMD_REM 23
#define WCMD_REN 24
#define WCMD_RENAME 25
#define WCMD_RD 26
#define WCMD_RMDIR 27
#define WCMD_SET 28
#define WCMD_SHIFT 29
#define WCMD_TIME 30
#define WCMD_TYPE 31
#define WCMD_VERIFY 32
#define WCMD_VER 33
#define WCMD_VOL 34
#define WCMD_EXIT 35

View File

@ -0,0 +1,556 @@
/*
* WCMD - Wine-compatible command line interface.
*
* (C) 1999 D A Pickles
*/
/*
* FIXME:
* - No support for redirection, pipes, batch commands
* - 32-bit limit on file sizes in DIR command
* - Cannot handle parameters in quotes
* - Lots of functionality missing from builtins
*/
#include "wcmd.h"
#ifdef WINELIB
/* external declaration here because we don't want to depend on Wine headers */
#ifdef __cplusplus
extern "C" HINSTANCE MAIN_WinelibInit( int *argc, char *argv[] );
#else
extern HINSTANCE MAIN_WinelibInit( int *argc, char *argv[] );
#endif
#endif /* WINELIB */
char *inbuilt[] = {"ATTRIB", "CALL", "CD", "CHDIR", "CLS", "COPY", "CTTY",
"DATE", "DEL", "DIR", "ECHO", "ERASE", "FOR", "GOTO",
"HELP", "IF", "LABEL", "MD", "MKDIR", "MOVE", "PATH", "PAUSE",
"PROMPT", "REM", "REN", "RENAME", "RD", "RMDIR", "SET", "SHIFT",
"TIME", "TYPE", "VERIFY", "VER", "VOL", "EXIT"};
HANDLE STDin, STDout;
HINSTANCE hinst;
int echo_mode = 1;
char nyi[] = "Not Yet Implemented\n\n";
char newline[] = "\n";
char version_string[] = "WCMD Version 0.10\n\n";
char anykey[] = "Press any key to continue: ";
char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
/*****************************************************************************
* Main entry point. This is a console application so we have a main() not a
* winmain().
*/
int main (int argc, char *argv[]) {
char string[1024], args[MAX_PATH], param[MAX_PATH];
int status, i;
DWORD count;
HANDLE h;
#ifdef WINELIB
if (!(hinst = MAIN_WinelibInit( &argc, argv ))) return 0;
#else
hinst = 0;
#endif
args[0] = param[0] = '\0';
if (argc > 1) {
for (i=1; i<argc; i++) {
if (argv[i][0] == '/') {
strcat (args, argv[i]);
}
else {
strcat (param, argv[i]);
strcat (param, " ");
}
}
}
/*
* Allocate a console and set it up.
*/
status = FreeConsole ();
if (!status) WCMD_print_error();
status = AllocConsole();
if (!status) WCMD_print_error();
STDout = GetStdHandle (STD_OUTPUT_HANDLE);
STDin = GetStdHandle (STD_INPUT_HANDLE);
SetConsoleMode (STDin, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
ENABLE_PROCESSED_INPUT);
/*
* Execute any command-line options.
*/
if (strstr(args, "/q") != NULL) {
WCMD_echo ("OFF");
}
if (strstr(args, "/c") != NULL) {
WCMD_process_command (param);
return 0;
}
if (strstr(args, "/k") != NULL) {
WCMD_process_command (param);
}
/*
* If there is an AUTOEXEC.BAT file, try to execute it.
*/
GetFullPathName ("\\autoexec.bat", sizeof(string), string, NULL);
h = CreateFile (string, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle (h);
// WCMD_batch (string, " ");
}
/*
* Loop forever getting commands and executing them.
*/
WCMD_version ();
while (TRUE) {
WCMD_show_prompt ();
ReadFile (STDin, string, sizeof(string), &count, NULL);
if (count > 1) {
string[count-1] = '\0'; /* ReadFile output is not null-terminated! */
if (string[count-2] == '\r') string[count-2] = '\0'; /* Under Windoze we get CRLF! */
if (lstrlen (string) != 0) {
WCMD_process_command (string);
}
}
}
}
/*****************************************************************************
* Process one command. If the command is EXIT this routine does not return.
* We will recurse through here executing batch files.
*/
void WCMD_process_command (char *command) {
char cmd[1024];
char *p;
int status, i;
DWORD count;
/*
* Throw away constructs we don't support yet
*/
if ((strchr(command,'<') != NULL) || (strchr(command,'>') != NULL)) {
WCMD_output ("Redirection not yet implemented\n");
return;
}
if (strchr(command,'|') != NULL) {
WCMD_output ("Pipes not yet implemented\n");
return;
}
/*
* Expand up environment variables.
*/
status = ExpandEnvironmentStrings (command, cmd, sizeof(cmd));
if (!status) {
WCMD_print_error ();
return;
}
/*
* Changing default drive has to be handled as a special case.
*/
if ((cmd[1] == ':') && IsCharAlpha (cmd[0]) && (strlen(cmd) == 2)) {
status = SetCurrentDirectory (cmd);
if (!status) WCMD_print_error ();
return;
}
WCMD_output (newline);
/*
* Check if the command entered is internal. If it is, pass the rest of the
* line down to the command. If not try to run a program.
*/
count = 0;
while (IsCharAlphaNumeric(cmd[count])) {
count++;
}
for (i=0; i<=WCMD_EXIT; i++) {
if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
cmd, count, inbuilt[i], -1) == 2) break;
}
p = WCMD_strtrim_leading_spaces (&cmd[count]);
WCMD_parse (p, quals, param1, param2);
switch (i) {
case WCMD_ATTRIB:
WCMD_setshow_attrib ();
break;
case WCMD_CALL:
WCMD_batch (param1, p);
break;
case WCMD_CD:
case WCMD_CHDIR:
WCMD_setshow_default ();
break;
case WCMD_CLS:
WCMD_clear_screen ();
break;
case WCMD_COPY:
WCMD_copy ();
break;
case WCMD_CTTY:
WCMD_change_tty ();
break;
case WCMD_DATE:
WCMD_setshow_date ();
break;
case WCMD_DEL:
case WCMD_ERASE:
WCMD_delete (0);
break;
case WCMD_DIR:
WCMD_directory ();
break;
case WCMD_ECHO:
WCMD_echo (p);
break;
case WCMD_FOR:
WCMD_for ();
break;
case WCMD_GOTO:
break;
case WCMD_HELP:
WCMD_give_help (p);
break;
case WCMD_IF:
WCMD_if ();
break;
case WCMD_LABEL:
WCMD_volume (1, p);
break;
case WCMD_MD:
case WCMD_MKDIR:
WCMD_create_dir ();
break;
case WCMD_MOVE:
WCMD_move ();
break;
case WCMD_PATH:
WCMD_setshow_path ();
break;
case WCMD_PAUSE:
WCMD_pause ();
break;
case WCMD_PROMPT:
WCMD_setshow_prompt ();
break;
case WCMD_REM:
break;
case WCMD_REN:
case WCMD_RENAME:
WCMD_rename ();
break;
case WCMD_RD:
case WCMD_RMDIR:
WCMD_remove_dir ();
break;
case WCMD_SET:
WCMD_setshow_env (p);
break;
case WCMD_SHIFT:
WCMD_shift ();
break;
case WCMD_TIME:
WCMD_setshow_time ();
break;
case WCMD_TYPE:
WCMD_type ();
break;
case WCMD_VER:
WCMD_version ();
break;
case WCMD_VERIFY:
WCMD_verify ();
break;
case WCMD_VOL:
WCMD_volume (0, p);
break;
case WCMD_EXIT:
ExitProcess (0);
default:
WCMD_run_program (cmd);
};
}
/******************************************************************************
* WCMD_run_program
*
* Execute a command line as an external program. If no extension given then
* precedence is given to .BAT files. Must allow recursion.
*
* FIXME: Case sensitivity in suffixes!
*/
void WCMD_run_program (char *command) {
STARTUPINFO st;
PROCESS_INFORMATION pe;
BOOL status;
HANDLE h;
char filetorun[MAX_PATH];
WCMD_parse (command, quals, param1, param2); /* Quick way to get the filename */
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);
return;
}
}
}
else { /* Explicit path given */
if (strstr (param1, ".bat") != NULL) {
WCMD_batch (param1, command);
return;
}
if (strchr (param1, '.') == NULL) {
strcpy (filetorun, param1);
strcat (filetorun, ".bat");
h = CreateFile (filetorun, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle (h);
WCMD_batch (param1, command);
return;
}
}
}
/* No batch file found, assume executable */
ZeroMemory (&st, sizeof(STARTUPINFO));
st.cb = sizeof(STARTUPINFO);
status = CreateProcess (NULL, command, NULL, NULL, FALSE,
0, NULL, NULL, &st, &pe);
if (!status) {
WCMD_print_error ();
}
}
/******************************************************************************
* WCMD_show_prompt
*
* Display the prompt on STDout
*
*/
void WCMD_show_prompt () {
int status;
char out_string[MAX_PATH], curdir[MAX_PATH], prompt_string[MAX_PATH];
char *p, *q;
status = GetEnvironmentVariable ("PROMPT", prompt_string, sizeof(prompt_string));
if ((status == 0) || (status > sizeof(prompt_string))) {
lstrcpy (prompt_string, "$N$G");
}
p = prompt_string;
q = out_string;
*q = '\0';
while (*p != '\0') {
if (*p != '$') {
*q++ = *p++;
*q = '\0';
}
else {
p++;
switch (toupper(*p)) {
case '$':
*q++ = '$';
break;
case 'B':
*q++ = '|';
break;
case 'D':
GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, q, MAX_PATH);
while (*q) q++;
break;
case 'E':
*q++ = '\E';
break;
case 'G':
*q++ = '>';
break;
case 'L':
*q++ = '<';
break;
case 'N':
status = GetCurrentDirectory (sizeof(curdir), curdir);
if (status) {
*q++ = curdir[0];
}
break;
case 'P':
status = GetCurrentDirectory (sizeof(curdir), curdir);
if (status) {
lstrcat (q, curdir);
while (*q) q++;
}
break;
case 'Q':
*q++ = '=';
break;
case 'T':
GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, NULL, q, MAX_PATH);
while (*q) q++;
break;
case '_':
*q++ = '\n';
break;
}
p++;
*q = '\0';
}
}
WCMD_output (out_string);
}
/****************************************************************************
* WCMD_print_error
*
* Print the message for GetLastError - not much use yet as Wine doesn't have
* the messages available, so we show meaningful messages for the most likely.
*/
void WCMD_print_error () {
LPVOID lpMsgBuf;
DWORD error_code;
error_code = GetLastError ();
switch (error_code) {
case ERROR_FILE_NOT_FOUND:
WCMD_output ("File Not Found\n");
break;
case ERROR_PATH_NOT_FOUND:
WCMD_output ("Path Not Found\n");
break;
default:
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error_code,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
WCMD_output (lpMsgBuf);
LocalFree ((HLOCAL)lpMsgBuf);
}
return;
}
/*******************************************************************
* WCMD_parse - parse a command into parameters and qualifiers.
*
* On exit, all qualifiers are concatenated into q, the first string
* not beginning with "/" is in p1 and the
* second in p2. Any subsequent non-qualifier strings are lost.
* Parameters in quotes are handled.
*/
void WCMD_parse (char *s, char *q, char *p1, char *p2) {
int p = 0;
*q = *p1 = *p2 = '\0';
while (TRUE) {
switch (*s) {
case '/':
*q++ = *s++;
while ((*s != '\0') && (*s != ' ') && *s != '/') {
*q++ = toupper (*s++);
}
*q = '\0';
break;
case ' ':
s++;
break;
case '"':
s++;
while ((*s != '\0') && (*s != '"')) {
if (p == 0) *p1++ = *s++;
else if (p == 1) *p2++ = *s++;
else s++;
}
if (p == 0) *p1 = '\0';
if (p == 1) *p2 = '\0';
p++;
if (*s == '"') s++;
break;
case '\0':
return;
default:
while ((*s != '\0') && (*s != ' ') && (*s != '/')) {
if (p == 0) *p1++ = *s++;
else if (p == 1) *p2++ = *s++;
else s++;
}
if (p == 0) *p1 = '\0';
if (p == 1) *p2 = '\0';
p++;
}
}
}
/*******************************************************************
* WCMD_output - send output to current standard output device.
*
*/
void WCMD_output (char *format, ...) {
va_list ap;
char string[1024];
DWORD count;
va_start(ap,format);
vsprintf (string, format, ap);
WriteFile (STDout, string, lstrlen(string), &count, NULL);
va_end(ap);
}
/* Remove leading spaces from a string. Return a pointer to the first
* non-space character. Does not modify the input string
*/
char *WCMD_strtrim_leading_spaces (char *string) {
char *ptr;
ptr = string;
while (*ptr == ' ') ptr++;
return ptr;
}
/* Remove trailing spaces from a string. This routine modifies the input
* string by placing a null after the last non-space character
*/
void WCMD_strtrim_trailing_spaces (char *string) {
char *ptr;
ptr = string + lstrlen (string) - 1;
while ((*ptr == ' ') && (ptr >= string)) {
*ptr = '\0';
ptr--;
}
}

View File

@ -0,0 +1,294 @@
#include "wcmd.h"
STRINGTABLE
{
WCMD_ATTRIB, "Help about ATTRIB\n"
WCMD_CALL, "Help about CALL\n"
WCMD_CD, "Help about CD\n"
WCMD_CHDIR, "Help about CHDIR\n"
WCMD_CLS,
"CLS clears the console screen\n"
WCMD_COPY, "Help about COPY\n"
WCMD_CTTY, "Help about CTTY\n"
WCMD_DATE, "Help about DATE\n"
WCMD_DEL, "Help about DEL\n"
WCMD_DIR, "Help about DIR\n"
WCMD_ECHO,
"ECHO <string> displays <string> on the current terminal device.\
\
ECHO ON causes all subsequent commands in a batch file to be displayed\
on the terminal device before they are executed.\
\
ECHO OFF reverses the effect of a previous ECHO ON (ECHO is OFF by\
default). The ECHO OFF command can be prevented from displaying by\
preceding it with an @ sign.\n"
WCMD_ERASE, "Help about ERASE\n"
WCMD_FOR, "Help about FOR\n"
WCMD_GOTO, "Help about GOTO\n"
WCMD_HELP, "Help about HELP\n"
WCMD_IF, "Help about IF\n"
WCMD_LABEL, "Help about LABEL\n"
WCMD_MD, "Help about MD\n"
WCMD_MKDIR, "Help about MKDIR\n"
WCMD_MOVE, "Help about MOVE\n"
WCMD_PATH,
"PATH displays or changes the wcmd search path. \
\
Entering PATH will display the current PATH setting (initially this is \
the value given in your wine.conf file). To change the setting follow the \
PATH command with the new value. \
\
It is also possible to modify the PATH by using the PATH environment \
variable, for example: \
PATH %PATH%;c:\\temp \n"
WCMD_PAUSE,
"PAUSE displays a message on the screen 'Press Return key to continue'\
and waits for the user to press the Return key. It is mainly useful in\
batch files to allow the user to read the output of a previous command\
before it scrolls off the screen.\n"
WCMD_PROMPT,
"PROMPT sets the command-line prompt.\
\
The string following the PROMPT command (and the space immediately after)\
appears at the beginning of the line when wcmd is waiting for input.\
\
The following character strings have the special meaning shown:\
\
$$ Dollar sign $_ Linefeed $b Pipe sign (|)\
$d Current date $e Escape $g > sign\
$l > sign $n Current drive $p Current path\
$q Equal sign $t Current time $v wcmd version\
\
Note that entering the PROMPT command without a prompt-string resets the\
prompt to the default, which is the current drive letter followed by a\
greater-than (>) sign.\
\
The prompt can also be changed by altering the PROMPT environment variable,\
so the command 'SET PROMPT=text' has the same effect as 'PROMPT text'\n"
WCMD_REM,
"A command line beginning REM (followed by a space) performs no\
action, and can therefore be used as a comment in a batch file.\n"
WCMD_REN, "Help about REN\n"
WCMD_RENAME, "Help about RENAME\n"
WCMD_RD, "Help about RD\n"
WCMD_RMDIR, "Help about RMDIR\n"
WCMD_SET,
"SET displays or changes the wcmd environment variables.\
\
SET without parameters shows all of the current environment.\
\
To create or modify an environment variable the syntax is:\
\
SET <variable>=<value>\
\
where <variable> and <value> are character strings. There must be no\
spaces either side of the equals sign, nor can the variable or value\
have embedded spaces.\
\
Under Wine, the environment of the underlying operating system is\
included into the Win32 environment, there will generally therefore be\
many more values than in a native Win32 implementation. Note that it is\
not possible to affect the operating system environment from within wcmd.\n"
WCMD_SHIFT, "Help about SHIFT\n"
WCMD_TIME, "Help about TIME\n"
WCMD_TYPE,
"TYPE <filename> copies <filename> to the console device (or elsewhere\
if redirected). No check is made that the file is readable text.\n"
WCMD_VERIFY, "Help about VERIFY\n"
WCMD_VER,
"VER displays the version of wcmd you are running\n"
WCMD_VOL, "Help about VOL\n"
WCMD_EXIT,
"EXIT terminates the current command session and returns\
to the operating system or shell from which you invoked wcmd.\n"
1000, "WCMD built-in commands are:\
ATTRIB\t\tShow or change DOS file attributes\
CALL\t\tInvoke a batch file from inside another\
CD (CHDIR)\tChange current default directory\
CLS\t\tClear the console screen\
COPY\t\tCopy file\
CTTY\t\tChange input/output device\
DATE\t\tShow or change the system date\
DEL (ERASE)\tDelete a file or set of files\
DIR\t\tList the contents of a directory\
ECHO\t\tCopy text directly to the console output\
HELP\t\tShow brief help details on a topic\
MD (MKDIR)\tCreate a subdirectory\
MOVE\t\tMove a file, set of files or directory tree\
PATH\t\tSet or show the search path\
PROMPT\t\tChange the command prompt\
REN (RENAME)\tRename a file\
RD (RMDIR)\tDelete a subdirectory\
SET\t\tSet or show environment variables\
TIME\t\tSet or show the current system time\
TYPE\t\tType the contents of a text file\
VER\t\tShow the current version of WCMD\
VOL\t\tShow the volume label of a disk device\
EXIT\t\tClose down WCMD\n\
Enter HELP <command> for further information on any of the above commands\n"
}
LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
IDI_ICON1 ICON
{
'00 00 01 00 01 00 20 20 00 01 00 00 00 00 A8 08'
'00 00 16 00 00 00 28 00 00 00 20 00 00 00 40 00'
'00 00 01 00 08 00 00 00 00 00 80 04 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 40 00 00 00 80 00 00 00 FF 00 00 00 00 20'
'00 00 40 20 00 00 80 20 00 00 FF 20 00 00 00 40'
'00 00 40 40 00 00 80 40 00 00 FF 40 00 00 00 60'
'00 00 40 60 00 00 80 60 00 00 FF 60 00 00 00 80'
'00 00 40 80 00 00 80 80 00 00 FF 80 00 00 00 A0'
'00 00 40 A0 00 00 80 A0 00 00 FF A0 00 00 00 C0'
'00 00 40 C0 00 00 80 C0 00 00 FF C0 00 00 00 FF'
'00 00 40 FF 00 00 80 FF 00 00 FF FF 00 00 00 00'
'20 00 40 00 20 00 80 00 20 00 FF 00 20 00 00 20'
'20 00 40 20 20 00 80 20 20 00 FF 20 20 00 00 40'
'20 00 40 40 20 00 80 40 20 00 FF 40 20 00 00 60'
'20 00 40 60 20 00 80 60 20 00 FF 60 20 00 00 80'
'20 00 40 80 20 00 80 80 20 00 FF 80 20 00 00 A0'
'20 00 40 A0 20 00 80 A0 20 00 FF A0 20 00 00 C0'
'20 00 40 C0 20 00 80 C0 20 00 FF C0 20 00 00 FF'
'20 00 40 FF 20 00 80 FF 20 00 FF FF 20 00 00 00'
'40 00 40 00 40 00 80 00 40 00 FF 00 40 00 00 20'
'40 00 40 20 40 00 80 20 40 00 FF 20 40 00 00 40'
'40 00 40 40 40 00 80 40 40 00 FF 40 40 00 00 60'
'40 00 40 60 40 00 80 60 40 00 FF 60 40 00 00 80'
'40 00 40 80 40 00 80 80 40 00 FF 80 40 00 00 A0'
'40 00 40 A0 40 00 80 A0 40 00 FF A0 40 00 00 C0'
'40 00 40 C0 40 00 80 C0 40 00 FF C0 40 00 00 FF'
'40 00 40 FF 40 00 80 FF 40 00 FF FF 40 00 00 00'
'60 00 40 00 60 00 80 00 60 00 FF 00 60 00 00 20'
'60 00 40 20 60 00 80 20 60 00 FF 20 60 00 00 40'
'60 00 40 40 60 00 80 40 60 00 FF 40 60 00 00 60'
'60 00 40 60 60 00 80 60 60 00 FF 60 60 00 00 80'
'60 00 40 80 60 00 80 80 60 00 FF 80 60 00 00 A0'
'60 00 40 A0 60 00 80 A0 60 00 FF A0 60 00 00 C0'
'60 00 40 C0 60 00 80 C0 60 00 FF C0 60 00 00 FF'
'60 00 40 FF 60 00 80 FF 60 00 FF FF 60 00 00 00'
'80 00 40 00 80 00 80 00 80 00 FF 00 80 00 00 20'
'80 00 40 20 80 00 80 20 80 00 FF 20 80 00 00 40'
'80 00 40 40 80 00 80 40 80 00 FF 40 80 00 00 60'
'80 00 40 60 80 00 80 60 80 00 FF 60 80 00 00 80'
'80 00 40 80 80 00 80 80 80 00 FF 80 80 00 00 A0'
'80 00 40 A0 80 00 80 A0 80 00 FF A0 80 00 00 C0'
'80 00 40 C0 80 00 80 C0 80 00 FF C0 80 00 00 FF'
'80 00 40 FF 80 00 80 FF 80 00 FF FF 80 00 00 00'
'A0 00 40 00 A0 00 80 00 A0 00 FF 00 A0 00 00 20'
'A0 00 40 20 A0 00 80 20 A0 00 FF 20 A0 00 00 40'
'A0 00 40 40 A0 00 80 40 A0 00 FF 40 A0 00 00 60'
'A0 00 40 60 A0 00 80 60 A0 00 FF 60 A0 00 00 80'
'A0 00 40 80 A0 00 80 80 A0 00 FF 80 A0 00 00 A0'
'A0 00 40 A0 A0 00 80 A0 A0 00 FF A0 A0 00 00 C0'
'A0 00 40 C0 A0 00 80 C0 A0 00 FF C0 A0 00 00 FF'
'A0 00 40 FF A0 00 80 FF A0 00 FF FF A0 00 00 00'
'C0 00 40 00 C0 00 80 00 C0 00 FF 00 C0 00 00 20'
'C0 00 40 20 C0 00 80 20 C0 00 FF 20 C0 00 00 40'
'C0 00 40 40 C0 00 80 40 C0 00 FF 40 C0 00 00 60'
'C0 00 40 60 C0 00 80 60 C0 00 FF 60 C0 00 00 80'
'C0 00 40 80 C0 00 80 80 C0 00 FF 80 C0 00 00 A0'
'C0 00 40 A0 C0 00 80 A0 C0 00 FF A0 C0 00 00 C0'
'C0 00 40 C0 C0 00 80 C0 C0 00 FF C0 C0 00 00 FF'
'C0 00 40 FF C0 00 80 FF C0 00 FF FF C0 00 00 00'
'FF 00 40 00 FF 00 80 00 FF 00 FF 00 FF 00 00 20'
'FF 00 40 20 FF 00 80 20 FF 00 FF 20 FF 00 00 40'
'FF 00 40 40 FF 00 80 40 FF 00 FF 40 FF 00 00 60'
'FF 00 40 60 FF 00 80 60 FF 00 FF 60 FF 00 00 80'
'FF 00 40 80 FF 00 80 80 FF 00 FF 80 FF 00 00 A0'
'FF 00 40 A0 FF 00 80 A0 FF 00 FF A0 FF 00 00 C0'
'FF 00 40 C0 FF 00 80 C0 FF 00 FF C0 FF 00 00 FF'
'FF 00 40 FF FF 00 80 FF FF 00 FF FF FF 00 FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF B6 24 FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 6D 24 FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF B6 00 B6 FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF 92 00 FF FF 24 FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF 24 FF FF FF FF 92 FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF 24 FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 92 FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF 6D FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF B6 FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 6D FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF 92 FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 6D FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 6D FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92 FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 24 FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 24'
'FF B6 FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 24'
'80 81 60 6C FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 24 81'
'C1 81 80 81 20 FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF C0 C1'
'80 80 C1 81 C1 20 FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 81 81'
'81 80 81 80 80 80 24 FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 6D 80 81'
'81 80 81 C1 C0 80 80 92 FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF B6 FF FF'
'FF FF FF 81 C0 80 80 20 FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF 92 FF FF'
'FF FF FF FF C5 C0 80 81 6D FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FB 81 81 24 FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92 FF'
'FF FF FF FF FF FF FF FF 24 FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF 6D FF'
'FF FF FF FF FF FF FF FF 6D FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 92'
'FF FF FF FF FF FF FF 24 24 FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'92 FF FF FF FF 24 6D FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'92 FF FF 00 92 FF FF FF FF FF FF FF FF FF FF FF'
'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF'
'FF 24 B6 FF FF FF FF FF FF FF FF FF FF FF 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00'
}