*
* 20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>
* Unicode and redirection safe!
+ *
+ * 17-Oct-2001 (Eric Kohl <ekohl@rz.online.de>
+ * Implemented basic rename code.
*/
#include "config.h"
#include <windows.h>
#include <tchar.h>
#include <string.h>
+#include <ctype.h>
#include "cmd.h"
+#include "batch.h"
+
+enum
+{
+ REN_ATTRIBUTES = 0x001, /* /A : not implemented */
+ REN_ERROR = 0x002, /* /E */
+ REN_NOTHING = 0x004, /* /N */
+ REN_PROMPT = 0x008, /* /P : not implemented */
+ REN_QUIET = 0x010, /* /Q */
+ REN_SUBDIR = 0x020, /* /S */
+ REN_TOTAL = 0x040, /* /T */
+};
+
/*
- * simple file rename internal command.
+ * file rename internal command.
*
*/
INT cmd_rename (LPTSTR cmd, LPTSTR param)
{
- LPTSTR *arg;
- INT argc;
+ LPTSTR *arg = NULL;
+ INT args = 0;
+ INT nEvalArgs = 0; /* nunber of evaluated arguments */
+ DWORD dwFlags = 0;
+ DWORD dwFiles = 0; /* number of renamedd files */
+ INT i;
+ LPTSTR srcPattern = NULL;
+ LPTSTR dstPattern = NULL;
+ TCHAR dstFile[MAX_PATH];
+ BOOL bDstWildcard = FALSE;
+
+ LPTSTR p,q,r;
+
+ HANDLE hFile;
+ WIN32_FIND_DATA f;
+
+ if (!_tcsncmp(param, _T("/?"), 2))
+ {
+ ConOutPuts(_T("Renames a file/directory or files/directories.\n"
+ "\n"
+ "RENAME [/E /N /P /Q /S /T] old_name ... new_name\n"
+ "REN [/E /N /P /Q /S /T] old_name ... new_name\n"
+ "\n"
+ " /E No eror messages.\n"
+ " /N Nothing.\n"
+ " /P Prompts for confirmation before renaming each file.\n"
+ " (Not implemented yet!)\n"
+ " /Q Quiet.\n"
+ " /S Rename subdirectories.\n"
+ " /T Display total number of renamed files.\n"
+ "\n"
+ "Note that you cannot specify a new drive or path for your destination. Use\n"
+ "the MOVE command for that purpose."));
+ return(0);
+ }
+
+ /* split the argument list */
+ arg = split(param, &args);
- if (!_tcsncmp (param, _T("/?"), 2))
+ if (args < 2)
+ {
+ if (!(dwFlags & REN_ERROR))
+ error_req_param_missing();
+ freep(arg);
+ return(1);
+ }
+
+ /* read options */
+ for (i = 0; i < args; i++)
+ {
+ if (*arg[i] == _T('/'))
{
- ConOutPuts (_T("Renames a file/directory or files/directories.\n"
- "\n"
- "RENAME [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n"
- "REN [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n"
- "\n"
- "Note that you cannot specify a new drive or path for your destination. Use\n"
- "the MOVE command for that purpose."));
- return 0;
+ if (_tcslen(arg[i]) >= 2)
+ {
+ switch (_totupper(arg[i][1]))
+ {
+ case _T('E'):
+ dwFlags |= REN_ERROR;
+ break;
+
+ case _T('N'):
+ dwFlags |= REN_NOTHING;
+ break;
+
+ case _T('P'):
+ dwFlags |= REN_PROMPT;
+ break;
+
+ case _T('Q'):
+ dwFlags |= REN_QUIET;
+ break;
+
+ case _T('S'):
+ dwFlags |= REN_SUBDIR;
+ break;
+
+ case _T('T'):
+ dwFlags |= REN_TOTAL;
+ break;
+ }
+ }
+ nEvalArgs++;
}
+ }
+
+ /* keep quiet within batch files */
+ if (bc != NULL)
+ dwFlags |= REN_QUIET;
+
+ /* there are only options on the command line --> error!!! */
+ if (args < nEvalArgs + 2)
+ {
+ if (!(dwFlags & REN_ERROR))
+ error_req_param_missing();
+ freep(arg);
+ return(1);
+ }
- /* split the argument list */
- arg = split (param, &argc);
+ /* get destination pattern */
+ for (i = 0; i < args; i++)
+ {
+ if (*arg[i] == _T('/'))
+ continue;
+ dstPattern = arg[i];
+ }
- if (argc != 2)
+ if (_tcschr(dstPattern, _T('*')) || _tcschr(dstPattern, _T('?')))
+ bDstWildcard = TRUE;
+
+ /* enumerate source patterns */
+ for (i = 0; i < args; i++)
+ {
+ if (*arg[i] == _T('/') || arg[i] == dstPattern)
+ continue;
+
+ srcPattern = arg[i];
+
+#ifdef _DEBUG
+ ConErrPrintf(_T("\n\nSourcePattern: %s\n"), srcPattern);
+ ConErrPrintf(_T("DestinationPattern: %s\n"), dstPattern);
+#endif
+
+ hFile = FindFirstFile(srcPattern, &f);
+ if (hFile == INVALID_HANDLE_VALUE)
{
- freep (arg);
- error_too_many_parameters (param);
- return 1;
+ if (!(dwFlags & REN_ERROR))
+ error_file_not_found();
+ continue;
}
- if (!MoveFile (arg[0], arg[1]))
+ do
{
- ConErrPuts (_T("rename"));
- freep (arg);
- return 1;
+ /* ignore "." and ".." */
+ if (!_tcscmp (f.cFileName, _T(".")) ||
+ !_tcscmp (f.cFileName, _T("..")))
+ continue;
+
+ /* do not rename hidden or system files */
+ if (f.dwAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
+ continue;
+
+ /* do not rename directories when the destination pattern contains
+ * wildcards, unless option /S is used */
+ if ((f.dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ && bDstWildcard
+ && !(dwFlags & REN_SUBDIR))
+ continue;
+
+#ifdef _DEBUG
+ ConErrPrintf(_T("Found source name: %s\n"), f.cFileName);
+#endif
+
+ /* build destination file name */
+ p = f.cFileName;
+ q = dstPattern;
+ r = dstFile;
+ 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;
+
+#ifdef _DEBUG
+ ConErrPrintf(_T("DestinationFile: %s\n"), dstFile);
+#endif
+
+ if (!(dwFlags & REN_QUIET) && !(dwFlags & REN_TOTAL))
+ ConOutPrintf(_T("%s -> %s\n"), f.cFileName, dstFile);
+
+ /* rename the file */
+ if (!(dwFlags & REN_NOTHING))
+ {
+ if (MoveFile(f.cFileName, dstFile))
+ {
+ dwFiles++;
+ }
+ else
+ {
+ if (!(dwFlags & REN_ERROR))
+ ConErrPrintf(_T("MoveFile() failed. Error: %lu\n"), GetLastError());
+ }
+ }
}
+ while (FindNextFile(hFile, &f));
+ FindClose(hFile);
+ }
- freep (arg);
+ if (!(dwFlags & REN_QUIET))
+ {
+ if (dwFiles == 1)
+ ConOutPrintf(_T(" %lu file renamed\n"),
+ dwFiles);
+ else
+ ConOutPrintf(_T(" %lu files renamed\n"),
+ dwFiles);
+ }
- return 0;
+ freep(arg);
+
+ return(0);
}
#endif
+
+/* EOF */