[PATCH 1/3] [cmd] Add support for wildcards in copy

Jason Edmeades jason.edmeades at googlemail.com
Fri Jul 27 15:43:37 CDT 2007


Should fix bug 7237
---
 programs/cmd/builtins.c |  113 ++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 87 insertions(+), 26 deletions(-)

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index af58717..9c34e8f 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -108,7 +108,7 @@ void WCMD_change_tty (void) {
  * WCMD_copy
  *
  * Copy a file or wildcarded set.
- * FIXME: No wildcard support
+ * FIXME: Add support for a+b+c type syntax
  */
 
 void WCMD_copy (void) {
@@ -116,21 +116,52 @@ void WCMD_copy (void) {
   WIN32_FIND_DATA fd;
   HANDLE hff;
   BOOL force, status;
-  WCHAR outpath[MAX_PATH], inpath[MAX_PATH], *infile, copycmd[3];
+  WCHAR outpath[MAX_PATH], srcpath[MAX_PATH], copycmd[3];
   DWORD len;
   static const WCHAR copyCmdW[] = {'C','O','P','Y','C','M','D','\0'};
+  BOOL copyToDir = FALSE;
+  BOOL copyFromDir = FALSE;
+  WCHAR srcspec[MAX_PATH];
+  DWORD attribs;
+  WCHAR drive[10];
+  WCHAR dir[MAX_PATH];
+  WCHAR fname[MAX_PATH];
+  WCHAR ext[MAX_PATH];
 
   if (param1[0] == 0x00) {
     WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
     return;
   }
 
-  if ((strchrW(param1,'*') != NULL) && (strchrW(param1,'%') != NULL)) {
-    WCMD_output (WCMD_LoadMessage(WCMD_NYI));
-    return;
+  /* Convert source into full spec */
+  WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(param1));
+  GetFullPathName (param1, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
+  if (srcpath[strlenW(srcpath) - 1] == '\\')
+      srcpath[strlenW(srcpath) - 1] = '\0';
+
+  if ((strchrW(srcpath,'*') == NULL) && (strchrW(srcpath,'?') == NULL)) {
+    attribs = GetFileAttributes(srcpath);
+  } else {
+    attribs = 0;
   }
+  strcpyW(srcspec, srcpath);
+
+  /* If a directory, then add \* on the end when searching */
+  if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
+    strcatW(srcpath, slashW);
+    copyFromDir = TRUE;
+    strcatW(srcspec, slashW);
+    strcatW(srcspec, starW);
+  } else {
+    WCMD_splitpath(srcpath, drive, dir, fname, ext);
+    strcpyW(srcpath, drive);
+    strcatW(srcpath, dir);
+  }
+
+  WINE_TRACE("Copy source (calculated): path: '%s'\n", wine_dbgstr_w(srcpath));
 
   /* If no destination supplied, assume current directory */
+  WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(param2));
   if (param2[0] == 0x00) {
       strcpyW(param2, dotW);
   }
@@ -138,15 +169,13 @@ void WCMD_copy (void) {
   GetFullPathName (param2, sizeof(outpath)/sizeof(WCHAR), outpath, NULL);
   if (outpath[strlenW(outpath) - 1] == '\\')
       outpath[strlenW(outpath) - 1] = '\0';
-  hff = FindFirstFile (outpath, &fd);
-  if (hff != INVALID_HANDLE_VALUE) {
-    if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-      GetFullPathName (param1, sizeof(inpath)/sizeof(WCHAR), inpath, &infile);
-      strcatW (outpath, slashW);
-      strcatW (outpath, infile);
-    }
-    FindClose (hff);
+  attribs = GetFileAttributes(outpath);
+  if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
+    strcatW (outpath, slashW);
+    copyToDir = TRUE;
   }
+  WINE_TRACE("Copy destination (calculated): '%s'(%d)\n",
+             wine_dbgstr_w(outpath), copyToDir);
 
   /* /-Y has the highest priority, then /Y and finally the COPYCMD env. variable */
   if (strstrW (quals, parmNoY))
@@ -158,21 +187,53 @@ void WCMD_copy (void) {
     force = (len && len < (sizeof(copycmd)/sizeof(WCHAR)) && ! lstrcmpiW (copycmd, parmY));
   }
 
-  if (!force) {
-    hff = FindFirstFile (outpath, &fd);
-    if (hff != INVALID_HANDLE_VALUE) {
-      WCHAR buffer[MAXSTRING];
+  /* Loop through all source files */
+  WINE_TRACE("Searching for: '%s'\n", wine_dbgstr_w(srcspec));
+  hff = FindFirstFile (srcspec, &fd);
+  if (hff != INVALID_HANDLE_VALUE) {
+      do {
+        WCHAR outname[MAX_PATH];
+        WCHAR srcname[MAX_PATH];
+        BOOL  overwrite = force;
+
+        /* Destination is either supplied filename, or source name in
+           supplied destination directory                             */
+        strcpyW(outname, outpath);
+        if (copyToDir) strcatW(outname, fd.cFileName);
+        strcpyW(srcname, srcpath);
+        strcatW(srcname, fd.cFileName);
+
+        WINE_TRACE("Copying from : '%s'\n", wine_dbgstr_w(srcname));
+        WINE_TRACE("Copying to : '%s'\n", wine_dbgstr_w(outname));
+
+        /* Skip . and .., and directories */
+        if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+          overwrite = FALSE;
+          WINE_TRACE("Skipping directories\n");
+        }
+
+        /* Prompt before overwriting */
+        else if (!overwrite) {
+          attribs = GetFileAttributes(outname);
+          if (attribs != INVALID_FILE_ATTRIBUTES) {
+            WCHAR buffer[MAXSTRING];
+            wsprintf(buffer, WCMD_LoadMessage(WCMD_OVERWRITE), outname);
+            overwrite = WCMD_ask_confirm(buffer, FALSE, NULL);
+          }
+          else overwrite = TRUE;
+        }
 
-      FindClose (hff);
+        /* Do the copy as appropriate */
+        if (overwrite) {
+          status = CopyFile (srcname, outname, FALSE);
+          if (!status) WCMD_print_error ();
+        }
 
-      wsprintf(buffer, WCMD_LoadMessage(WCMD_OVERWRITE), outpath);
-      force = WCMD_ask_confirm(buffer, FALSE, NULL);
-    }
-    else force = TRUE;
-  }
-  if (force) {
-    status = CopyFile (param1, outpath, FALSE);
-    if (!status) WCMD_print_error ();
+      } while (FindNextFile(hff, &fd) != 0);
+      FindClose (hff);
+  } else {
+      status = ERROR_FILE_NOT_FOUND;
+      WCMD_print_error ();
   }
 }
 
-- 
1.5.0




More information about the wine-patches mailing list