Index: cmd/ren.c =================================================================== --- cmd/ren.c (revisión: 37561) +++ cmd/ren.c (copia de trabajo) @@ -3,6 +3,7 @@ * * * History: + * * * 27-Jul-1998 (John P Price ) * added config.h include @@ -18,6 +19,14 @@ * * 30-Apr-2005 (Magnus Olsen) ) * Remove all hardcode string to En.rc + * 25-Nov-2008 (Victor Martinez) Patch dedicated to Myrjala because her comprenhension 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 @@ -44,31 +53,52 @@ { LPTSTR *arg = NULL; INT args = 0; + INT nSlash = 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]; + + + 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 wildcarts*/ + 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 */ + /* Split the argument list.Args will be saved in arg vector*/ arg = split(param, &args, FALSE); - + if (args < 2) { if (!(dwFlags & REN_ERROR)) @@ -77,42 +107,43 @@ return 1; } - /* read options */ + /* Read options */ for (i = 0; i < args; i++) { + /* Lets check if we have a special option choosen 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; + 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('N'): + dwFlags |= REN_NOTHING; + break; + + case _T('P'): + dwFlags |= REN_PROMPT; + break; - case _T('P'): - dwFlags |= REN_PROMPT; - break; + case _T('Q'): + dwFlags |= REN_QUIET; + break; - case _T('Q'): - dwFlags |= REN_QUIET; - break; + case _T('S'): + dwFlags |= REN_SUBDIR; + break; - case _T('S'): - dwFlags |= REN_SUBDIR; - break; - - case _T('T'): - dwFlags |= REN_TOTAL; - break; + case _T('T'): + dwFlags |= REN_TOTAL; + break; + } + } + nEvalArgs++;//Save the number of the options. } - } - nEvalArgs++; - } } /* keep quiet within batch files */ @@ -123,122 +154,212 @@ if (args < nEvalArgs + 2) { if (!(dwFlags & REN_ERROR)) - error_req_param_missing(); - freep(arg); - return 1; + error_req_param_missing(); + freep(arg); + return 1; } - - /* get destination pattern */ + + + /* Get destination pattern and source pattern*/ for (i = 0; i < args; i++) { - if (*arg[i] == _T('/')) - continue; - dstPattern = arg[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(dstPattern, _T('*')) || _tcschr(dstPattern, _T('?'))) - bDstWildcard = TRUE; + if (_tcschr(srcPattern, _T('\\'))) //Checking if the Source (srcPattern) is a Path to the file + { + + bPath= TRUE; - /* enumerate source patterns */ - for (i = 0; i < args; i++) - { - if (*arg[i] == _T('/') || arg[i] == dstPattern) - continue; + //Splitting srcPath and srcFile. - srcPattern = arg[i]; + 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; + + } - TRACE("\n\nSourcePattern: %s\n", debugstr_aw(srcPattern)); - TRACE("DestinationPattern: %s\n", debugstr_aw(dstPattern)); - + + + } + + if (!_tcschr(srcPattern, _T('\\'))) //If srcPattern isnt 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(); - continue; - } - + { + if (!(dwFlags & REN_ERROR)) + error_file_not_found(); + + } do - { + { /* ignore "." and ".." */ - if (!_tcscmp (f.cFileName, _T(".")) || - !_tcscmp (f.cFileName, _T(".."))) - continue; + 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; + 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; + if ((f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + && bDstWildcard + && !(dwFlags & REN_SUBDIR)) + continue; - TRACE("Found source name: %s\n", debugstr_aw(f.cFileName)); + 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 == TRUE) + { + + _tcscpy(srcFinal,srcPath); + + _tcscat(srcFinal,f.cFileName); + + _tcscpy(dstFinal,dstPath); + _tcscat(dstFinal,dstLast); + + + }else{ + _tcscpy(srcFinal,f.cFileName); + _tcscpy(dstFinal,dstLast); - /* 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; + } + - TRACE("DestinationFile: %s\n", debugstr_aw(dstFile)); - if (!(dwFlags & REN_QUIET) && !(dwFlags & REN_TOTAL)) - ConOutPrintf(_T("%s -> %s\n"), f.cFileName, dstFile); + 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(f.cFileName, dstFile)) - { - dwFiles++; - } - else - { - if (!(dwFlags & REN_ERROR)) - { - ConErrResPrintf(STRING_REN_ERROR1, GetLastError()); - } - } - } - } + /* 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)) { @@ -247,9 +368,9 @@ else ConOutResPrintf(STRING_REN_HELP3, dwFiles); } - + freep(arg); - + return 0; } Index: cmd/ren.txt =================================================================== --- cmd/ren.txt (revisión: 0) +++ cmd/ren.txt (revisión: 0) @@ -0,0 +1,91 @@ +Made by Vicmarcal 23/11/08 + +THIS FILE HELPS TO EXPLAIN HOW REN IS NOW IMPLEMENTED. +**************************************************************** +(Please change or add latest modifications) +**************************************************************** +Before detailing the Rem code just 3 things: + +1)Ren can be used in 3 different ways: + +WAY #1:Full Path Way: +ren c:\ie\hello.txt c:\ie\hi.txt + +rename command will change the name of hello.txt->hi.txt. We have to be sure that both paths(c:\ie\ ) be the same.Since rename cant move files within Directories (MSDN). + +WAY #2:Semi Path Way: +ren c:\ie\hello.txt hi.txt + +This is a special feature,since this does the same as Way #1 but without telling the Destiny path.So this feature must be implemented also. + +WAY #3: Just file +ren hello.txt hi.txt + +So it changes the name of hello.txt in the current directory. + +2)Also can be used Wildcards.So be careful ;) + +3)Syntax errors: + +-Way #1 with different Subdirectories path: ren c:\ie\hello.txt c:\hi\hi.txt, this is not possible.Since ren doesnt move files,just rename them. +-Way #2 semi path in destiny: ren hello.txt c:\ie\hi.txt. This feature isnt available. + + +************************************************** +Explaining code: + + +srcPattern: here is stored Source Argument (C:\ie\hello.txt) +srcPath: here is stored Source Path(C:\ie) +srcFILE: here is stored FILE name(hello.txt) + +dstPattern: here is stored Destiny Argument (C:\ie\hi.txt) +dstPath: here is stored Destiny Path(C:\i) +dstFILE: here is stored FILE re-name(hi.txt) + +1)We begin retrieving arguments from command line and fulffilling dstPattern and srcPattern + + +2)If srcPattern contains "\" then: + -we activate bPath, since srcPattern has a path inside of it. + -we explit the srcPattern to srcFile and srcPath. + -Now we check the dstPattern ¿does it contain a Path?: + -If does: we divide it in dstPath and dstFile.AND ALSO CHECK THAT dstPath and srcPath it´s the same(see syntax error).If they aren the same we launch an error. + -If doesnt then we copy srcPath to dstPath(see #way2) and also saving dstPattern as dstFile. +3)If srcPattern doesnt contain "\" then: + -srcPattern is copied in srcFile(we dont need a previous split,because it´s just a name) + -Now we check the dstPattern ¿does it contains a Path? + -If does: we launch an error (see syntax error 2) + -If doesnt: we copy dstPattern to dstFile(we dont need a previous split because it´s just a name) + +4)Now we are entering in the do...while: + +"p" will store a REAL name file(It uses f.cFileName) +Real name file is the name that FindFile returns us.FindFile return NULL if it doesnt find the Source File that we want to rename.And returns the name if finds it. + +Do while is used to manage Wildcards.So we can iterate Finding all the files with the Wildcards in it. +But wildcards (? and *) has different behavior so we have to be carefull. + +"q" stores the srcFile(this can be a real name file but ALSO A NAME FULL OF WILDCARDS)(p always has a REAL NAME)(This is the most difficult point to understand the code) +"r" is the Name File after aplying the Mask (q)(it´s stored in dstLast). + +If we are just renaming one file,then we dont make the while loop.The do..while loop is made when some files are renamed: i.e ren *.lol *.rem + +5)Now we have to check our Boolean. + +bPath==TRUE means that Source Argument was a Path so now we have to Join again the Path with the Name File: + -srcFINAL: srcPath+f.cFileName + -dstFINAL: dstPath+dstFile +bPath==False then Souce wasn a Path an we dont need to join anything. + -srcFINAL:f.cFileName + -dstFINAL:dstFile + + +At last we just make a MoveFile(srcFinal, dstFinal)): + +Also there are a Bunch of Flags (the options) +.It makes the code more difficult to understand.But they are just option flags that show or hides errors,that prevents system files to be renamed...and so. + + + +