mirror of
https://github.com/reactos/reactos.git
synced 2024-08-24 12:18:57 +00:00
341 lines
9.7 KiB
C
341 lines
9.7 KiB
C
/*
|
|
* REN.C - rename internal command.
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
*
|
|
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
* added config.h include
|
|
*
|
|
* 18-Dec-1998 (Eric Kohl)
|
|
* Added support for quoted long file names with spaces.
|
|
*
|
|
* 20-Jan-1999 (Eric Kohl)
|
|
* Unicode and redirection safe!
|
|
*
|
|
* 17-Oct-2001 (Eric Kohl)
|
|
* Implemented basic rename code.
|
|
*
|
|
* 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
|
|
* Remove all hardcoded strings in En.rc
|
|
*
|
|
* 25-Nov-2008 (Victor Martinez <vicmarcal@hotmail.com>)
|
|
* Patch dedicated to Myrjala because her comprehension and love :D
|
|
* Fixing following Bugs:
|
|
* -Wrong behavior with wildcards when Source and Destiny are Paths(FIXED).
|
|
* -Wrong general behavior (MSDN:"Rename cant move files between subdirectories")(FIXED)
|
|
* -Wrong behavior when renaming without path in destiny:(i.e) "ren C:\text\as.txt list.txt" it moves as.txt and then rename it(FIXED)
|
|
* (MSDN: If there is a Path in Source and no Path in Destiny, then Destiny Path is Source Path,because never Ren has to be used to move.)
|
|
* -Implemented checkings if SourcePath and DestinyPath are differents.
|
|
*
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef INCLUDE_CMD_RENAME
|
|
|
|
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 */
|
|
};
|
|
|
|
|
|
/*
|
|
* file rename internal command.
|
|
*/
|
|
INT cmd_rename (LPTSTR param)
|
|
{
|
|
LPTSTR *arg = NULL;
|
|
INT args = 0;
|
|
INT nSlash = 0;
|
|
INT nEvalArgs = 0; /* number of evaluated arguments */
|
|
DWORD dwFlags = 0;
|
|
DWORD dwFiles = 0; /* number of renamed files */
|
|
INT i;
|
|
|
|
LPTSTR srcPattern = NULL; /* Source Argument*/
|
|
TCHAR srcPath[MAX_PATH]; /*Source Path Directories*/
|
|
LPTSTR srcFILE = NULL; /*Contains the files name(s)*/
|
|
TCHAR srcFinal[MAX_PATH];
|
|
|
|
LPTSTR dstPattern = NULL; /*Destiny Argument*/
|
|
TCHAR dstPath[MAX_PATH]; /*Source Path Directories*/
|
|
LPTSTR dstFILE = NULL; /*Contains the files name(s)*/
|
|
|
|
TCHAR dstLast[MAX_PATH]; /*It saves the File name after unmasked with wildcards*/
|
|
TCHAR dstFinal[MAX_PATH]; /*It saves the Final destiny Path*/
|
|
|
|
BOOL bDstWildcard = FALSE;
|
|
BOOL bPath = FALSE;
|
|
|
|
LPTSTR p,q,r;
|
|
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA f;
|
|
/*If the PARAM=/? then show the help*/
|
|
if (!_tcsncmp(param, _T("/?"), 2))
|
|
{
|
|
ConOutResPaging(TRUE,STRING_REN_HELP1);
|
|
return 0;
|
|
}
|
|
|
|
nErrorLevel = 0;
|
|
|
|
/* Split the argument list.Args will be saved in arg vector*/
|
|
arg = split(param, &args, FALSE, FALSE);
|
|
|
|
if (args < 2)
|
|
{
|
|
if (!(dwFlags & REN_ERROR))
|
|
error_req_param_missing();
|
|
freep(arg);
|
|
return 1;
|
|
}
|
|
|
|
/* Read options */
|
|
for (i = 0; i < args; i++)
|
|
{
|
|
/* Lets check if we have a special option chosen and set the flag(s)*/
|
|
if (*arg[i] == _T('/'))
|
|
{
|
|
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++;//Save the number of the options.
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Get destination pattern and source pattern*/
|
|
for (i = 0; i < args; i++)
|
|
{
|
|
if (*arg[i] == _T('/'))//We have find an Option.Jump it.
|
|
continue;
|
|
dstPattern = arg[i]; //we save the Last argument as dstPattern
|
|
srcPattern = arg[i-1];
|
|
}
|
|
|
|
if (_tcschr(srcPattern, _T('\\'))) //Checking if the Source (srcPattern) is a Path to the file
|
|
{
|
|
bPath= TRUE;
|
|
|
|
//Splitting srcPath and srcFile.
|
|
|
|
srcFILE = _tcschr(srcPattern, _T('\\'));
|
|
nSlash++;
|
|
while(_tcschr(srcFILE, _T('\\')))
|
|
{
|
|
srcFILE++;
|
|
if (*srcFILE==_T('\\')) nSlash++ ;
|
|
if (!_tcschr(srcFILE, _T('\\'))) break;
|
|
}
|
|
_tcsncpy(srcPath,srcPattern,_tcslen(srcPattern)-_tcslen(srcFILE));
|
|
|
|
if (_tcschr(dstPattern, _T('\\'))) //Checking if the Destiny (dstPattern)is also a Path.And splitting dstPattern in dstPath and srcPath.
|
|
{
|
|
dstFILE = _tcschr(dstPattern, _T('\\'));
|
|
nSlash=0;
|
|
while(_tcschr(dstFILE, _T('\\')))
|
|
{
|
|
dstFILE++;
|
|
if (*dstFILE==_T('\\')) nSlash++ ;
|
|
if (!_tcschr(dstFILE, _T('\\'))) break;
|
|
}
|
|
_tcsncpy(dstPath,dstPattern,_tcslen(dstPattern)-_tcslen(dstFILE));
|
|
|
|
if ((_tcslen(dstPath)!=_tcslen(srcPath))||(_tcsncmp(srcPath,dstPath,_tcslen(srcPath))!=0)) //If it has a Path,then MUST be equal than srcPath
|
|
{
|
|
error_syntax(dstPath);
|
|
freep(arg);
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{ //If Destiny hasnt a Path,then (MSDN says) srcPath is its Path.
|
|
_tcscpy(dstPath,srcPath);
|
|
dstFILE=dstPattern;
|
|
}
|
|
}
|
|
|
|
if (!_tcschr(srcPattern, _T('\\'))) //If srcPattern isn't a Path but a name:
|
|
{
|
|
srcFILE=srcPattern;
|
|
if (_tcschr(dstPattern, _T('\\')))
|
|
{
|
|
error_syntax(dstPattern);
|
|
freep(arg);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
dstFILE=dstPattern;
|
|
}
|
|
}
|
|
|
|
//Checking Wildcards.
|
|
if (_tcschr(dstFILE, _T('*')) || _tcschr(dstFILE, _T('?')))
|
|
bDstWildcard = TRUE;
|
|
|
|
TRACE("\n\nSourcePattern: %s SourcePath: %s SourceFile: %s", debugstr_aw(srcPattern),debugstr_aw(srcPath),debugstr_aw(srcFILE));
|
|
TRACE("\n\nDestinationPattern: %s Destination Path:%s Destination File: %s\n", debugstr_aw(dstPattern),debugstr_aw(dstPath),debugstr_aw(dstFILE));
|
|
|
|
hFile = FindFirstFile(srcPattern, &f);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!(dwFlags & REN_ERROR)) error_file_not_found();
|
|
}
|
|
do
|
|
{
|
|
/* ignore "." and ".." */
|
|
if (!_tcscmp (f.cFileName, _T(".")) || !_tcscmp (f.cFileName, _T("..")))
|
|
continue;
|
|
|
|
/* do not rename hidden or system files */
|
|
if (f.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
|
|
continue;
|
|
|
|
/* do not rename directories when the destination pattern contains
|
|
* wildcards, unless option /S is used */
|
|
if ((f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
bDstWildcard && !(dwFlags & REN_SUBDIR))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TRACE("Found source name: %s\n", debugstr_aw(f.cFileName));
|
|
/* So here we have splitted the dstFILE and we have find a f.cFileName(thanks to srcPattern)
|
|
* Now we have to use the mask (dstFILE) (which can have Wildcards) with f.cFileName to find destination file name(dstLast) */
|
|
p = f.cFileName;
|
|
q = dstFILE;
|
|
r = dstLast;
|
|
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;
|
|
//Well we have splitted the Paths,so now we have to paste them again(if needed),thanks bPath.
|
|
if (bPath != FALSE)
|
|
{
|
|
_tcscpy(srcFinal,srcPath);
|
|
_tcscat(srcFinal,f.cFileName);
|
|
_tcscpy(dstFinal,dstPath);
|
|
_tcscat(dstFinal,dstLast);
|
|
}
|
|
else
|
|
{
|
|
_tcscpy(srcFinal,f.cFileName);
|
|
_tcscpy(dstFinal,dstLast);
|
|
}
|
|
|
|
TRACE("DestinationPath: %s\n", debugstr_aw(dstFinal));
|
|
|
|
if (!(dwFlags & REN_QUIET) && !(dwFlags & REN_TOTAL))
|
|
ConOutPrintf(_T("%s -> %s\n"),srcFinal , dstFinal);
|
|
|
|
/* Rename the file */
|
|
if (!(dwFlags & REN_NOTHING))
|
|
{
|
|
if (MoveFile(srcFinal, dstFinal))
|
|
{
|
|
dwFiles++;
|
|
}
|
|
else
|
|
{
|
|
if (!(dwFlags & REN_ERROR))
|
|
ConErrResPrintf(STRING_REN_ERROR1, GetLastError());
|
|
}
|
|
}
|
|
}
|
|
while (FindNextFile(hFile, &f));
|
|
|
|
//Closing and Printing errors.
|
|
FindClose(hFile);
|
|
|
|
if (!(dwFlags & REN_QUIET))
|
|
{
|
|
if (dwFiles == 1)
|
|
ConOutResPrintf(STRING_REN_HELP2, dwFiles);
|
|
else
|
|
ConOutResPrintf(STRING_REN_HELP3, dwFiles);
|
|
}
|
|
|
|
freep(arg);
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* EOF */
|