Reginald offers a built-in Function to copy a file (COPYFILE), and also a Function to move a file (MOVEFILE). These Functions support wildcard templates, so you can specify an entire group of files to copy/move with only a single call to the Function -- including even all files in a directory.

COPYFILE and MOVEFILE are very similiar. The only difference is that COPYFILE makes a duplicate of the original file in any directory of your chosing, perhaps giving the duplicate a new name. MOVEFILE moves the original file to any directory of your choosing, with perhaps a new file name (or if the file is to stay in its original location, then it's simply given a new name). MOVEFILE therefore affects the original file because no duplicate is made.

The first arg to each is the source file to be copied/moved. The second arg is the new name to be given to the file. COPYFILE also takes a third arg for some additional options.


Copying/Moving all files in a directory

As you've seen when you used MATCHNAME() to list the contents of an entire directory, your template consisted of the desired directory name, ending with a backslash. It's the same thing when you wish to copy/move all files in the directory with COPYFILE/MOVEFILE. Your source name should be the name of the desired directory which contains the files to copy/move, ending with a backslash.

You also need to provide a destination directory name (ie, where the files are copied/moved to). Again, your destination directory name will end with a backslash.

If COPYFILE/MOVEFILE successfully completes the operation, then an empty string is returned. Otherwise, if there is a problem, an error message is returned.

Note: The source and destination directories must exist. Otherwise an error message is returned. If needed, you can create the destination directory before you call COPYFILE/MOVEFILE, by first using the DIR function.

Here's an example of copying all files in the directory C:\MyDir to the directory C:\MyDir2:

/* Make sure that our destination directory exists. If
 * it doesn't, create it.
 */
error = DIR('C:\MyDir2') /* Note: 'C\MyDir2\' is also ok. */

/* Check for an error with the destination. */
IF error == "" THEN

   /* Copy the directory. */
   error = COPYFILE('C:\MyDir\', 'C:\MyDir2\')

/* Display any error. */
IF error \= "" THEN SAY error
Of course you could also copy from one drive to another, for example, from C:\MyDir to the directory D:\MyDir:
error = DIR('D:\MyDir')
IF error == "" THEN error = COPYFILE('C:\MyDir\', 'D:\MyDir\')
IF error \= "" THEN SAY error
MOVEFILE would work the same way. So you can simply replace COPYFILE with MOVEFILE in the above examples.

Note: You can omit the backslash at the end of the source and directory names (when you have no wildcard template to append to them). But it's a little more efficient to include the trailing backslash when you're certain that the directories exist.


Copying/Moving only files with a certain name pattern

Let's say that we wish to copy only those files in C:\Windows whose names end with a .TXT extension. For this, we need to append a wildcard template of *.TXT to our source directory name. In other words, for our first arg to COPYFILE, we'll pass C:\Windows\*.TXT. Let's assume that we wish to copy the files to the destination directory C:\TextFiles.

error = DIR('C:\TextFiles')
IF error == "" THEN error = COPYFILE('C:\Windows\*.txt', 'C:\TextFiles\')
IF error \= "" THEN SAY error
After the above, you would have a directory named C:\TextFiles containing duplicates of those files in C:\Windows whose names end with a .TXT extension. If you instead wanted to move those files, you could use MOVEFILE in the above example.

If you'd like to give the copied/moved files a new name, then you can use a wildcard template to indicate how you would like the names transformed. For example, if you want to strip off the extension and put a new extension of .BAK on the name, you add the wildcard template *.BAK to the end of the destination, as so:

error = DIR('C:\TextFiles')
IF error == "" THEN error = COPYFILE('C:\Windows\*.txt', 'C:\TextFiles\*.bak')
IF error \= "" THEN SAY error
After the above, you would have a directory named C:\TextFiles containing duplicates of those files in C:\Windows whose names end with a .TXT extension. But each duplicate's name would end with a .BAK extension instead of the .TXT extension.

Note: If you're giving the files new names, then you can eliminate the directory name on the source and/or destination if they happen to be the current directory. For example, assume that our current directory is C:\TextFiles (and it obviously already exists). Since our destination directory is the same, we can specify only the wildcard template:

error = COPYFILE('C:\Windows\*.txt', '*.bak')
IF error \= "" THEN SAY error

Copying/Moving a specific file

If you have a specific file to copy/move, then the source name will be that file. It must not end with a backslash. (In the following examples, we assume that the destination directory exists, and so omit a call to DIR() to create it. We'll also dispense with error checking).

Here we copy the file C:\Windows\system.ini to the C:\Backup directory.

error = COPYFILE('C:\Windows\system.ini', 'C:\Backup\')
If you wish to give the copy a new name, then you can specify the specific name you want. Here we name the new copy C:\Backup\system.bak.
error = COPYFILE('C:\Windows\system.ini', 'C:\Backup\system.bak')
Or, we could have used a wildcard template to achieve the same result, as so:
error = COPYFILE('C:\Windows\system.ini', 'C:\Backup\*.bak')
Once again, if you're giving the file a new name, then you can eliminate the directory name on the source and/or destination if they happen to be the current directory. For example, assume that our current directory is C:\Windows. Since our source directory is the same, we can specify only the filename part:
error = COPYFILE('system.ini', 'C:\Backup\*.bak')

Overwriting an existing file

If you try to copy a file to some destination, and you're using a name that is the same as some existing file already in the destination, then COPYFILE will report an error. If you instead prefer to overwrite that destination file, then you can specify the "R" option. For example, here we copy all text files in C:\Windows whose names end in .TXT extension, and rename them with .BAK extensions, overwriting any similiarly named files already in C:\TextFiles:

error = COPYFILE('C:\Windows\*.txt', 'C:\TextFiles\*.bak', 'R')

Copying/Moving a directory tree (ie, Recursive copy/move)

In those examples where we asked COPYFILE/MOVEFILE to copy/move all the files in a directory, you'll notice that sub-directories and their contents (ie, all of the files and additional sub-directories that may be inside of each sub-directory) were also not copied/moved. In other words, COPYFILE/MOVEFILE don't copy/move an entire directory tree. If you want to copy/move all sub-directories and their contents, then you'll need to use MATCHNAME to do a recursive search of all the sub-directories in a given directory, and make another COPYFILE/MOVEFILE call for each sub-directory (and another DIR() call to perhaps create it in the destination).

Here we have a function named CopyFolder. It is passed the name of a source directory to copy, the name of a destination directory, and the MATCHNAME search number. It copies all files in the source directory to the destination directory. And whenever CopyFolder encounters a sub-directory, it dives into that sub-directory to copy any files inside of that sub-directory too. CopyFolder does this by calling itself -- passing a new search number, and the name of the source and destination sub-directories. In other words, whenever it encounters a sub-directory, it starts up another, simultaneous MATCHNAME loop to query that new directory and copy its contents. It is also important to use the PROCEDURE keyword.

We'll write this function so that it returns an empty string if it is successful. If there is a problem, it will abort the copy process and return that error message.

/* Copies the contents of a folder and all sub-folders inside it */
CopyFolder: PROCEDURE

   /* Copy all files in this directory to destination directory.
    * Note: We overwrite any existing files.
    */
   error = COPYFILE(ARG(1), ARG(2), 'R')
   IF error \== "" THEN RETURN error

   /* DO UNTIL no more sub-directories. */
   DO UNTIL error \== ""

      /* Get the name of the next sub-directory inside of this directory. */
      error = MATCHNAME(ARG(3), 'name', ARG(1), 'D')

      /* No error? */
      IF error == "" THEN DO

         /* Make sure that the sub-directory exists in the destination. */
         error = DIR(ARG(2) || '\' || name)
         IF error \== "" THEN DO
BadCopyFolder:
             MATCHNAME(ARG(3))
             RETURN error
         END

         /* Copy all files in this sub-directory to destination sub-directory. */
         error = CopyFolder(ARG(1) || '\' || name, ARG(2) || '\' || name, ARG(3) + 1)
         IF error \== "" THEN SIGNAL BadCopyFolder

      END

   END

   /* Return an empty string if success, or an error message */
   IF error == 'DONE' THEN error = ""
   RETURN error
And here's an example of how you may call CopyFolder to copy all the files/sub-directories in C:\Windows to D:\Windows. We arbitrarily start with a search number of 1.
result = CopyFolder('C:\Windows', 'D:\Windows', 1)

/* Did CopyFolder complete its job? If not, display why. */
IF result \== "" THEN SAY result