Jason Edmeades : cmd.exe: Support for DEL filename /s.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Apr 24 07:23:58 CDT 2007
Module: wine
Branch: master
Commit: 68b11d12906655bdb27053ffa14de74399620811
URL: http://source.winehq.org/git/wine.git/?a=commit;h=68b11d12906655bdb27053ffa14de74399620811
Author: Jason Edmeades <us at edmeades.me.uk>
Date: Mon Apr 23 23:24:38 2007 +0100
cmd.exe: Support for DEL filename /s.
---
programs/cmd/README | 7 ---
programs/cmd/builtins.c | 128 +++++++++++++++++++++++++++++++++++++++++-----
programs/cmd/directory.c | 7 ---
programs/cmd/wcmd.h | 11 ++++-
programs/cmd/wcmdmain.c | 2 +-
5 files changed, 125 insertions(+), 30 deletions(-)
diff --git a/programs/cmd/README b/programs/cmd/README
index ee1c542..d7d80c2 100644
--- a/programs/cmd/README
+++ b/programs/cmd/README
@@ -11,7 +11,6 @@ WHAT'S INCLUDED
WHAT'S MISSING
- Command-line qualifiers for most builtin commands
-- Wildcards and relative paths in COPY, MOVE and RENAME
- Set functionality in DATE, TIME, ATTRIB, LABEL
- Full internationalisation of the text (and commands?).
@@ -26,11 +25,6 @@ US date-time format is used. Set eg "LANG=en_GB" for DD/MM/YY dates and 24-hour
times.
- Line editing and command recall doesn't work due to missing functionality in
Wine.
-- DIR/S only works if no file specification is given, ie "DIR C:\TEMP /S" works
-but "DIR C:\TEMP\*.C" doesn't work if a matching file exists 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.
- Redirection is implemented as a command line is parsed. This means that ">"
and "<" symbols cannot appear in command arguments even within quotes.
- In many cases parsing and syntax checking is less rigorous than DOS. Thus an
@@ -43,4 +37,3 @@ 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
"CMD /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.
-
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index e7398fd..4d0fd5e 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -239,24 +239,32 @@ void WCMD_create_dir (void) {
* non-hidden files
*/
-void WCMD_delete (char *command) {
+BOOL WCMD_delete (char *command, BOOL expectDir) {
int argno = 0;
int argsProcessed = 0;
char *argN = command;
+ BOOL foundAny = FALSE;
+
+ /* If not recursing, clear error flag */
+ if (expectDir) errorlevel = 0;
/* Loop through all args */
while (argN) {
char *thisArg = WCMD_parameter (command, argno++, &argN);
+ char argCopy[MAX_PATH];
+
if (argN && argN[0] != '/') {
WIN32_FIND_DATA fd;
HANDLE hff;
char fpath[MAX_PATH];
char *p;
+ BOOL handleParm = TRUE;
+ BOOL found = FALSE;
-
- WINE_TRACE("del: Processing arg %s (quals:%s)\n", thisArg, quals);
+ strcpy(argCopy, thisArg);
+ WINE_TRACE("del: Processing arg %s (quals:%s)\n", argCopy, quals);
argsProcessed++;
/* If filename part of parameter is * or *.*, prompt unless
@@ -269,7 +277,7 @@ void WCMD_delete (char *command) {
char ext[MAX_PATH];
/* Convert path into actual directory spec */
- GetFullPathName (thisArg, sizeof(fpath), fpath, NULL);
+ GetFullPathName (argCopy, sizeof(fpath), fpath, NULL);
WCMD_splitpath(fpath, drive, dir, fname, ext);
/* Only prompt for * and *.*, not *a, a*, *.a* etc */
@@ -278,6 +286,9 @@ void WCMD_delete (char *command) {
BOOL ok;
char question[MAXSTRING];
+ /* Note: Flag as found, to avoid file not found message */
+ found = TRUE;
+
/* Ask for confirmation */
sprintf(question, "%s, ", fpath);
ok = WCMD_ask_confirm(question, TRUE);
@@ -287,25 +298,28 @@ void WCMD_delete (char *command) {
}
}
- hff = FindFirstFile (thisArg, &fd);
+ /* First, try to delete in the current directory */
+ hff = FindFirstFile (argCopy, &fd);
if (hff == INVALID_HANDLE_VALUE) {
- WCMD_output ("%s :File Not Found\n", thisArg);
- continue;
+ handleParm = FALSE;
+ } else {
+ found = TRUE;
}
+
/* Support del <dirname> by just deleting all files dirname\* */
- if ((strchr(thisArg,'*') == NULL) && (strchr(thisArg,'?') == NULL)
+ if (handleParm && (strchr(argCopy,'*') == NULL) && (strchr(argCopy,'?') == NULL)
&& (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
char modifiedParm[MAX_PATH];
- strcpy(modifiedParm, thisArg);
+ strcpy(modifiedParm, argCopy);
strcat(modifiedParm, "\\*");
FindClose(hff);
- WCMD_delete(modifiedParm);
- continue;
+ found = TRUE;
+ WCMD_delete(modifiedParm, FALSE);
- } else {
+ } else if (handleParm) {
/* Build the filename to delete as <supplied directory>\<findfirst filename> */
- strcpy (fpath, thisArg);
+ strcpy (fpath, argCopy);
do {
p = strrchr (fpath, '\\');
if (p != NULL) {
@@ -399,14 +413,100 @@ void WCMD_delete (char *command) {
} while (FindNextFile(hff, &fd) != 0);
FindClose (hff);
}
+
+ /* Now recurse into all subdirectories handling the paramater in the same way */
+ if (strstr (quals, "/S") != NULL) {
+
+ char thisDir[MAX_PATH];
+ int cPos;
+
+ char drive[10];
+ char dir[MAX_PATH];
+ char fname[MAX_PATH];
+ char ext[MAX_PATH];
+
+ /* Convert path into actual directory spec */
+ GetFullPathName (argCopy, sizeof(thisDir), thisDir, NULL);
+ WCMD_splitpath(thisDir, drive, dir, fname, ext);
+
+ strcpy(thisDir, drive);
+ strcat(thisDir, dir);
+ cPos = strlen(thisDir);
+
+ WINE_TRACE("Searching recursively in '%s'\n", thisDir);
+
+ /* Append '*' to the directory */
+ thisDir[cPos] = '*';
+ thisDir[cPos+1] = 0x00;
+
+ hff = FindFirstFile (thisDir, &fd);
+
+ /* Remove residual '*' */
+ thisDir[cPos] = 0x00;
+
+ if (hff != INVALID_HANDLE_VALUE) {
+ DIRECTORY_STACK *allDirs = NULL;
+ DIRECTORY_STACK *lastEntry = NULL;
+
+ do {
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (strcmp(fd.cFileName, "..") != 0) &&
+ (strcmp(fd.cFileName, ".") != 0)) {
+
+ DIRECTORY_STACK *nextDir;
+ char subParm[MAX_PATH];
+
+ /* Work out search parameter in sub dir */
+ strcpy (subParm, thisDir);
+ strcat (subParm, fd.cFileName);
+ strcat (subParm, "\\");
+ strcat (subParm, fname);
+ strcat (subParm, ext);
+ WINE_TRACE("Recursive, Adding to search list '%s'\n", subParm);
+
+ /* Allocate memory, add to list */
+ nextDir = (DIRECTORY_STACK *) HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
+ if (allDirs == NULL) allDirs = nextDir;
+ if (lastEntry != NULL) lastEntry->next = nextDir;
+ lastEntry = nextDir;
+ nextDir->next = NULL;
+ nextDir->dirName = HeapAlloc(GetProcessHeap(),0,(strlen(subParm)+1));
+ strcpy(nextDir->dirName, subParm);
+ }
+ } while (FindNextFile(hff, &fd) != 0);
+ FindClose (hff);
+
+ /* Go through each subdir doing the delete */
+ while (allDirs != NULL) {
+ DIRECTORY_STACK *tempDir;
+
+ tempDir = allDirs->next;
+ found |= WCMD_delete (allDirs->dirName, FALSE);
+
+ HeapFree(GetProcessHeap(),0,allDirs->dirName);
+ HeapFree(GetProcessHeap(),0,allDirs);
+ allDirs = tempDir;
+ }
+ }
+ }
+ /* Keep running total to see if any found, and if not recursing
+ issue error message */
+ if (expectDir) {
+ if (!found) {
+ errorlevel = 1;
+ WCMD_output ("%s : File Not Found\n", argCopy);
+ }
+ }
+ foundAny |= found;
}
}
/* Handle no valid args */
if (argsProcessed == 0) {
WCMD_output ("Argument missing\n");
- return;
}
+
+ return foundAny;
}
/****************************************************************************
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c
index 801d59d..24c7c6c 100644
--- a/programs/cmd/directory.c
+++ b/programs/cmd/directory.c
@@ -57,13 +57,6 @@ typedef enum _DISPLAYORDER
Date
} DISPLAYORDER;
-typedef struct _DIRECTORY_STACK
-{
- struct _DIRECTORY_STACK *next;
- char *dirName;
- char *fileName;
-} DIRECTORY_STACK;
-
static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *parms, int level);
static int file_total, dir_total, recurse, wide, bare, max_width, lower;
static int shortname, usernames;
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 8718dd6..76cd22b 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -35,7 +35,7 @@ void WCMD_clear_screen (void);
void WCMD_color (void);
void WCMD_copy (void);
void WCMD_create_dir (void);
-void WCMD_delete (char *);
+BOOL WCMD_delete (char *, BOOL);
void WCMD_directory (char *);
void WCMD_echo (const char *);
void WCMD_endlocal (void);
@@ -109,6 +109,15 @@ struct env_stack
WCHAR *strings;
};
+/* Data structure to handle building lists during recursive calls */
+
+typedef struct _DIRECTORY_STACK
+{
+ struct _DIRECTORY_STACK *next;
+ char *dirName;
+ char *fileName;
+} DIRECTORY_STACK;
+
#endif /* !RC_INVOKED */
/*
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 88a827c..a74b085 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -620,7 +620,7 @@ void WCMD_process_command (char *command)
break;
case WCMD_DEL:
case WCMD_ERASE:
- WCMD_delete (p);
+ WCMD_delete (p, TRUE);
break;
case WCMD_DIR:
WCMD_directory (p);
More information about the wine-cvs
mailing list