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