1 /* 2 * REN.C - rename internal command. 3 * 4 * 5 * History: 6 * 7 * 8 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>) 9 * added config.h include 10 * 11 * 18-Dec-1998 (Eric Kohl) 12 * Added support for quoted long file names with spaces. 13 * 14 * 20-Jan-1999 (Eric Kohl) 15 * Unicode and redirection safe! 16 * 17 * 17-Oct-2001 (Eric Kohl) 18 * Implemented basic rename code. 19 * 20 * 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>) 21 * Remove all hardcoded strings in En.rc 22 * 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. 31 * 32 */ 33 34 #include "precomp.h" 35 36 #ifdef INCLUDE_CMD_RENAME 37 38 enum 39 { 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 */ 47 }; 48 49 50 /* 51 * file rename internal command. 52 */ 53 INT cmd_rename (LPTSTR param) 54 { 55 LPTSTR *arg = NULL; 56 INT args = 0; 57 INT nSlash = 0; 58 INT nEvalArgs = 0; /* number of evaluated arguments */ 59 DWORD dwFlags = 0; 60 DWORD dwFiles = 0; /* number of renamed files */ 61 INT i; 62 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]; 67 68 LPTSTR dstPattern = NULL; /*Destiny Argument*/ 69 TCHAR dstPath[MAX_PATH]; /*Source Path Directories*/ 70 LPTSTR dstFILE = NULL; /*Contains the files name(s)*/ 71 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*/ 74 75 BOOL bDstWildcard = FALSE; 76 BOOL bPath = FALSE; 77 78 LPTSTR p,q,r; 79 80 HANDLE hFile; 81 WIN32_FIND_DATA f; 82 /*If the PARAM=/? then show the help*/ 83 if (!_tcsncmp(param, _T("/?"), 2)) 84 { 85 ConOutResPaging(TRUE,STRING_REN_HELP1); 86 return 0; 87 } 88 89 nErrorLevel = 0; 90 91 /* Split the argument list.Args will be saved in arg vector*/ 92 arg = split(param, &args, FALSE, FALSE); 93 94 if (args < 2) 95 { 96 if (!(dwFlags & REN_ERROR)) 97 error_req_param_missing(); 98 freep(arg); 99 return 1; 100 } 101 102 /* Read options */ 103 for (i = 0; i < args; i++) 104 { 105 /* Lets check if we have a special option chosen and set the flag(s)*/ 106 if (*arg[i] == _T('/')) 107 { 108 if (_tcslen(arg[i]) >= 2) 109 { 110 switch (_totupper(arg[i][1])) 111 { 112 case _T('E'): 113 dwFlags |= REN_ERROR; 114 break; 115 116 case _T('N'): 117 dwFlags |= REN_NOTHING; 118 break; 119 120 case _T('P'): 121 dwFlags |= REN_PROMPT; 122 break; 123 124 case _T('Q'): 125 dwFlags |= REN_QUIET; 126 break; 127 128 case _T('S'): 129 dwFlags |= REN_SUBDIR; 130 break; 131 132 case _T('T'): 133 dwFlags |= REN_TOTAL; 134 break; 135 } 136 } 137 nEvalArgs++;//Save the number of the options. 138 } 139 } 140 141 /* keep quiet within batch files */ 142 if (bc != NULL) 143 dwFlags |= REN_QUIET; 144 145 /* there are only options on the command line --> error!!! */ 146 if (args < nEvalArgs + 2) 147 { 148 if (!(dwFlags & REN_ERROR)) 149 error_req_param_missing(); 150 freep(arg); 151 return 1; 152 } 153 154 /* Get destination pattern and source pattern*/ 155 for (i = 0; i < args; i++) 156 { 157 if (*arg[i] == _T('/'))//We have find an Option.Jump it. 158 continue; 159 dstPattern = arg[i]; //we save the Last argument as dstPattern 160 srcPattern = arg[i-1]; 161 } 162 163 if (_tcschr(srcPattern, _T('\\'))) //Checking if the Source (srcPattern) is a Path to the file 164 { 165 bPath= TRUE; 166 167 //Splitting srcPath and srcFile. 168 169 srcFILE = _tcschr(srcPattern, _T('\\')); 170 nSlash++; 171 while(_tcschr(srcFILE, _T('\\'))) 172 { 173 srcFILE++; 174 if (*srcFILE==_T('\\')) nSlash++ ; 175 if (!_tcschr(srcFILE, _T('\\'))) break; 176 } 177 _tcsncpy(srcPath,srcPattern,_tcslen(srcPattern)-_tcslen(srcFILE)); 178 179 if (_tcschr(dstPattern, _T('\\'))) //Checking if the Destiny (dstPattern)is also a Path.And splitting dstPattern in dstPath and srcPath. 180 { 181 dstFILE = _tcschr(dstPattern, _T('\\')); 182 nSlash=0; 183 while(_tcschr(dstFILE, _T('\\'))) 184 { 185 dstFILE++; 186 if (*dstFILE==_T('\\')) nSlash++ ; 187 if (!_tcschr(dstFILE, _T('\\'))) break; 188 } 189 _tcsncpy(dstPath,dstPattern,_tcslen(dstPattern)-_tcslen(dstFILE)); 190 191 if ((_tcslen(dstPath)!=_tcslen(srcPath))||(_tcsncmp(srcPath,dstPath,_tcslen(srcPath))!=0)) //If it has a Path,then MUST be equal than srcPath 192 { 193 error_syntax(dstPath); 194 freep(arg); 195 return 1; 196 } 197 } 198 else 199 { //If Destiny hasnt a Path,then (MSDN says) srcPath is its Path. 200 _tcscpy(dstPath,srcPath); 201 dstFILE=dstPattern; 202 } 203 } 204 205 if (!_tcschr(srcPattern, _T('\\'))) //If srcPattern isn't a Path but a name: 206 { 207 srcFILE=srcPattern; 208 if (_tcschr(dstPattern, _T('\\'))) 209 { 210 error_syntax(dstPattern); 211 freep(arg); 212 return 1; 213 } 214 else 215 { 216 dstFILE=dstPattern; 217 } 218 } 219 220 //Checking Wildcards. 221 if (_tcschr(dstFILE, _T('*')) || _tcschr(dstFILE, _T('?'))) 222 bDstWildcard = TRUE; 223 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)); 226 227 hFile = FindFirstFile(srcPattern, &f); 228 229 if (hFile == INVALID_HANDLE_VALUE) 230 { 231 if (!(dwFlags & REN_ERROR)) error_file_not_found(); 232 } 233 do 234 { 235 /* ignore "." and ".." */ 236 if (!_tcscmp (f.cFileName, _T(".")) || !_tcscmp (f.cFileName, _T(".."))) 237 continue; 238 239 /* do not rename hidden or system files */ 240 if (f.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) 241 continue; 242 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)) 247 { 248 continue; 249 } 250 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) */ 254 p = f.cFileName; 255 q = dstFILE; 256 r = dstLast; 257 while(*q != 0) 258 { 259 if (*q == '*') 260 { 261 q++; 262 while (*p != 0 && *p != *q) 263 { 264 *r = *p; 265 p++; 266 r++; 267 } 268 } 269 else if (*q == '?') 270 { 271 q++; 272 if (*p != 0) 273 { 274 *r = *p; 275 p++; 276 r++; 277 } 278 } 279 else 280 { 281 *r = *q; 282 if (*p != 0) p++; 283 q++; 284 r++; 285 } 286 } 287 *r = 0; 288 //Well we have splitted the Paths,so now we have to paste them again(if needed),thanks bPath. 289 if (bPath != FALSE) 290 { 291 _tcscpy(srcFinal,srcPath); 292 _tcscat(srcFinal,f.cFileName); 293 _tcscpy(dstFinal,dstPath); 294 _tcscat(dstFinal,dstLast); 295 } 296 else 297 { 298 _tcscpy(srcFinal,f.cFileName); 299 _tcscpy(dstFinal,dstLast); 300 } 301 302 TRACE("DestinationPath: %s\n", debugstr_aw(dstFinal)); 303 304 if (!(dwFlags & REN_QUIET) && !(dwFlags & REN_TOTAL)) 305 ConOutPrintf(_T("%s -> %s\n"),srcFinal , dstFinal); 306 307 /* Rename the file */ 308 if (!(dwFlags & REN_NOTHING)) 309 { 310 if (MoveFile(srcFinal, dstFinal)) 311 { 312 dwFiles++; 313 } 314 else 315 { 316 if (!(dwFlags & REN_ERROR)) 317 ConErrResPrintf(STRING_REN_ERROR, GetLastError()); 318 } 319 } 320 } 321 while (FindNextFile(hFile, &f)); 322 323 //Closing and Printing errors. 324 FindClose(hFile); 325 326 if (!(dwFlags & REN_QUIET)) 327 { 328 if (dwFiles == 1) 329 ConOutResPrintf(STRING_REN_HELP2, dwFiles); 330 else 331 ConOutResPrintf(STRING_REN_HELP3, dwFiles); 332 } 333 334 freep(arg); 335 return 0; 336 } 337 338 #endif 339 340 /* EOF */ 341