diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index c273572d..28a98dfb 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -433,76 +433,103 @@ std::string wstring2string(const std::wstring & rwString, UINT codepage) return ""; } -static TCHAR* convertFileName(TCHAR *buffer, const TCHAR *filename) +// Escapes ampersands in file name to use it in menu +template +generic_string convertFileName(T beg, T end) { - TCHAR *b = buffer; - const TCHAR *p = filename; - while (*p) + generic_string strTmp; + + for (T it = beg; it != end; ++it) { - if (*p == '&') *b++ = '&'; - *b++ = *p++; + if (*it == '&') strTmp.push_back('&'); + strTmp.push_back(*it); } - *b = 0; - return buffer; + + return strTmp; +} + +generic_string intToString(int val) +{ + std::vector vt; + bool isNegative = val < 0; + // can't use abs here because std::numeric_limits::min() has no positive representation + //val = std::abs(val); + + vt.push_back('0' + (TCHAR)(std::abs(val % 10))); + val /= 10; + while (val != 0) { + vt.push_back('0' + (TCHAR)(std::abs(val % 10))); + val /= 10; + } + + if (isNegative) + vt.push_back('-'); + + return generic_string(vt.rbegin(), vt.rend()); +} + +generic_string uintToString(unsigned int val) +{ + std::vector vt; + + vt.push_back('0' + (TCHAR)(val % 10)); + val /= 10; + while (val != 0) { + vt.push_back('0' + (TCHAR)(val % 10)); + val /= 10; + } + + return generic_string(vt.rbegin(), vt.rend()); } // Build Recent File menu entries from given -TCHAR *BuildMenuFileName(TCHAR *buffer, int len, int pos, const TCHAR *filename) +generic_string BuildMenuFileName(int filenameLen, unsigned int pos, const generic_string &filename) { - buffer[0] = 0; + generic_string strTemp; - TCHAR *itr = buffer; - TCHAR *end = buffer + MAX_PATH - 1; if (pos < 9) { - *itr++ = '&'; - *itr++ = '1' + (TCHAR)pos; + strTemp.push_back('&'); + strTemp.push_back('1' + (TCHAR)pos); } else if (pos == 9) { - *itr++ = '1'; - *itr++ = '&'; - *itr++ = '0'; + strTemp.append(TEXT("1&0")); } else { - wsprintf(itr, TEXT("%d"), pos+1); - itr = itr + lstrlen(itr); + strTemp.append(uintToString(pos + 1)); } - *itr++ = ':'; - *itr++ = ' '; + strTemp.append(TEXT(": ")); - if (len > 0) + if (filenameLen > 0) { - TCHAR cnvName[MAX_PATH*2]; - convertFileName(cnvName, filename); - ::PathCompactPathEx(itr, filename, len - (itr-buffer), 0); + std::vector vt(filenameLen + 1); + PathCompactPathExW(&vt[0], filename.c_str(), filenameLen + 1, 0); + strTemp.append(convertFileName(vt.begin(), vt.begin() + lstrlen(&vt[0]))); } else { - TCHAR cnvName[MAX_PATH]; - const TCHAR *s1; + // (filenameLen < 0) + generic_string::const_iterator it = filename.begin(); - if (len == 0) - s1 = PathFindFileName(filename); - else // (len < 0) - s1 = filename; + if (filenameLen == 0) + it += PathFindFileName(filename.c_str()) - filename.c_str(); - int len = lstrlen(s1); - if (len < (end-itr)) + // MAX_PATH is still here to keep old trimming behaviour. + if (filename.end() - it < MAX_PATH) { - lstrcpy(cnvName, s1); + strTemp.append(convertFileName(it, filename.end())); } else { - int n = (len-3-(itr-buffer))/2; - generic_strncpy(cnvName, s1, n); - lstrcpy(cnvName+n, TEXT("...")); - lstrcat(cnvName, s1 + lstrlen(s1) - n); + strTemp.append(convertFileName(it, it + MAX_PATH / 2 - 3)); + strTemp.append(TEXT("...")); + strTemp.append(convertFileName(filename.end() - MAX_PATH / 2, filename.end())); } - convertFileName(itr, cnvName); } - return buffer; + + return strTemp; } generic_string PathRemoveFileSpec(generic_string & path) diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 32220f7a..d4443d76 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -101,7 +101,7 @@ void ScreenRectToClientRect(HWND hWnd, RECT* rect); std::wstring string2wstring(const std::string & rString, UINT codepage); std::string wstring2string(const std::wstring & rwString, UINT codepage); bool isInList(const TCHAR *token, const TCHAR *list); -TCHAR *BuildMenuFileName(TCHAR *buffer, int len, int pos, const TCHAR *filename); +generic_string BuildMenuFileName(int filenameLen, unsigned int pos, const generic_string &filename); class WcharMbcsConvertor { public: diff --git a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp index 4bda157a..c9f71a47 100644 --- a/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp +++ b/PowerEditor/src/WinControls/WindowsDlg/WindowsDlg.cpp @@ -803,7 +803,6 @@ void WindowsMenu::initPopupMenu(HMENU hMenu, DocTabView *pTab) int id, pos; for (id=IDM_WINDOW_MRU_FIRST, pos=0; idgetBufferByIndex(pos); Buffer * buf = MainFileManager->getBufferByID(bufID); @@ -811,7 +810,12 @@ void WindowsMenu::initPopupMenu(HMENU hMenu, DocTabView *pTab) memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING|MIIM_STATE|MIIM_ID; - mii.dwTypeData = BuildMenuFileName(buffer, 60, pos, buf->getFileName()); + generic_string strBuffer(BuildMenuFileName(60, pos, buf->getFileName())); + // Can't make mii.dwTypeData = strBuffer.c_str() because of const cast. + // So, making temporary buffer for this. + std::vector vBuffer(strBuffer.begin(), strBuffer.end()); + vBuffer.push_back('\0'); + mii.dwTypeData = (&vBuffer[0]); mii.fState &= ~(MF_GRAYED|MF_DISABLED|MF_CHECKED); if (pos == curDoc) mii.fState |= MF_CHECKED; diff --git a/PowerEditor/src/lastRecentFileList.cpp b/PowerEditor/src/lastRecentFileList.cpp index 2940bd6d..8868add7 100644 --- a/PowerEditor/src/lastRecentFileList.cpp +++ b/PowerEditor/src/lastRecentFileList.cpp @@ -149,11 +149,10 @@ void LastRecentFileList::updateMenu() ::RemoveMenu(_hMenu, _lrfl.at(i)._id, MF_BYCOMMAND); } //Then readd them, so everything stays in sync - TCHAR buffer[MAX_PATH]; for(int j = 0; j < _size; j++) { - BuildMenuFileName(buffer, pNppParam->getRecentFileCustomLength(), j, _lrfl.at(j)._name.c_str()); - ::InsertMenu(_hMenu, _posBase + j, MF_BYPOSITION, _lrfl.at(j)._id, buffer); + generic_string strBuffer(BuildMenuFileName(pNppParam->getRecentFileCustomLength(), j, _lrfl.at(j)._name)); + ::InsertMenu(_hMenu, _posBase + j, MF_BYPOSITION, _lrfl.at(j)._id, strBuffer.c_str()); } }