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 hardcode string to En.rc
22 * 25-Nov-2008 (Victor Martinez) <vicmarcal@hotmail.com> Patch dedicated to Myrjala because her comprenhension and love :D
23 * Fixing following Bugs:
24 * -Wrong behavior with wildcards when Source and Destiny are Paths(FIXED).
25 * -Wrong general behavior (MSDN:"Rename cant move files between subdirectories")(FIXED)
26 * -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)
27 * (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.)
28 * -Implemented checkings if SourcePath and DestinyPath are differents.
34 #ifdef INCLUDE_CMD_RENAME
38 REN_ATTRIBUTES
= 0x001, /* /A : not implemented */
39 REN_ERROR
= 0x002, /* /E */
40 REN_NOTHING
= 0x004, /* /N */
41 REN_PROMPT
= 0x008, /* /P : not implemented */
42 REN_QUIET
= 0x010, /* /Q */
43 REN_SUBDIR
= 0x020, /* /S */
44 REN_TOTAL
= 0x040, /* /T */
49 * file rename internal command.
52 INT
cmd_rename (LPTSTR param
)
57 INT nEvalArgs
= 0; /* nunber of evaluated arguments */
59 DWORD dwFiles
= 0; /* number of renamedd 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
];
69 LPTSTR dstPattern
= NULL
; /*Destiny Argument*/
70 TCHAR dstPath
[MAX_PATH
]; /*Source Path Directories*/
71 LPTSTR dstFILE
= NULL
; /*Contains the files name(s)*/
73 TCHAR dstLast
[MAX_PATH
]; /*It saves the File name after unmasked with wildcarts*/
74 TCHAR dstFinal
[MAX_PATH
]; /*It saves the Final destiny Path*/
76 BOOL bDstWildcard
= FALSE
;
88 /*If the PARAM=/? then show the help*/
89 if (!_tcsncmp(param
, _T("/?"), 2))
93 ConOutResPaging(TRUE
,STRING_REN_HELP1
);
99 /* Split the argument list.Args will be saved in arg vector*/
100 arg
= split(param
, &args
, FALSE
);
104 if (!(dwFlags
& REN_ERROR
))
105 error_req_param_missing();
111 for (i
= 0; i
< args
; i
++)
113 /* Lets check if we have a special option choosen and set the flag(s)*/
114 if (*arg
[i
] == _T('/'))
116 if (_tcslen(arg
[i
]) >= 2)
118 switch (_totupper(arg
[i
][1]))
121 dwFlags
|= REN_ERROR
;
125 dwFlags
|= REN_NOTHING
;
129 dwFlags
|= REN_PROMPT
;
133 dwFlags
|= REN_QUIET
;
137 dwFlags
|= REN_SUBDIR
;
141 dwFlags
|= REN_TOTAL
;
145 nEvalArgs
++;//Save the number of the options.
149 /* keep quiet within batch files */
151 dwFlags
|= REN_QUIET
;
153 /* there are only options on the command line --> error!!! */
154 if (args
< nEvalArgs
+ 2)
156 if (!(dwFlags
& REN_ERROR
))
157 error_req_param_missing();
163 /* Get destination pattern and source pattern*/
164 for (i
= 0; i
< args
; i
++)
166 if (*arg
[i
] == _T('/'))//We have find an Option.Jump it.
168 dstPattern
= arg
[i
]; //we save the Last argument as dstPattern
169 srcPattern
= arg
[i
-1];
177 if (_tcschr(srcPattern
, _T('\\'))) //Checking if the Source (srcPattern) is a Path to the file
182 //Splitting srcPath and srcFile.
184 srcFILE
= _tcschr(srcPattern
, _T('\\'));
186 while(_tcschr(srcFILE
, _T('\\')))
189 if(*srcFILE
==_T('\\')) nSlash
++ ;
190 if(!_tcschr(srcFILE
, _T('\\'))) break;
192 _tcsncpy(srcPath
,srcPattern
,_tcslen(srcPattern
)-_tcslen(srcFILE
));
196 if(_tcschr(dstPattern
, _T('\\'))) //Checking if the Destiny (dstPattern)is also a Path.And splitting dstPattern in dstPath and srcPath.
198 dstFILE
= _tcschr(dstPattern
, _T('\\'));
200 while(_tcschr(dstFILE
, _T('\\')))
203 if(*dstFILE
==_T('\\')) nSlash
++ ;
204 if(!_tcschr(dstFILE
, _T('\\'))) break;
206 _tcsncpy(dstPath
,dstPattern
,_tcslen(dstPattern
)-_tcslen(dstFILE
));
208 if((_tcslen(dstPath
)!=_tcslen(srcPath
))||(_tcsncmp(srcPath
,dstPath
,_tcslen(srcPath
))!=0)) //If it has a Path,then MUST be equal than srcPath
210 error_syntax(dstPath
);
214 }else { //If Destiny hasnt a Path,then (MSDN says) srcPath is its Path.
216 _tcscpy(dstPath
,srcPath
);
226 if (!_tcschr(srcPattern
, _T('\\'))) //If srcPattern isnt a Path but a name:
229 if(_tcschr(dstPattern
, _T('\\')))
231 error_syntax(dstPattern
);
235 }else dstFILE
=dstPattern
;
238 //Checking Wildcards.
239 if (_tcschr(dstFILE
, _T('*')) || _tcschr(dstFILE
, _T('?')))
244 TRACE("\n\nSourcePattern: %s SourcePath: %s SourceFile: %s", debugstr_aw(srcPattern
),debugstr_aw(srcPath
),debugstr_aw(srcFILE
));
245 TRACE("\n\nDestinationPattern: %s Destination Path:%s Destination File: %s\n", debugstr_aw(dstPattern
),debugstr_aw(dstPath
),debugstr_aw(dstFILE
));
247 hFile
= FindFirstFile(srcPattern
, &f
);
249 if (hFile
== INVALID_HANDLE_VALUE
)
251 if (!(dwFlags
& REN_ERROR
))
252 error_file_not_found();
257 /* ignore "." and ".." */
258 if (!_tcscmp (f
.cFileName
, _T(".")) ||
259 !_tcscmp (f
.cFileName
, _T("..")))
262 /* do not rename hidden or system files */
263 if (f
.dwFileAttributes
& (FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
))
266 /* do not rename directories when the destination pattern contains
267 * wildcards, unless option /S is used */
268 if ((f
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
270 && !(dwFlags
& REN_SUBDIR
))
273 TRACE("Found source name: %s\n", debugstr_aw(f
.cFileName
));
274 /* So here we have splitted the dstFILE and we have find a f.cFileName(thanks to srcPattern)
275 * Now we have to use the mask (dstFILE) (which can have Wildcards) with f.cFileName to find destination file name(dstLast) */
284 while (*p
!= 0 && *p
!= *q
)
311 //Well we have splitted the Paths,so now we have to paste them again(if needed),thanks bPath.
315 _tcscpy(srcFinal
,srcPath
);
317 _tcscat(srcFinal
,f
.cFileName
);
319 _tcscpy(dstFinal
,dstPath
);
320 _tcscat(dstFinal
,dstLast
);
324 _tcscpy(srcFinal
,f
.cFileName
);
325 _tcscpy(dstFinal
,dstLast
);
331 TRACE("DestinationPath: %s\n", debugstr_aw(dstFinal
));
334 if (!(dwFlags
& REN_QUIET
) && !(dwFlags
& REN_TOTAL
))
336 ConOutPrintf(_T("%s -> %s\n"),srcFinal
, dstFinal
);
338 /* Rename the file */
339 if (!(dwFlags
& REN_NOTHING
))
344 if (MoveFile(srcFinal
, dstFinal
))
350 if (!(dwFlags
& REN_ERROR
))
352 ConErrResPrintf(STRING_REN_ERROR1
, GetLastError());
358 while (FindNextFile(hFile
, &f
));
359 //Closing and Printing errors.
364 if (!(dwFlags
& REN_QUIET
))
367 ConOutResPrintf(STRING_REN_HELP2
, dwFiles
);
369 ConOutResPrintf(STRING_REN_HELP3
, dwFiles
);