Fix 2 different files whose canonic names are the same can't be opened
in the same time issue Fix Unicode file name comparision to match Windows behaviour (as opposed to doing a linguistic filename comparision) Fixes #3820, closes #4141
This commit is contained in:
parent
7a0dae5912
commit
683c358e8a
@ -29,6 +29,7 @@
|
|||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <uxtheme.h>
|
#include <uxtheme.h>
|
||||||
|
#include <cassert>
|
||||||
#include "StaticDialog.h"
|
#include "StaticDialog.h"
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
@ -850,6 +851,64 @@ double stodLocale(const generic_string& str, _locale_t loc, size_t* idx)
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Source: https://blogs.msdn.microsoft.com/greggm/2005/09/21/comparing-file-names-in-native-code/
|
||||||
|
// Modified to use TCHAR's instead of assuming Unicode and reformatted to conform with Notepad++ code style
|
||||||
|
static TCHAR ToUpperInvariant(TCHAR input)
|
||||||
|
{
|
||||||
|
TCHAR result;
|
||||||
|
LONG lres = LCMapString(LOCALE_INVARIANT, LCMAP_UPPERCASE, &input, 1, &result, 1);
|
||||||
|
if (lres == 0)
|
||||||
|
{
|
||||||
|
assert(false and "LCMapString failed to convert a character to upper case");
|
||||||
|
result = input;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source: https://blogs.msdn.microsoft.com/greggm/2005/09/21/comparing-file-names-in-native-code/
|
||||||
|
// Modified to use TCHAR's instead of assuming Unicode and reformatted to conform with Notepad++ code style
|
||||||
|
int OrdinalIgnoreCaseCompareStrings(LPCTSTR sz1, LPCTSTR sz2)
|
||||||
|
{
|
||||||
|
if (sz1 == sz2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz1 == nullptr) sz1 = _T("");
|
||||||
|
if (sz2 == nullptr) sz2 = _T("");
|
||||||
|
|
||||||
|
for (;; sz1++, sz2++)
|
||||||
|
{
|
||||||
|
const TCHAR c1 = *sz1;
|
||||||
|
const TCHAR c2 = *sz2;
|
||||||
|
|
||||||
|
// check for binary equality first
|
||||||
|
if (c1 == c2)
|
||||||
|
{
|
||||||
|
if (c1 == 0)
|
||||||
|
{
|
||||||
|
return 0; // We have reached the end of both strings. No difference found.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c1 == 0 || c2 == 0)
|
||||||
|
{
|
||||||
|
return (c1-c2); // We have reached the end of one string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: this needs to be upper case to match the behavior of the operating system.
|
||||||
|
// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/StringsinNET20.asp
|
||||||
|
const TCHAR u1 = ToUpperInvariant(c1);
|
||||||
|
const TCHAR u2 = ToUpperInvariant(c2);
|
||||||
|
if (u1 != u2)
|
||||||
|
{
|
||||||
|
return (u1-u2); // strings are different
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool str2Clipboard(const generic_string &str2cpy, HWND hwnd)
|
bool str2Clipboard(const generic_string &str2cpy, HWND hwnd)
|
||||||
{
|
{
|
||||||
size_t len2Allocate = (str2cpy.size() + 1) * sizeof(TCHAR);
|
size_t len2Allocate = (str2cpy.size() + 1) * sizeof(TCHAR);
|
||||||
|
@ -178,6 +178,8 @@ generic_string stringJoin(const std::vector<generic_string>& strings, const gene
|
|||||||
generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable);
|
generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable);
|
||||||
double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL);
|
double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL);
|
||||||
|
|
||||||
|
int OrdinalIgnoreCaseCompareStrings(LPCTSTR sz1, LPCTSTR sz2);
|
||||||
|
|
||||||
bool str2Clipboard(const generic_string &str2cpy, HWND hwnd);
|
bool str2Clipboard(const generic_string &str2cpy, HWND hwnd);
|
||||||
|
|
||||||
generic_string GetLastErrorAsString(DWORD errorCode = 0);
|
generic_string GetLastErrorAsString(DWORD errorCode = 0);
|
||||||
|
@ -1409,7 +1409,7 @@ void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_st
|
|||||||
}
|
}
|
||||||
else if (isRecursive)
|
else if (isRecursive)
|
||||||
{
|
{
|
||||||
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
|
||||||
{
|
{
|
||||||
generic_string pathDir(dir);
|
generic_string pathDir(dir);
|
||||||
pathDir += foundData.cFileName;
|
pathDir += foundData.cFileName;
|
||||||
@ -1438,7 +1438,7 @@ void Notepad_plus::getMatchedFileNames(const TCHAR *dir, const vector<generic_st
|
|||||||
}
|
}
|
||||||
else if (isRecursive)
|
else if (isRecursive)
|
||||||
{
|
{
|
||||||
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
|
||||||
{
|
{
|
||||||
generic_string pathDir(dir);
|
generic_string pathDir(dir);
|
||||||
pathDir += foundData.cFileName;
|
pathDir += foundData.cFileName;
|
||||||
|
@ -95,7 +95,7 @@ DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params)
|
|||||||
if (pos == 2)
|
if (pos == 2)
|
||||||
fn.replace(pos, 2, TEXT("\\"));
|
fn.replace(pos, 2, TEXT("\\"));
|
||||||
|
|
||||||
if (lstrcmp(fullFileName, fn.c_str()) == 0)
|
if (OrdinalIgnoreCaseCompareStrings(fullFileName, fn.c_str()) == 0)
|
||||||
{
|
{
|
||||||
if (dwAction == FILE_ACTION_MODIFIED)
|
if (dwAction == FILE_ACTION_MODIFIED)
|
||||||
{
|
{
|
||||||
|
@ -194,13 +194,13 @@ void Buffer::setFileName(const TCHAR *fn, LangType defaultLang)
|
|||||||
|
|
||||||
if (newLang == defaultLang || newLang == L_TEXT) //language can probably be refined
|
if (newLang == defaultLang || newLang == L_TEXT) //language can probably be refined
|
||||||
{
|
{
|
||||||
if ((!generic_stricmp(_fileName, TEXT("makefile"))) || (!generic_stricmp(_fileName, TEXT("GNUmakefile"))))
|
if ((OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("makefile")) == 0) || (OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("GNUmakefile")) == 0))
|
||||||
newLang = L_MAKEFILE;
|
newLang = L_MAKEFILE;
|
||||||
else if (!generic_stricmp(_fileName, TEXT("CmakeLists.txt")))
|
else if (OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("CmakeLists.txt")) == 0)
|
||||||
newLang = L_CMAKE;
|
newLang = L_CMAKE;
|
||||||
else if ((!generic_stricmp(_fileName, TEXT("SConstruct"))) || (!generic_stricmp(_fileName, TEXT("SConscript"))) || (!generic_stricmp(_fileName, TEXT("wscript"))))
|
else if ((OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("SConstruct")) == 0) || (OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("SConscript")) == 0) || (OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("wscript")) == 0))
|
||||||
newLang = L_PYTHON;
|
newLang = L_PYTHON;
|
||||||
else if ((!generic_stricmp(_fileName, TEXT("Rakefile"))) || (!generic_stricmp(_fileName, TEXT("Vagrantfile"))))
|
else if ((OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("Rakefile")) == 0) || (OrdinalIgnoreCaseCompareStrings(_fileName, TEXT("Vagrantfile")) == 0))
|
||||||
newLang = L_RUBY;
|
newLang = L_RUBY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1507,7 +1507,7 @@ BufferID FileManager::getBufferFromName(const TCHAR* name)
|
|||||||
|
|
||||||
for(size_t i = 0; i < _buffers.size(); i++)
|
for(size_t i = 0; i < _buffers.size(); i++)
|
||||||
{
|
{
|
||||||
if (!lstrcmpi(name, _buffers.at(i)->getFullPathName()))
|
if (OrdinalIgnoreCaseCompareStrings(name, _buffers.at(i)->getFullPathName()) == 0)
|
||||||
return _buffers.at(i)->getID();
|
return _buffers.at(i)->getID();
|
||||||
}
|
}
|
||||||
return BUFFER_INVALID;
|
return BUFFER_INVALID;
|
||||||
|
@ -96,7 +96,7 @@ BufferID DocTabView::findBufferByName(const TCHAR * fullfilename) //-1 if not fo
|
|||||||
::SendMessage(_hSelf, TCM_GETITEM, i, reinterpret_cast<LPARAM>(&tie));
|
::SendMessage(_hSelf, TCM_GETITEM, i, reinterpret_cast<LPARAM>(&tie));
|
||||||
BufferID id = reinterpret_cast<BufferID>(tie.lParam);
|
BufferID id = reinterpret_cast<BufferID>(tie.lParam);
|
||||||
Buffer * buf = MainFileManager->getBufferByID(id);
|
Buffer * buf = MainFileManager->getBufferByID(id);
|
||||||
if (!lstrcmp(fullfilename, buf->getFullPathName()))
|
if (OrdinalIgnoreCaseCompareStrings(fullfilename, buf->getFullPathName()) == 0)
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -815,7 +815,7 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
|
|||||||
}
|
}
|
||||||
else if (isRecursive)
|
else if (isRecursive)
|
||||||
{
|
{
|
||||||
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
|
||||||
{
|
{
|
||||||
generic_string pathDir(dir);
|
generic_string pathDir(dir);
|
||||||
if (pathDir[pathDir.length() - 1] != '\\')
|
if (pathDir[pathDir.length() - 1] != '\\')
|
||||||
@ -848,7 +848,7 @@ void FileBrowser::getDirectoryStructure(const TCHAR *dir, const std::vector<gene
|
|||||||
}
|
}
|
||||||
else if (isRecursive)
|
else if (isRecursive)
|
||||||
{
|
{
|
||||||
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
|
||||||
{
|
{
|
||||||
generic_string pathDir(dir);
|
generic_string pathDir(dir);
|
||||||
if (pathDir[pathDir.length() - 1] != '\\')
|
if (pathDir[pathDir.length() - 1] != '\\')
|
||||||
|
@ -1129,7 +1129,7 @@ void ProjectPanel::recursiveAddFilesFrom(const TCHAR *folderPath, HTREEITEM hTre
|
|||||||
}
|
}
|
||||||
else if (isRecursive)
|
else if (isRecursive)
|
||||||
{
|
{
|
||||||
if ((lstrcmp(foundData.cFileName, TEXT("."))) && (lstrcmp(foundData.cFileName, TEXT(".."))))
|
if ((OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT(".")) != 0) && (OrdinalIgnoreCaseCompareStrings(foundData.cFileName, TEXT("..")) != 0))
|
||||||
{
|
{
|
||||||
generic_string pathDir(folderPath);
|
generic_string pathDir(folderPath);
|
||||||
if (folderPath[lstrlen(folderPath)-1] != '\\')
|
if (folderPath[lstrlen(folderPath)-1] != '\\')
|
||||||
|
@ -284,7 +284,7 @@ int LastRecentFileList::find(const TCHAR *fn)
|
|||||||
{
|
{
|
||||||
for(int i = 0; i < _size; ++i)
|
for(int i = 0; i < _size; ++i)
|
||||||
{
|
{
|
||||||
if (!lstrcmpi(_lrfl.at(i)._name.c_str(), fn))
|
if (OrdinalIgnoreCaseCompareStrings(_lrfl.at(i)._name.c_str(), fn) == 0)
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user