Made cmd unicode compatible.
[reactos.git] / reactos / subsys / system / cmd / copy.c
index b349214..957a1da 100644 (file)
  *
  *    03-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
  *        Remove all hardcode string to En.rc
+ *
+ *    13-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
+ *        Rewrite to clean up copy and support wildcard.
+ *
+ *    20-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>)
+ *        Add touch syntax.  "copy arp.exe+,,"
+ *        Copy command is now completed.
  */
-
 #include <precomp.h>
 #include "resource.h"
-
 #ifdef INCLUDE_CMD_COPY
-
-
-#define VERIFY  1               /* VERIFY Switch */
-#define BINARY  2               /* File is to be copied as BINARY */
-#define ASCII   4               /* File is to be copied as ASCII */
-#define PROMPT  8               /* Prompt before overwriting files */
-#define NPROMPT 16              /* Do not prompt before overwriting files */
-#define HELP    32              /* Help was asked for */
-#define SOURCE  128             /* File is a source */
-
-
-typedef struct tagFILES
-{
-       struct tagFILES *next;
-       TCHAR szFile[MAX_PATH];
-       DWORD dwFlag;                   /* BINARY -xor- ASCII */
-} FILES, *LPFILES;
-
-
-static BOOL DoSwitches (LPTSTR, LPDWORD);
-static BOOL AddFile (LPFILES, TCHAR *, int *, int *, LPDWORD);
-static BOOL AddFiles (LPFILES, TCHAR *, int *, int *, int *, LPDWORD);
-static BOOL GetDestination (LPFILES, LPFILES);
-static INT  ParseCommand (LPFILES, int, TCHAR **, LPDWORD);
-static VOID DeleteFileList (LPFILES);
-static INT  Overwrite (LPTSTR);
-
-
-static BOOL
-DoSwitches (LPTSTR arg, LPDWORD lpdwFlags)
-{
-       if (!_tcsicmp (arg, _T("/-Y")))
-       {
-               *lpdwFlags |= PROMPT;
-               *lpdwFlags &= ~NPROMPT;
-               return TRUE;
-       }
-       else if (_tcslen (arg) > 2)
-       {
-               error_too_many_parameters (_T(""));
-               return FALSE;
-       }
-
-       switch (_totupper (arg[1]))
-       {
-               case _T('V'):
-                       *lpdwFlags |= VERIFY;
-                       break;
-
-               case _T('A'):
-                       *lpdwFlags |= ASCII;
-                       *lpdwFlags &= ~BINARY;
-                       break;
-
-               case _T('B'):
-                       *lpdwFlags |= BINARY;
-                       *lpdwFlags &= ~ASCII;
-                       break;
-
-               case _T('Y'):
-                       *lpdwFlags &= ~PROMPT;
-                       *lpdwFlags |= NPROMPT;
-                       break;
-
-               default:
-                       error_invalid_switch (arg[1]);
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-
-static BOOL
-AddFile (LPFILES f, TCHAR *arg, int *source, int *dest, LPDWORD flags)
-{
-       if (*dest)
-       {
-               error_too_many_parameters (_T(""));
-               return FALSE;
-       }
-       if (*source)
-       {
-               *dest = 1;
-               f->dwFlag = 0;
-       }
-       else
-       {
-               *source = 1;
-               f->dwFlag = SOURCE;
-       }
-       _tcscpy(f->szFile, arg);
-       f->dwFlag |= *flags & ASCII ? ASCII : BINARY;
-       if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL)
-       {
-               error_out_of_memory ();
-               return FALSE;
-       }
-       f = f->next;
-       f->dwFlag = 0;
-       f->next = NULL;
-       return TRUE;
-}
-
-
-static BOOL
-AddFiles (LPFILES f, TCHAR *arg, int *source, int *dest,
-                 int *count, LPDWORD flags)
-{
-       TCHAR t[128];
-       int j;
-       int k;
-
-       if (*dest)
-       {
-               error_too_many_parameters (_T(""));
-               return FALSE;
-       }
-
-       j = 0;
-       k = 0;
-
-       while (arg[j] == _T('+'))
-               j++;
-
-       while (arg[j] != _T('\0'))
-       {
-               t[k] = arg[j++];
-               if (t[k] == '+' || arg[j] == _T('\0'))
-               {
-                       if (!k)
-                               continue;
-                       if (arg[j] == _T('\0') && t[k] != _T('+'))
-                               k++;
-                       t[k] = _T('\0');
-                       *count += 1;
-                       _tcscpy (f->szFile, t);
-                       *source = 1;
-                       if (*flags & ASCII)
-                               f->dwFlag |= *flags | SOURCE | ASCII;
-                       else
-                               f->dwFlag |= *flags | BINARY | SOURCE;
-
-                       if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL)
-                       {
-                               error_out_of_memory ();
-                               return FALSE;
-                       }
-                       f = f->next;
-                       f->next = NULL;
-                       k = 0;
-                       f->dwFlag = 0;
-                       continue;
-               }
-               k++;
-       }
-
-       if (arg[--j] == _T('+'))
-               *source = 0;
-
-       return 1;
-}
-
-
-static BOOL
-GetDestination (LPFILES f, LPFILES dest)
-{
-       LPFILES p = NULL;
-       LPFILES start = f;
-
-       while (f->next != NULL)
-       {
-               p = f;
-               f = f->next;
-       }
-
-       f = p;
-
-       if ((f->dwFlag & SOURCE) == 0)
-       {
-               free (p->next);
-               p->next = NULL;
-               _tcscpy (dest->szFile, f->szFile);
-               dest->dwFlag = f->dwFlag;
-               dest->next = NULL;
-               f = start;
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-
-static INT
-ParseCommand (LPFILES f, int argc, TCHAR **arg, LPDWORD lpdwFlags)
-{
-       INT i;
-       INT dest;
-       INT source;
-       INT count;
-       TCHAR temp[128];
-       dest = 0;
-       source = 0;
-       count = 0;
-
-  ConOutPrintf(_T("here\n"));
-
-
-  /* hack geting pipe 1>null working */
-  for (i = 0; i < argc; i++)
-       {
-    if (arg[i][0] != _T('/')) 
-        count++;
-  }
-  if (count==3) argc=2;
-  /* end hack */
-
-  
-
-       for (i = 0; i < argc; i++)
-       {     
-
-               if (arg[i][0] == _T('/'))
-               {
-                       if (!DoSwitches (arg[i], lpdwFlags))
-                               return -1;
-               }
-               else
-               {
-                       if (!_tcscmp(arg[i], _T("+")))
-                               source = 0;
-                       else if (!_tcschr(arg[i], _T('+')) && source)
-                       {
-
-//                             Make sure we have a clean workable path
-
-                               GetFullPathName( arg[i], 128, (LPTSTR) &temp, NULL);
-//                             printf("A Input %s, Output %s\n", arg[i], temp);
-
-                               if (!AddFile(f, (TCHAR *) &temp, &source, &dest, lpdwFlags))
-                                       return -1;
-                               f = f->next;
-                               count++;
-                       }
-                       else
-                       {
-
-                               GetFullPathName( arg[i], 128, (LPTSTR) &temp, NULL);
-//                             printf("B Input %s, Output %s\n", arg[i], temp);
-
-                               if (!AddFiles(f, (TCHAR *) &temp, &source, &dest, &count, lpdwFlags))
-                                       return -1;
-                               while (f->next != NULL)
-                                       f = f->next;
-                       }
-               }
-       }
-
-#ifdef _DEBUG
-       DebugPrintf (_T("ParseCommand: flags has %s\n"),
-                                *lpdwFlags & ASCII ? _T("ASCII") : _T("BINARY"));
-#endif
-       return count;
-}
-
-
-static VOID
-DeleteFileList (LPFILES f)
-{
-       LPFILES temp;
-
-       while (f != NULL)
-       {
-               temp = f;
-               f = f->next;
-               free (temp);
-       }
-}
-
-
-static INT
-Overwrite (LPTSTR fn)
+enum
 {
-       TCHAR inp[10];
-       LPTSTR p;
-       TCHAR szOptions[4];
-
-       LoadString( CMD_ModuleHandle, STRING_COPY_OPTION, szOptions, sizeof(szOptions) / sizeof(szOptions[0]) );
-
-       ConOutResPuts(STRING_COPY_HELP1);
-
-       ConInString(inp, 10);
-       ConOutPuts(_T(""));
-
-       _tcsupr (inp);
-       for (p = inp; _istspace (*p); p++)
-               ;
-
-       if (*p != szOptions[0] && *p != szOptions[2])
-               return 0;
-       if (*p == szOptions[2])
-               return 2;
-
-       return 1;
-}
-
-
+       COPY_ASCII       = 0x001,   /* /A  */
+       COPY_DECRYPT     = 0x004,   /* /D  */
+       COPY_VERIFY      = 0x008,   /* /V  : Dummy, Never will be Impleneted */
+       COPY_SHORTNAME   = 0x010,   /* /N  : Dummy, Never will be Impleneted */
+       COPY_NO_PROMPT   = 0x020,   /* /Y  */
+       COPY_PROMPT      = 0x040,   /* /-Y */
+       COPY_RESTART     = 0x080,   /* /Z  */
+       COPY_BINARY      = 0x100,   /* /B  */
+};
 #define BUFF_SIZE 16384         /* 16k = max buffer size */
-
-
-int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
+int copy (TCHAR source[MAX_PATH], TCHAR dest[MAX_PATH], INT append, DWORD lpdwFlags, BOOL bTouch)
 {
        TCHAR szMsg[RC_STRING_MAX_SIZE];
        FILETIME srctime;
@@ -349,32 +63,104 @@ int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
        DWORD  dwWritten;
        DWORD  i;
        BOOL   bEof = FALSE;
+       TCHAR TrueDest[MAX_PATH];
+       TCHAR TempSrc[MAX_PATH];
+       TCHAR * FileName;
 
 #ifdef _DEBUG
        DebugPrintf (_T("checking mode\n"));
 #endif
+       if(bTouch)
+       {
+       hFileSrc = CreateFile (source, GENERIC_WRITE, FILE_SHARE_READ,
+               NULL, OPEN_EXISTING, 0, NULL);
+       if (hFileSrc == INVALID_HANDLE_VALUE)
+       {
+               LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
+               ConOutPrintf(szMsg, source);
+    nErrorLevel = 1;
+               return 0;
+       }
 
-       dwAttrib = GetFileAttributes (source);
+               FILETIME NewFileTime;
+               SYSTEMTIME CurrentTime;
+
+               GetSystemTime(&CurrentTime);
+               SystemTimeToFileTime(&CurrentTime, &NewFileTime);
+               if(SetFileTime(hFileSrc,(LPFILETIME) NULL, (LPFILETIME) NULL, &NewFileTime))
+               {
+                       CloseHandle(hFileSrc);
+                       return 1;
 
+               }
+               else
+               {
+                       CloseHandle(hFileSrc);
+                       return 0;
+               }
+       }
+
+       dwAttrib = GetFileAttributes (source);
        hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ,
-                                                  NULL, OPEN_EXISTING, 0, NULL);
+               NULL, OPEN_EXISTING, 0, NULL);
        if (hFileSrc == INVALID_HANDLE_VALUE)
        {
                LoadString(CMD_ModuleHandle, STRING_COPY_ERROR1, szMsg, RC_STRING_MAX_SIZE);
-               ConErrPrintf(szMsg, source);
+               ConOutPrintf(szMsg, source);
+    nErrorLevel = 1;
                return 0;
        }
 
 #ifdef _DEBUG
        DebugPrintf (_T("getting time\n"));
 #endif
-
        GetFileTime (hFileSrc, &srctime, NULL, NULL);
-
 #ifdef _DEBUG
        DebugPrintf (_T("copy: flags has %s\n"),
-                                *lpdwFlags & ASCII ? "ASCII" : "BINARY");
+               lpdwFlags & COPY_ASCII ? "ASCII" : "BINARY");
 #endif
+       /* Check to see if /D or /Z are true, if so we need a middle
+          man to copy the file too to allow us to use CopyFileEx later */
+       if(lpdwFlags & COPY_DECRYPT)
+       {
+               GetEnvironmentVariable(_T("TEMP"),TempSrc,MAX_PATH);
+               _tcscat(TempSrc,_T("\\"));
+               FileName = _tcsrchr(source,_T('\\'));
+               FileName++;
+               _tcscat(TempSrc,FileName);
+               /* This is needed to be on the end to prevent an error
+                  if the user did "copy /D /Z foo bar then it would be copied
+                  too %TEMP%\foo here and when %TEMP%\foo when it sets it up
+                  for COPY_RESTART, this would mean it is copying to itself
+                  which would error when it tried to open the handles for ReadFile
+                  and WriteFile */
+               _tcscat(TempSrc,_T(".decrypt"));
+               if(!CopyFileEx(source, TempSrc, NULL, NULL, FALSE, COPY_FILE_ALLOW_DECRYPTED_DESTINATION))
+               {
+                  nErrorLevel = 1;
+                  return 0;
+               }
+               _tcscpy(source, TempSrc);
+       }
+
+
+       if(lpdwFlags & COPY_RESTART)
+       {
+               _tcscpy(TrueDest, dest);
+               GetEnvironmentVariable(_T("TEMP"),dest,MAX_PATH);
+               _tcscat(dest,_T("\\"));
+               FileName = _tcsrchr(TrueDest,_T('\\'));
+               FileName++;
+               _tcscat(dest,FileName);
+       }
+
+
 
        if (!IsExistingFile (dest))
        {
@@ -389,63 +175,69 @@ int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
                if (!_tcscmp (dest, source))
                {
                        LoadString(CMD_ModuleHandle, STRING_COPY_ERROR2, szMsg, RC_STRING_MAX_SIZE);
-                       ConErrPrintf(szMsg, source);
-
+                       ConOutPrintf(szMsg, source);
                        CloseHandle (hFileSrc);
+      nErrorLevel = 1;
                        return 0;
                }
-
 #ifdef _DEBUG
                DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest);
 #endif
                SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
-
 #ifdef _DEBUG
                DebugPrintf (_T("DeleteFile (%s);\n"), dest);
 #endif
                DeleteFile (dest);
-
-               hFileDest =
-                       CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+               hFileDest =     CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
        }
        else
        {
                LONG lFilePosHigh = 0;
-
                if (!_tcscmp (dest, source))
                {
                        CloseHandle (hFileSrc);
                        return 0;
                }
-
 #ifdef _DEBUG
                DebugPrintf (_T("opening/appending\n"));
 #endif
+               SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
                hFileDest =
                        CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+               /* Move to end of file to start writing */
                SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END);
        }
-
-       if (hFileDest == INVALID_HANDLE_VALUE)
+               if (hFileDest == INVALID_HANDLE_VALUE)
        {
                CloseHandle (hFileSrc);
-               error_path_not_found ();
+               ConOutResPuts(STRING_ERROR_PATH_NOT_FOUND);
+    nErrorLevel = 1;
                return 0;
        }
-
        buffer = (LPBYTE)malloc (BUFF_SIZE);
        if (buffer == NULL)
        {
                CloseHandle (hFileDest);
                CloseHandle (hFileSrc);
-               error_out_of_memory ();
+               ConOutResPuts(STRING_ERROR_OUT_OF_MEMORY);
+    nErrorLevel = 1;
                return 0;
        }
-
        do
        {
                ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL);
-               if (*lpdwFlags & ASCII)
+               if (lpdwFlags & COPY_ASCII)
                {
                        for (i = 0; i < dwRead; i++)
                        {
@@ -457,29 +249,30 @@ int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
                        }
                        dwRead = i;
                }
-
                if (dwRead == 0)
                        break;
-
                WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL);
                if (dwWritten != dwRead)
                {
-                       ConErrResPuts(STRING_COPY_ERROR3);
-
+                       ConOutResPuts(STRING_COPY_ERROR3);
                        free (buffer);
                        CloseHandle (hFileDest);
                        CloseHandle (hFileSrc);
+      nErrorLevel = 1;
                        return 0;
                }
        }
        while (dwRead && !bEof);
-
 #ifdef _DEBUG
        DebugPrintf (_T("setting time\n"));
 #endif
        SetFileTime (hFileDest, &srctime, NULL, NULL);
-
-       if (*lpdwFlags & ASCII)
+       if (lpdwFlags & COPY_ASCII)
        {
                ((LPTSTR)buffer)[0] = 0x1A;
                ((LPTSTR)buffer)[1] = _T('\0');
@@ -488,299 +281,585 @@ int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags)
 #endif
                WriteFile (hFileDest, buffer, sizeof(TCHAR), &dwWritten, NULL);
        }
-
        free (buffer);
        CloseHandle (hFileDest);
        CloseHandle (hFileSrc);
-
 #ifdef _DEBUG
        DebugPrintf (_T("setting mode\n"));
 #endif
        SetFileAttributes (dest, dwAttrib);
+       /* Now finish off the copy if needed with CopyFileEx */
+       if(lpdwFlags & COPY_RESTART)
+       {
+               if(!CopyFileEx(dest, TrueDest, NULL, NULL, FALSE, COPY_FILE_RESTARTABLE))
+               {
+                  nErrorLevel = 1;
+                  DeleteFile(dest);
+           return 0;                   
+               }
+               /* Take care of file in the temp folder */
+               DeleteFile(dest);
 
-       return 1;
-}
+       }
 
+       if(lpdwFlags & COPY_DECRYPT)
+          DeleteFile(TempSrc);
 
-static INT
-SetupCopy (LPFILES sources, TCHAR **p, BOOL bMultiple,
-           TCHAR *drive_d, TCHAR *dir_d, TCHAR *file_d,
-           TCHAR *ext_d, int *append, LPDWORD lpdwFlags)
-{
-       WIN32_FIND_DATA find;
-       TCHAR drive_s[_MAX_DRIVE];
-       TCHAR dir_s[_MAX_DIR];
-       TCHAR file_s[_MAX_FNAME];
-       TCHAR ext_s[_MAX_EXT];
-       TCHAR from_merge[_MAX_PATH];
-
-       LPTSTR real_source;
-       LPTSTR real_dest;
-
-       INT  nCopied = 0;
-       BOOL bAll = FALSE;
-       BOOL bDone;
-       HANDLE hFind;
-       TCHAR temp[128];
 
-#ifdef _DEBUG
-       DebugPrintf (_T("SetupCopy\n"));
-#endif
-
-       real_source = (LPTSTR)malloc (MAX_PATH * sizeof(TCHAR));
-       real_dest = (LPTSTR)malloc (MAX_PATH * sizeof(TCHAR));
 
-       if (!real_source || !real_dest)
+       return 1;
+}
+static INT Overwrite (LPTSTR fn)
+{
+       /*ask the user if they want to override*/
+       TCHAR szMsg[RC_STRING_MAX_SIZE];
+       INT res;
+       LoadString(CMD_ModuleHandle, STRING_COPY_HELP1, szMsg, RC_STRING_MAX_SIZE);
+       ConOutPrintf(szMsg,fn);
+       res = FilePromptYNA (_T(""));
+       return res;
+}
+INT cmd_copy (LPTSTR cmd, LPTSTR param)
+{
+       TCHAR szMsg[RC_STRING_MAX_SIZE];
+       LPTSTR *arg;
+       INT argc, i, nFiles, nOverwrite = 0, nSrc = -1, nDes = -1;
+       /* this is the path up to the folder of the src and dest ie C:\windows\ */
+       TCHAR szDestPath[MAX_PATH];
+       TCHAR szSrcPath[MAX_PATH];
+       DWORD dwFlags = 0;
+       /* If this is the type of copy where we are adding files */
+       BOOL bAppend = FALSE;
+       WIN32_FIND_DATA findBuffer;
+       HANDLE hFile;
+       BOOL bTouch = FALSE;
+       /* Used when something like "copy c*.exe d*.exe" during the process of
+          figuring out the new name */
+       TCHAR tmpName[MAX_PATH] = _T("");
+       /* Pointer to keep track of how far through the append input(file1+file2+file3) we are */
+       TCHAR  * appendPointer = _T("\0");
+       /* The full path to src and dest.  This has drive letter, folders, and filename */
+       TCHAR tmpDestPath[MAX_PATH];
+       TCHAR tmpSrcPath[MAX_PATH];
+       /* A bool on weather or not the destination name will be taking from the input */
+       BOOL bSrcName = FALSE;
+       /* Seems like a waste but it is a pointer used to copy from input to PreserveName */
+       TCHAR * UseThisName;
+       /* Stores the name( i.e. blah.txt or blah*.txt) which later we might need */
+       TCHAR PreserveName[MAX_PATH];
+   /* for CMDCOPY env */
+   TCHAR *evar;
+   int size;
+       TCHAR * szTouch;
+       BOOL bDone = FALSE;
+       
+  /*Show help/usage info*/
+       if (!_tcsncmp (param, _T("/?"), 2))
        {
-               error_out_of_memory ();
-               DeleteFileList (sources);
-               free (real_source);
-               free (real_dest);
-               freep (p);
+               ConOutResPaging(TRUE, STRING_COPY_HELP2);
                return 0;
        }
+  nErrorLevel = 0;
 
-       while (sources->next != NULL)
-       {
+  /* Get the envor value if it exists */
+  evar = malloc(512 * sizeof(TCHAR));
+  if (evar==NULL) size = 0;
+  else
+  {
+   size = GetEnvironmentVariable (_T("COPYCMD"), evar, 512);  
+  }
+  if (size > 512)
+  {
+    evar = realloc(evar,size * sizeof(TCHAR) );
+    if (evar!=NULL)
+    {             
+      size = GetEnvironmentVariable (_T("COPYCMD"), evar, size);
+      }
+    else 
+    {
+      size=0;
+    }
+  }
 
-/*             Force a clean full path
-*/
-               GetFullPathName( sources->szFile, 128, (LPTSTR) &temp, NULL);
-               if (IsExistingDirectory(temp))
-               {
-                       _tcscat(temp, _T("\\*"));
-               }
+  /* check see if we did get any env variable */
+  if (size !=0)
+  {
+    int t=0;
+    /* scan and set the flags */
+    for (t=0;t<size;t++)
+    {
+      if (_tcsncicmp(_T("/A"),&evar[t],2)==0) 
+      {
+        dwFlags |=COPY_ASCII;
+        t++;
+      }
+
+      else if (_tcsncicmp(_T("/B"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_BINARY;
+        t++;
+      }
+      else if (_tcsncicmp(_T("/D"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_DECRYPT;
+        t++;
+      }
+
+                       else if (_tcsncicmp(_T("/V"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_VERIFY;
+        t++;
+      }
+
+                       else if (_tcsncicmp(_T("/N"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_SHORTNAME;
+        t++;
+      }
+      else if (_tcsncicmp(_T("/Y"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_NO_PROMPT;
+        t++;
+      }
+
+      else if (_tcsncicmp(_T("/-Y"),&evar[t],3)==0) 
+      {
+        dwFlags |= COPY_PROMPT;
+        t+=2;
+      }
+
+      else if (_tcsncicmp(_T("/Z"),&evar[t],2)==0) 
+      {
+        dwFlags |= COPY_PROMPT;
+        t++;
+      }
+    }
+  }
+  free(evar);
 
-               _tsplitpath (temp, drive_s, dir_s, file_s, ext_s);
 
-               hFind = FindFirstFile ((TCHAR*)&temp, &find);
-               if (hFind == INVALID_HANDLE_VALUE)
+  /*Split the user input into array*/
+       arg = split (param, &argc, FALSE);
+       nFiles = argc;
+       /*Read switches and count files*/
+       for (i = 0; i < argc; i++)
+       {
+               if (*arg[i] == _T('/'))
                {
-                       error_file_not_found();
-                       freep(p);
-                       free(real_source);
-                       free(real_dest);
-                       return 0;
+                       if (_tcslen(arg[i]) >= 2)
+                       {
+                               switch (_totupper(arg[i][1]))
+                               {
+                               case _T('A'):
+                                       dwFlags |= COPY_ASCII;
+                                       break;
+                               case _T('B'):
+                                       dwFlags |= COPY_BINARY;
+                                       break;
+                               case _T('D'):
+                                       dwFlags |= COPY_DECRYPT;
+                                       break;
+                               case _T('V'):
+                                       dwFlags |= COPY_VERIFY;
+                                       break;
+                               case _T('N'):
+                                       dwFlags |= COPY_SHORTNAME;
+                                       break;
+                               case _T('Y'):
+                                       dwFlags |= COPY_NO_PROMPT;
+                                       dwFlags &= ~COPY_PROMPT;
+                                       break;
+                               case _T('-'):
+                                       if(_tcslen(arg[i]) >= 3)
+                                               if(_totupper(arg[i][2]) == _T('Y'))
+                                               {
+                                                       dwFlags &= ~COPY_NO_PROMPT;
+                                                       dwFlags |= COPY_PROMPT;
+                                               }
+                                               break;
+                               case _T('Z'):
+                                       dwFlags |= COPY_RESTART;
+                                       break;
+                               default:
+                                       /* invaild switch */
+          LoadString(CMD_ModuleHandle, STRING_ERROR_INVALID_SWITCH, szMsg, RC_STRING_MAX_SIZE);
+               ConOutPrintf(szMsg, _totupper(arg[i][1]));
+                                       
+                                       return 1;
+                                       break;
+                               }
+                       }
+                       /*If it was a switch, subtract from total arguments*/
+                       nFiles--;
                }
-
-               do
+               else
                {
-                       if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                               goto next;
-
-                       _tmakepath(from_merge, drive_d, dir_d, file_d, ext_d);
-
-                       if (from_merge[_tcslen(from_merge) - 1] == _T('\\'))
-                               from_merge[_tcslen(from_merge) - 1] = 0;
-
-//                     printf("Merge %s, filename %s\n", from_merge, find.cFileName);
-
-                       if (IsExistingDirectory (from_merge))
+                       /*if it isnt a switch then it is the source or destination*/
+                       if(nSrc == -1)
                        {
-
-//                     printf("Merge DIR\n");
-
-                               bMultiple = FALSE;
-                               _tcscat (from_merge, _T("\\"));
-                               _tcscat (from_merge, find.cFileName);
+                               nSrc = i;
                        }
-                       else
-                               bMultiple = TRUE;
-
-                       _tcscpy (real_dest, from_merge);
-                       _tmakepath (real_source, drive_s, dir_s, find.cFileName, NULL);
-
-#ifdef _DEBUG
-                       DebugPrintf(_T("copying %S -> %S (%Sappending%S)\n"),
-                                                real_source, real_dest,
-                                                *append ? _T("") : _T("not "),
-                                                sources->dwFlag & ASCII ? _T(", ASCII") : _T(", BINARY"));
-#endif
-
-                       if (IsExistingFile (real_dest) && !bAll)
+                       else if(*arg[i] == _T('+') || *arg[i] == _T(','))
                        {
-                               /* Don't prompt in a batch file */
-                               if (bc != NULL)
-                               {
-                                       bAll = TRUE;
-                               }
-                               else
-                               {
-                                       int over;
-
-                                       over = Overwrite (real_dest);
-                                       if (over == 2)
-                                               bAll = TRUE;
-                                       else if (over == 0)
-                                               goto next;
-                                       else if (bMultiple)
-                                               bAll = TRUE;
-                               }
+                               /* Add these onto the source string
+                                  this way we can do all checks
+                                       directly on source string later on */
+                               _tcscat(arg[nSrc],arg[i]);
+                               nFiles--;
+                       }                               
+                       else if(nDes == -1)
+                       {
+                               nDes = i;
                        }
-                       if (copy (real_source, real_dest, *append, lpdwFlags))
-                               nCopied++;
-               next:
-                       bDone = FindNextFile (hFind, &find);
-
-                       if (bMultiple)
-                               *append = 1;
                }
-               while (bDone);
-
-               FindClose (hFind);
-               sources = sources->next;
-
        }
-       free (real_source);
-       free (real_dest);
-
-       return nCopied;
-}
-
-
-INT cmd_copy (LPTSTR first, LPTSTR rest)
-{
-       TCHAR **p;
-       TCHAR drive_d[_MAX_DRIVE];
-       TCHAR dir_d[_MAX_DIR];
-       TCHAR file_d[_MAX_FNAME];
-       TCHAR ext_d[_MAX_EXT];
-       TCHAR szMsg[RC_STRING_MAX_SIZE];
-
-       int argc;
-       int append;
-       int files;
-       int copied;
-
-       LPFILES sources = NULL;
-       LPFILES start = NULL;
-       FILES dest;
-       BOOL bMultiple;
-       BOOL bWildcards;
-       BOOL bDestFound;
-       DWORD dwFlags = 0;
-
-  ConOutPrintf(_T("string : %s\n"),rest);
-       if (!_tcsncmp (rest, _T("/?"), 2))
+       if(nFiles < 1)
        {
-               ConOutResPaging(TRUE,STRING_COPY_HELP2);
+               /* There is not enough files, there has to be at least 1 */
+               ConOutResPuts(STRING_ERROR_REQ_PARAM_MISSING);
+               freep (arg);
                return 1;
        }
-
-       p = split (rest, &argc, FALSE);
-
-       if (argc == 0)
+       if(nFiles > 2)
        {
-               error_req_param_missing ();
-               return 0;
+               /* there is too many file names in command */
+      LoadString(CMD_ModuleHandle, STRING_ERROR_TOO_MANY_PARAMETERS, szMsg, RC_STRING_MAX_SIZE);
+          ConErrPrintf(szMsg,_T(""));          
+      nErrorLevel = 1;
+               freep (arg);
+               return 1;
        }
-
-       sources = (LPFILES)malloc (sizeof (FILES));
-       if (!sources)
+       if(((_tcschr (arg[nSrc], _T('+')) != NULL) ||
+               (_tcschr (arg[nSrc], _T('*')) != NULL && _tcschr (arg[nDes], _T('*')) == NULL) ||
+               (IsExistingDirectory (arg[nSrc]) && (_tcschr (arg[nDes], _T('*')) == NULL && !IsExistingDirectory (arg[nDes])))
+               ))
+       {
+               /* There is a + in the source filename, this means
+               that there is more then one file being put into
+               one file. */
+               bAppend = TRUE;
+               if(_tcschr (arg[nSrc], _T('+')) != NULL)
+                  appendPointer = arg[nSrc];
+       }
+       /* Reusing the number of files variable */
+       nFiles = 0;
+       do
        {
-               error_out_of_memory ();
-               return 0;
-       }
-       sources->next = NULL;
-       sources->dwFlag = 0;
-
-       if ((files = ParseCommand (sources, argc, p, &dwFlags)) == -1)
+       /* Set up the string that is the path to the destination */
+       if(nDes != -1)
        {
-               DeleteFileList (sources);
-               freep (p);
-               return 0;
+               if(_tcslen(arg[nDes]) == 2 && arg[nDes][1] == _T(':'))
+               {
+                       GetRootPath(arg[nDes],szDestPath,MAX_PATH);
+               }
+               else
+               /* If the user entered two file names then form the full string path*/
+               GetFullPathName (arg[nDes], MAX_PATH, szDestPath, NULL);
        }
-       else if (files == 0)
+       else
        {
-               error_req_param_missing();
-               DeleteFileList (sources);
-               freep (p);
-               return 0;
+               /* If no destination was entered then just use 
+               the current directory as the destination */
+               GetCurrentDirectory (MAX_PATH, szDestPath);
        }
-       start = sources;
-
-       bDestFound = GetDestination (sources, &dest);
-       if (bDestFound)
+       /* Get the full string of the path to the source file*/
+       if(_tcschr (arg[nSrc], _T('+')) != NULL)
        {
-               _tsplitpath (dest.szFile, drive_d, dir_d, file_d, ext_d);
-               if (IsExistingDirectory (dest.szFile))
+               _tcscpy(tmpName,_T("\0"));
+               /* Loop through the source file name and copy all
+               the chars one at a time until it gets too + */
+               while(TRUE)
                {
-//             printf("A szFile= %s, Dir = %s, File = %s, Ext = %s\n", dest.szFile, dir_d, file_d, ext_d);
-                       _tcscat (dir_d, file_d);
-                       _tcscat (dir_d, ext_d);
-                       file_d[0] = _T('\0');
-                       ext_d[0] = _T('\0');
-               }
-       }
-
-       if (_tcschr (dest.szFile, _T('*')) || _tcschr (dest.szFile, _T('?')))
-               bWildcards = TRUE;
-       else
-               bWildcards = FALSE;
-
-       if (_tcschr(rest, _T('+')))
-               bMultiple = TRUE;
-       else
-               bMultiple = FALSE;
-
-       append = 0;
-       copied = 0;
+                       if(!_tcsncmp (appendPointer,_T("+"),1) || !_tcsncmp (appendPointer,_T("\0"),1))
+                       {
+                               /* Now that the pointer is on the + we 
+                                  need to go to the start of the next filename */
+                               if(!_tcsncmp (appendPointer,_T("+"),1))
+                                  appendPointer++;
+                               else
+                                       bDone = TRUE;
+                               break;
 
-       if (bDestFound && !bWildcards)
-       {
+                       }
+                       
+                       _tcsncat(tmpName,appendPointer,1);
+                       appendPointer++;
 
-//             _tcscpy(sources->szFile, dest.szFile);
+               }
+               /* Finish the string off with a null char */
+               _tcsncat(tmpName,_T("\0"),1);
+                       
+               if(_tcschr (arg[nSrc], _T(',')) != NULL)
+                       {
+                               /* Only time there is a , in the source is when they are using touch
+                                  Cant have a destination and can only have on ,, at the end of the string 
+                                       Cant have more then one file name */
+                               szTouch = _tcsstr (arg[nSrc], _T("+"));
+                               if(_tcsncmp (szTouch,_T("+,,\0"),4) || nDes != -1)
+                               {
+                                       LoadString(CMD_ModuleHandle, STRING_ERROR_INVALID_PARAM_FORMAT, szMsg, RC_STRING_MAX_SIZE);
+                                       ConErrPrintf(szMsg,arg[nSrc]);          
+                                       nErrorLevel = 1;
+                                       freep (arg);
+                                       return 1;
+                               }
+                               bTouch = TRUE;
+                               bDone = TRUE;
+                       }
 
-               copied = SetupCopy (sources, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags);
-       }
-       else if (bDestFound && bWildcards)
-       {
-               ConErrResPuts(STRING_COPY_ERROR4);
+               if(_tcslen(tmpName) == 2)
+               {
+                       if(tmpName[1] == _T(':'))
+                       {
 
-               DeleteFileList (sources);
-               freep (p);
-               return 0;
+                               GetRootPath(tmpName,szSrcPath,MAX_PATH);
+                       }
+               }
+               else
+               /* Get the full path to first file in the string of file names */
+               GetFullPathName (tmpName, MAX_PATH, szSrcPath, NULL);   
        }
-       else if (!bDestFound && !bMultiple)
+       else
        {
-               _tsplitpath (sources->szFile, drive_d, dir_d, file_d, ext_d);
-               if (IsExistingDirectory (sources->szFile))
+               bDone = TRUE;
+               if(_tcslen(arg[nSrc]) == 2 && arg[nSrc][1] == _T(':'))
                {
-//             printf("B File = %s, Ext = %s\n", file_d, ext_d);
-
-                       _tcscat (dir_d, file_d);
-                       _tcscat (dir_d, ext_d);
-                       file_d[0] = _T('\0');
-                       ext_d[0] = _T('\0');
+                       GetRootPath(arg[nSrc],szSrcPath,MAX_PATH);
                }
-               copied = SetupCopy (sources, p, FALSE, _T(""), _T(""), file_d, ext_d, &append, &dwFlags);
+               else
+               /* Get the full path of the source file */
+               GetFullPathName (arg[nSrc], MAX_PATH, szSrcPath, NULL);
+       }
+       /* From this point on, we can assume that the shortest path is 3 letters long
+       and that would be [DriveLetter]:\ */
+       /* If there is no * in the path name and it is a folder
+       then we will need to add a wildcard to the pathname
+       so FindFirstFile comes up with all the files in that
+       folder */
+       if(_tcschr (szSrcPath, _T('*')) == NULL && 
+               IsExistingDirectory (szSrcPath))
+       {
+               /* If it doesnt have a \ at the end already then on needs to be added */
+               if(szSrcPath[_tcslen(szSrcPath) -  1] != _T('\\'))
+                       _tcscat (szSrcPath, _T("\\"));
+               /* Add a wildcard after the \ */
+               _tcscat (szSrcPath, _T("*"));
+       }
+       /* Make sure there is an ending slash to the path if the dest is a folder */
+       if(_tcschr (szDestPath, _T('*')) == NULL && 
+               IsExistingDirectory(szDestPath))
+       {
+               if(szDestPath[_tcslen(szDestPath) -  1] != _T('\\'))
+                       _tcscat (szDestPath, _T("\\"));
+       }
+       /* Get a list of all the files */
+       hFile = FindFirstFile (szSrcPath, &findBuffer);
+       
+       /* We need to figure out what the name of the file in the is going to be */
+       if((szDestPath[_tcslen(szDestPath) -  1] == _T('*') && szDestPath[_tcslen(szDestPath) -  2] == _T('\\')) ||
+               szDestPath[_tcslen(szDestPath) -  1] == _T('\\'))
+       {
+               /* In this case we will be using the same name as the source file
+               for the destination file because destination is a folder */
+               bSrcName = TRUE;
        }
        else
        {
-               _tsplitpath(sources->szFile, drive_d, dir_d, file_d, ext_d);
-               if (IsExistingDirectory (sources->szFile))
+               /* Save the name the user entered */
+               UseThisName = _tcsrchr(szDestPath,_T('\\'));
+               UseThisName++;
+               _tcscpy(PreserveName,UseThisName);
+       }
+       /* Strip the paths back to the folder they are in */
+       for(i = (_tcslen(szSrcPath) -  1); i > -1; i--)
+               if(szSrcPath[i] != _T('\\'))
+                       szSrcPath[i] = _T('\0');
+               else
+                       break;
+       for(i = (_tcslen(szDestPath) -  1); i > -1; i--)
+               if(szDestPath[i] != _T('\\'))
+                       szDestPath[i] = _T('\0');
+               else
+                       break;
+               do
                {
-//             printf("C File = %s, Ext = %s\n", file_d, ext_d);
+                       /* Set the override to yes each new file */
+                       nOverwrite = 1;
+                       /* If it couldnt open the file handle, print out the error */
+                       if(hFile == INVALID_HANDLE_VALUE)
+                       {                       
+                               ConOutFormatMessage (GetLastError(), szSrcPath);                        
+                               freep (arg);
+                               nErrorLevel = 1;
+                               return 1;
+                       }
+                       /* Ignore the . and .. files */
+                       if(!_tcscmp (findBuffer.cFileName, _T("."))  ||
+                               !_tcscmp (findBuffer.cFileName, _T(".."))||
+                               findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                               continue;
+                       /* Copy the base folder over to a tmp string */
+                       _tcscpy(tmpDestPath,szDestPath);
+                       /* Can't put a file into a folder that isnt there */
+                       if(!IsExistingDirectory(szDestPath))
+                       {
+                               ConOutFormatMessage (GetLastError (), szSrcPath);                       
+                               freep (arg);
+                               nErrorLevel = 1;
+                               return 1;
+                       }
+                       /* Copy over the destination path name */
+                       if(bSrcName)
+                               _tcscat (tmpDestPath, findBuffer.cFileName);
+                       else
+                       {
+                               /* If there is no wildcard you can use the name the user entered */
+                               if(_tcschr (PreserveName, _T('*')) == NULL)
+                               {
+                                       _tcscat (tmpDestPath, PreserveName);
+                               }
+                               else
+                               {
+                                       /* The following lines of copy were written by someone else
+                                       (most likely Eric Khoul) and it was taken from ren.c */
+                                       LPTSTR p,q,r;
+                                       TCHAR DoneFile[MAX_PATH];
+                                       /* build destination file name */
+                                       p = findBuffer.cFileName;
+                                       q = PreserveName;
+                                       r = DoneFile;
+                                       while(*q != 0)
+                                       {
+                                               if (*q == '*')
+                                               {
+                                                       q++;
+                                                       while (*p != 0 && *p != *q)
+                                                       {
+                                                               *r = *p;
+                                                               p++;
+                                                               r++;
+                                                       }
+                                               }
+                                               else if (*q == '?')
+                                               {
+                                                       q++;
+                                                       if (*p != 0)
+                                                       {
+                                                               *r = *p;
+                                                               p++;
+                                                               r++;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       *r = *q;
+                                                       if (*p != 0)
+                                                               p++;
+                                                       q++;
+                                                       r++;
+                                               }
+                                       }
+                                       *r = 0;
+                                       /* Add the filename to the tmp string path */
+                                       _tcscat (tmpDestPath, DoneFile);
+                               }
+                       }
 
-                       _tcscat (dir_d, file_d);
-                       _tcscat (dir_d, ext_d);
-                       file_d[0] = _T('\0');
-                       ext_d[0] = _T('\0');
-               }
+                       /* Build the string path to the source file */
+                       _tcscpy(tmpSrcPath,szSrcPath);
+                       _tcscat (tmpSrcPath, findBuffer.cFileName);
 
-               ConOutPuts (sources->szFile);
-               append = 1;
-               copied = SetupCopy (sources->next, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags) + 1;
-       }
+                       /* Check to see if the file is the same file */
+                       if(!bTouch && !_tcscmp (tmpSrcPath, tmpDestPath))
+                               continue;
+
+                       /* Handle any overriding / prompting that needs to be done */
+                       if(((!(dwFlags & COPY_NO_PROMPT) && IsExistingFile (tmpDestPath)) || dwFlags & COPY_PROMPT) && !bTouch)
+                               nOverwrite = Overwrite(tmpDestPath);
+                       if(nOverwrite == PROMPT_NO || nOverwrite == PROMPT_BREAK)
+                               continue;
+                       if(nOverwrite == PROMPT_ALL || (nOverwrite == PROMPT_YES && bAppend))
+                               dwFlags |= COPY_NO_PROMPT;
+
+                       /* Tell weather the copy was successful or not */
+                       if(copy(tmpSrcPath,tmpDestPath, bAppend, dwFlags, bTouch))
+                       {
+                               nFiles++;
+                               /* only print source name when more then one file */
+                               if(_tcschr (arg[nSrc], _T('+')) != NULL || _tcschr (arg[nSrc], _T('*')) != NULL)
+                                       ConOutPrintf(_T("%s\n"),findBuffer.cFileName);
+                               //LoadString(CMD_ModuleHandle, STRING_MOVE_ERROR1, szMsg, RC_STRING_MAX_SIZE);
+                       }
+                       else
+                       {
+                               /* print out the error message */
+                               LoadString(CMD_ModuleHandle, STRING_COPY_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+                               ConOutPrintf(szMsg);
+                               ConOutFormatMessage (GetLastError(), szSrcPath);
+                               nErrorLevel = 1;
+                       }
+
+               /* Loop through all wildcard files */
+               }while(FindNextFile (hFile, &findBuffer));
+       /* Loop through all files in src string with a + */
+       }while(!bDone);
 
-       DeleteFileList (sources);
-       freep ((VOID*)p);
+       /* print out the number of files copied */
+       LoadString(CMD_ModuleHandle, STRING_COPY_FILE, szMsg, RC_STRING_MAX_SIZE);
+       ConOutPrintf(szMsg, nFiles);
        
-       LoadString( CMD_ModuleHandle, STRING_COPY_FILE, szMsg, RC_STRING_MAX_SIZE);
-    ConOutPrintf (szMsg, copied);
+       CloseHandle(hFile);             
+  if (arg!=NULL) 
+      free(arg);
 
-       return 1;
+       return 0;
 }
 #endif /* INCLUDE_CMD_COPY */
-
-/* EOF */