2 * REN.C - rename internal command.
8 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
9 * added config.h include
11 * 18-Dec-1998 (Eric Kohl)
12 * Added support for quoted long file names with spaces.
14 * 20-Jan-1999 (Eric Kohl)
15 * Unicode and redirection safe!
17 * 17-Oct-2001 (Eric Kohl)
18 * Implemented basic rename code.
20 * 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
21 * Remove all hardcoded strings in En.rc
23 * 25-Nov-2008 (Victor Martinez <vicmarcal@hotmail.com>)
24 * Patch dedicated to Myrjala because her comprehension and love :D
25 * Fixing following Bugs:
26 * -Wrong behavior with wildcards when Source and Destiny are Paths(FIXED).
27 * -Wrong general behavior (MSDN:"Rename cant move files between subdirectories")(FIXED)
28 * -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)
29 * (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.)
30 * -Implemented checkings if SourcePath and DestinyPath are differents.
36 #ifdef INCLUDE_CMD_RENAME
40 REN_ATTRIBUTES
= 0x001, /* /A : not implemented */
41 REN_ERROR
= 0x002, /* /E */
42 REN_NOTHING
= 0x004, /* /N */
43 REN_PROMPT
= 0x008, /* /P : not implemented */
44 REN_QUIET
= 0x010, /* /Q */
45 REN_SUBDIR
= 0x020, /* /S */
46 REN_TOTAL
= 0x040, /* /T */
51 * file rename internal command.
53 INT
cmd_rename (LPTSTR param
)
58 INT nEvalArgs
= 0; /* number of evaluated arguments */
60 DWORD dwFiles
= 0; /* number of renamed files */
63 LPTSTR srcPattern
= NULL
; /* Source Argument*/
64 TCHAR srcPath
[MAX_PATH
]; /*Source Path Directories*/
65 LPTSTR srcFILE
= NULL
; /*Contains the files name(s)*/
66 TCHAR srcFinal
[MAX_PATH
];
68 LPTSTR dstPattern
= NULL
; /*Destiny Argument*/
69 TCHAR dstPath
[MAX_PATH
]; /*Source Path Directories*/
70 LPTSTR dstFILE
= NULL
; /*Contains the files name(s)*/
72 TCHAR dstLast
[MAX_PATH
]; /*It saves the File name after unmasked with wildcards*/
73 TCHAR dstFinal
[MAX_PATH
]; /*It saves the Final destiny Path*/
75 BOOL bDstWildcard
= FALSE
;
82 /*If the PARAM=/? then show the help*/
83 if (!_tcsncmp(param
, _T("/?"), 2))
85 ConOutResPaging(TRUE
,STRING_REN_HELP1
);
91 /* Split the argument list.Args will be saved in arg vector*/
92 arg
= split(param
, &args
, FALSE
, FALSE
);
96 if (!(dwFlags
& REN_ERROR
))
97 error_req_param_missing();
103 for (i
= 0; i
< args
; i
++)
105 /* Lets check if we have a special option chosen and set the flag(s)*/
106 if (*arg
[i
] == _T('/'))
108 if (_tcslen(arg
[i
]) >= 2)
110 switch (_totupper(arg
[i
][1]))
113 dwFlags
|= REN_ERROR
;
117 dwFlags
|= REN_NOTHING
;
121 dwFlags
|= REN_PROMPT
;
125 dwFlags
|= REN_QUIET
;
129 dwFlags
|= REN_SUBDIR
;
133 dwFlags
|= REN_TOTAL
;
137 nEvalArgs
++;//Save the number of the options.
141 /* keep quiet within batch files */
143 dwFlags
|= REN_QUIET
;
145 /* there are only options on the command line --> error!!! */
146 if (args
< nEvalArgs
+ 2)
148 if (!(dwFlags
& REN_ERROR
))
149 error_req_param_missing();
154 /* Get destination pattern and source pattern*/
155 for (i
= 0; i
< args
; i
++)
157 if (*arg
[i
] == _T('/'))//We have find an Option.Jump it.
159 dstPattern
= arg
[i
]; //we save the Last argument as dstPattern
160 srcPattern
= arg
[i
-1];
163 if (_tcschr(srcPattern
, _T('\\'))) //Checking if the Source (srcPattern) is a Path to the file
167 //Splitting srcPath and srcFile.
169 srcFILE
= _tcschr(srcPattern
, _T('\\'));
171 while(_tcschr(srcFILE
, _T('\\')))
174 if (*srcFILE
==_T('\\')) nSlash
++ ;
175 if (!_tcschr(srcFILE
, _T('\\'))) break;
177 _tcsncpy(srcPath
,srcPattern
,_tcslen(srcPattern
)-_tcslen(srcFILE
));
179 if (_tcschr(dstPattern
, _T('\\'))) //Checking if the Destiny (dstPattern)is also a Path.And splitting dstPattern in dstPath and srcPath.
181 dstFILE
= _tcschr(dstPattern
, _T('\\'));
183 while(_tcschr(dstFILE
, _T('\\')))
186 if (*dstFILE
==_T('\\')) nSlash
++ ;
187 if (!_tcschr(dstFILE
, _T('\\'))) break;
189 _tcsncpy(dstPath
,dstPattern
,_tcslen(dstPattern
)-_tcslen(dstFILE
));
191 if ((_tcslen(dstPath
)!=_tcslen(srcPath
))||(_tcsncmp(srcPath
,dstPath
,_tcslen(srcPath
))!=0)) //If it has a Path,then MUST be equal than srcPath
193 error_syntax(dstPath
);
199 { //If Destiny hasnt a Path,then (MSDN says) srcPath is its Path.
200 _tcscpy(dstPath
,srcPath
);
205 if (!_tcschr(srcPattern
, _T('\\'))) //If srcPattern isn't a Path but a name:
208 if (_tcschr(dstPattern
, _T('\\')))
210 error_syntax(dstPattern
);
220 //Checking Wildcards.
221 if (_tcschr(dstFILE
, _T('*')) || _tcschr(dstFILE
, _T('?')))
224 TRACE("\n\nSourcePattern: %s SourcePath: %s SourceFile: %s", debugstr_aw(srcPattern
),debugstr_aw(srcPath
),debugstr_aw(srcFILE
));
225 TRACE("\n\nDestinationPattern: %s Destination Path:%s Destination File: %s\n", debugstr_aw(dstPattern
),debugstr_aw(dstPath
),debugstr_aw(dstFILE
));
227 hFile
= FindFirstFile(srcPattern
, &f
);
229 if (hFile
== INVALID_HANDLE_VALUE
)
231 if (!(dwFlags
& REN_ERROR
)) error_file_not_found();
235 /* ignore "." and ".." */
236 if (!_tcscmp (f
.cFileName
, _T(".")) || !_tcscmp (f
.cFileName
, _T("..")))
239 /* do not rename hidden or system files */
240 if (f
.dwFileAttributes
& (FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
))
243 /* do not rename directories when the destination pattern contains
244 * wildcards, unless option /S is used */
245 if ((f
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
246 bDstWildcard
&& !(dwFlags
& REN_SUBDIR
))
251 TRACE("Found source name: %s\n", debugstr_aw(f
.cFileName
));
252 /* So here we have splitted the dstFILE and we have find a f.cFileName(thanks to srcPattern)
253 * Now we have to use the mask (dstFILE) (which can have Wildcards) with f.cFileName to find destination file name(dstLast) */
262 while (*p
!= 0 && *p
!= *q
)
288 //Well we have splitted the Paths,so now we have to paste them again(if needed),thanks bPath.
291 _tcscpy(srcFinal
,srcPath
);
292 _tcscat(srcFinal
,f
.cFileName
);
293 _tcscpy(dstFinal
,dstPath
);
294 _tcscat(dstFinal
,dstLast
);
298 _tcscpy(srcFinal
,f
.cFileName
);
299 _tcscpy(dstFinal
,dstLast
);
302 TRACE("DestinationPath: %s\n", debugstr_aw(dstFinal
));
304 if (!(dwFlags
& REN_QUIET
) && !(dwFlags
& REN_TOTAL
))
305 ConOutPrintf(_T("%s -> %s\n"),srcFinal
, dstFinal
);
307 /* Rename the file */
308 if (!(dwFlags
& REN_NOTHING
))
310 if (MoveFile(srcFinal
, dstFinal
))
316 if (!(dwFlags
& REN_ERROR
))
317 ConErrResPrintf(STRING_REN_ERROR1
, GetLastError());
321 while (FindNextFile(hFile
, &f
));
323 //Closing and Printing errors.
326 if (!(dwFlags
& REN_QUIET
))
329 ConOutResPrintf(STRING_REN_HELP2
, dwFiles
);
331 ConOutResPrintf(STRING_REN_HELP3
, dwFiles
);