Index: src/Resources/grepWin.rc =================================================================== --- src/Resources/grepWin.rc (revision 578) 2014-09-09 03:04:25 +0900 +++ src/Resources/grepWin.rc (working copy) 2015-07-23 01:08:26 +0900 @@ -56,9 +56,10 @@ PUSHBUTTON "...",IDC_SEARCHPATHBROWSE,421,20,15,14 GROUPBOX "Search in",IDC_GROUPSEARCHIN,7,10,437,29 CONTROL "Regex search",IDC_REGEXRADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,52,86,10 - CONTROL "Text search",IDC_TEXTRADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,108,52,139,10 + CONTROL "Text search",IDC_TEXTRADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,108,52,86,10 + CONTROL "Word match",IDC_WORDMATCH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,52,86,10 //+[JOJO] RTEXT "",IDC_REGEXOKLABEL,324,52,112,8 - LTEXT "Search &for:",IDC_SEARCHFORLABEL,14,65,46,8 + LTEXT "Search &for:",IDC_SEARCHFORLABEL,14,65,70,8 EDITTEXT IDC_SEARCHTEXT,83,64,336,14,ES_AUTOHSCROLL PUSHBUTTON "/",IDC_EDITMULTILINE1,421,64,15,14 LTEXT "Replace with:",IDC_REPLACEWITHLABEL,14,83,64,8 Index: src/AboutDlg.cpp =================================================================== --- src/AboutDlg.cpp (revision 632) +++ src/AboutDlg.cpp (working copy) @@ -42,7 +42,7 @@ InitDialog(hwndDlg, IDI_GREPWIN); CLanguage::Instance().TranslateWindow(*this); TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("grepWin version %ld.%ld.%ld.%ld"), GREPWIN_VERMAJOR, GREPWIN_VERMINOR, GREPWIN_VERMICRO, GREPWIN_VERBUILD); + _stprintf_s(buf, _countof(buf), _T("grepWin version %ld.%ld.%ld.%ld (japanese)"), GREPWIN_VERMAJOR, GREPWIN_VERMINOR, GREPWIN_VERMICRO, GREPWIN_VERBUILD); SetDlgItemText(*this, IDC_VERSIONINFO, buf); SetDlgItemText(*this, IDC_DATE, _T(GREPWIN_VERDATE)); m_link.ConvertStaticToHyperlink(hwndDlg, IDC_WEBLINK, _T("http://stefanstools.sourceforge.net")); Index: src/Bookmarks.cpp =================================================================== --- src/Bookmarks.cpp (revision 632) +++ src/Bookmarks.cpp (working copy) @@ -86,6 +86,7 @@ val += _T("\""); SetValue(bm.Name.c_str(), _T("replaceString"), val.c_str()); SetValue(bm.Name.c_str(), _T("useregex"), bm.UseRegex ? _T("true") : _T("false")); + SetValue(bm.Name.c_str(), _T("wordmatch"), bm.WordMatch ? _T("true") : _T("false")); //+[JOJO] SetValue(bm.Name.c_str(), _T("casesensitive"), bm.CaseSensitive ? _T("true") : _T("false")); SetValue(bm.Name.c_str(), _T("dotmatchesnewline"), bm.DotMatchesNewline ? _T("true") : _T("false")); SetValue(bm.Name.c_str(), _T("backup"), bm.Backup ? _T("true") : _T("false")); @@ -111,6 +112,7 @@ Delete(name.c_str(), _T("searchString"), true); Delete(name.c_str(), _T("replaceString"), true); Delete(name.c_str(), _T("useregex"), true); + Delete(name.c_str(), _T("wordmatch"), true); //+[JOJO] Delete(name.c_str(), _T("casesensitive"), true); Delete(name.c_str(), _T("dotmatchesnewline"), true); Delete(name.c_str(), _T("backup"), true); @@ -131,6 +133,7 @@ bk.Search = GetValue(name.c_str(), L"searchString", L""); bk.Replace = GetValue(name.c_str(), L"replaceString", L""); bk.UseRegex = wcscmp(GetValue(name.c_str(), L"useregex", L"false"), L"true") == 0; + bk.WordMatch = wcscmp(GetValue(name.c_str(), L"wordmatch", L"false"), L"true") == 0; //+[JOJO] bk.CaseSensitive = wcscmp(GetValue(name.c_str(), L"casesensitive", L"false"), L"true") == 0; bk.DotMatchesNewline = wcscmp(GetValue(name.c_str(), L"dotmatchesnewline", L"false"), L"true") == 0; bk.Backup = wcscmp(GetValue(name.c_str(), L"backup", L"false"), L"true") == 0; Index: src/Bookmarks.h =================================================================== --- src/Bookmarks.h (revision 632) +++ src/Bookmarks.h (working copy) @@ -26,6 +26,7 @@ public: Bookmark() : UseRegex(false) + , WordMatch(false) //+[JOJO] , CaseSensitive(false) , DotMatchesNewline(false) , Backup(false) @@ -43,6 +44,7 @@ std::wstring Search; std::wstring Replace; bool UseRegex; + bool WordMatch; //+[JOJO] bool CaseSensitive; bool DotMatchesNewline; bool Backup; Index: src/BookmarksDlg.cpp =================================================================== --- src/BookmarksDlg.cpp (revision 632) +++ src/BookmarksDlg.cpp (working copy) @@ -29,6 +29,7 @@ CBookmarksDlg::CBookmarksDlg(HWND hParent) : m_hParent(hParent) , m_bUseRegex(false) + , m_bWordMatch(false) //+[JOJO] , m_bCaseSensitive(false) , m_bDotMatchesNewline(false) , m_bBackup(false) @@ -157,6 +158,7 @@ RemoveQuotes(m_sExcludeDirs); RemoveQuotes(m_sFileMatch); m_bUseRegex = _tcscmp(m_bookmarks.GetValue(buf.get(), _T("useregex"), _T("false")), _T("true")) == 0; + m_bWordMatch = _tcscmp(m_bookmarks.GetValue(buf.get(), _T("wordmatch"), _T("false")), _T("true")) == 0; //+[JOJO] m_bCaseSensitive = _tcscmp(m_bookmarks.GetValue(buf.get(), _T("casesensitive"), _T("false")), _T("true")) == 0; m_bDotMatchesNewline = _tcscmp(m_bookmarks.GetValue(buf.get(), _T("dotmatchesnewline"), _T("false")), _T("true")) == 0; m_bBackup = _tcscmp(m_bookmarks.GetValue(buf.get(), _T("backup"), _T("false")), _T("true")) == 0; Index: src/BookmarksDlg.h =================================================================== --- src/BookmarksDlg.h (revision 632) +++ src/BookmarksDlg.h (working copy) @@ -37,6 +37,7 @@ std::wstring GetSelectedSearchString() const { return m_searchString; } std::wstring GetSelectedReplaceString() const { return m_replaceString; } bool GetSelectedUseRegex() const { return m_bUseRegex; } + bool GetSelectedWordMatch() const { return m_bWordMatch; } //+[JOJO] bool GetSelectedSearchCase() const { return m_bCaseSensitive; } bool GetSelectedDotMatchNewline() const { return m_bDotMatchesNewline; } bool GetSelectedBackup() const { return m_bBackup; } @@ -61,6 +62,7 @@ std::wstring m_searchString; std::wstring m_replaceString; bool m_bUseRegex; + bool m_bWordMatch; //+[JOJO] bool m_bCaseSensitive; bool m_bDotMatchesNewline; bool m_bBackup; Index: src/RegexTestDlg.cpp =================================================================== --- src/RegexTestDlg.cpp (revision 632) +++ src/RegexTestDlg.cpp (working copy) @@ -23,6 +23,7 @@ #include #include #include +#include "PathUtils.h" //+[JOJO] CRegexTestDlg::CRegexTestDlg(HWND hParent) @@ -203,10 +204,14 @@ rflags |= boost::match_not_dot_newline; RegexReplaceFormatter replaceFmt(m_replaceText); - replaceFmt.SetReplacePair(L"${filepath}", L"c:\\grepwintest\\file.txt"); - replaceFmt.SetReplacePair(L"${filename}", L"file"); - replaceFmt.SetReplacePair(L"${fileext}", L"txt"); - + //////////////////////////////////////////////////////////// + // [JOJO] + WCHAR filepath[] = L"c:\\grepwintest\\file.txt"; + replaceFmt.SetReplacePair(L"${filepath}", filepath); // reference gets replaced with the full path of the current file + replaceFmt.SetReplacePair(L"${filename}", CPathUtils::GetFileNameWithoutExtension(filepath)); // gets replaced with the filename without the file extension + replaceFmt.SetReplacePair(L"${.fileext}", CPathUtils::GetFileNameExtension(filepath)); //+[JOJO] + replaceFmt.SetReplacePair(L"${fileext}", CPathUtils::GetFileExtension(filepath)); // gets replaced with the file extension of the current file + //////////////////////////////////////////////////////////// replaceresult = regex_replace(m_textContent, expression, replaceFmt, rflags); while (boost::regex_search(start, end, whatc, expression, flags)) Index: src/RegexTestDlg.h =================================================================== --- src/RegexTestDlg.h (revision 632) +++ src/RegexTestDlg.h (working copy) @@ -40,6 +40,7 @@ std::wstring GetReplaceString() {return m_replaceText;} bool bDotMatchesNewline; + bool bWordMatch; //+[JOJO] bool bCaseSensitive; protected: LRESULT CALLBACK DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); Index: src/Resources/grepWin.rc =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: src/SearchDlg.cpp =================================================================== --- src/SearchDlg.cpp (revision 632) +++ src/SearchDlg.cpp (working copy) @@ -19,12 +19,7 @@ #include "stdafx.h" #include "resource.h" #include "SearchDlg.h" -#include "Registry.h" #include "DirFileEnum.h" -#include "TextFile.h" -#include "SearchInfo.h" -#include "UnicodeUtils.h" -#include "StringUtils.h" #include "BrowseFolder.h" #include "SysImageList.h" #include "ShellContextMenu.h" @@ -38,8 +33,7 @@ #include "RegexReplaceFormatter.h" #include "LineData.h" #include "Settings.h" -#include "SysInfo.h" -#include "Language.h" +#include "PathUtils.h" //+[JOJO] #include #include @@ -59,7 +53,8 @@ DWORD WINAPI SearchThreadEntry(LPVOID lpParam); UINT CSearchDlg::GREPWIN_STARTUPMSG = RegisterWindowMessage(_T("grepWin_StartupMessage")); -std::map linepositions; +std::wstring /*CSearchDlg::*/WSTR_INFOLABEL, /*CSearchDlg::*/WSTR_INFOLABELFILE; //+[JOJO] +int tempNumber = -1; //+[JOJO] CSearchDlg::CSearchDlg(HWND hParent) : m_searchedItems(0) @@ -84,12 +79,14 @@ , m_bCreateBackupC(false) , m_bUTF8(false) , m_bUTF8C(false) + , m_bWordMatch(false) //+[JOJO] + , m_bWordMatchC(false) //+[JOJO] , m_bCaseSensitive(false) , m_bCaseSensitiveC(false) , m_bDotMatchesNewline(false) , m_bDotMatchesNewlineC(false) , m_bSizeC(false) - , m_bAllSize(false) + , m_bAllSize(true) //[JOJO] -false , m_bReplace(false) , m_lSize(0) , m_sizeCmp(0) @@ -105,6 +102,7 @@ , m_regIncludeBinary(_T("Software\\grepWin\\IncludeBinary"), 1) , m_regCreateBackup(_T("Software\\grepWin\\CreateBackup")) , m_regUTF8(_T("Software\\grepWin\\UTF8")) + , m_regWordMatch(_T("Software\\grepWin\\WordMatch")) //+[JOJO] , m_regCaseSensitive(_T("Software\\grepWin\\CaseSensitive")) , m_regDotMatchesNewline(_T("Software\\grepWin\\DotMatchesNewline")) , m_regUseRegexForPaths(_T("Software\\grepWin\\UseFileMatchRegex")) @@ -273,6 +271,8 @@ m_bIncludeHidden = bPortable ? !!_wtoi(g_iniFile.GetValue(L"global", L"IncludeHidden", L"0")) : !!DWORD(m_regIncludeHidden); if (!m_bIncludeBinaryC) m_bIncludeBinaryC = bPortable ? !!_wtoi(g_iniFile.GetValue(L"global", L"IncludeBinary", L"0")) : !!DWORD(m_regIncludeBinary); + if (!m_bWordMatchC) + m_bWordMatch = bPortable ? !!_wtoi(g_iniFile.GetValue(L"global", L"WordMatch", L"0")) : !!DWORD(m_regWordMatch); //+[JOJO] if (!m_bCaseSensitiveC) m_bCaseSensitive = bPortable ? !!_wtoi(g_iniFile.GetValue(L"global", L"CaseSensitive", L"0")) : !!DWORD(m_regCaseSensitive); if (!m_bDotMatchesNewlineC) @@ -297,6 +297,7 @@ SendDlgItemMessage(hwndDlg, IDC_INCLUDESYSTEM, BM_SETCHECK, m_bIncludeSystem ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_INCLUDEHIDDEN, BM_SETCHECK, m_bIncludeHidden ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_INCLUDEBINARY, BM_SETCHECK, m_bIncludeBinary ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(hwndDlg, IDC_WORDMATCH, BM_SETCHECK, m_bWordMatch ? BST_CHECKED : BST_UNCHECKED, 0); //+[JOJO] SendDlgItemMessage(hwndDlg, IDC_CASE_SENSITIVE, BM_SETCHECK, m_bCaseSensitive ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_DOTMATCHNEWLINE, BM_SETCHECK, m_bDotMatchesNewline ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_ONLYONE, BM_SETCHECK, (bPortable ? _wtoi(g_iniFile.GetValue(L"global", L"onlyone", L"0")) : DWORD(m_regOnlyOne)) ? BST_CHECKED : BST_UNCHECKED, 0); @@ -313,7 +314,7 @@ DialogEnableWindow(IDC_EXCLUDEDIRSPATTERN, !!m_bIncludeSubfolders); ::SetDlgItemText(*this, IDOK, TranslatedString(hResource, IDS_SEARCH).c_str()); - CheckRadioButton(*this, IDC_RESULTFILES, IDC_RESULTCONTENT, IDC_RESULTFILES); + CheckRadioButton(*this, IDC_RESULTFILES, IDC_RESULTCONTENT, IDC_RESULTCONTENT); //[JOJO] -IDC_RESULTFILES SetFocus(GetDlgItem(hwndDlg, IDC_SEARCHTEXT)); @@ -335,6 +336,7 @@ m_resizer.AddControl(hwndDlg, IDC_REPLACEWITHLABEL, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_REPLACETEXT, RESIZER_TOPLEFTRIGHT); m_resizer.AddControl(hwndDlg, IDC_EDITMULTILINE2, RESIZER_TOPRIGHT); + m_resizer.AddControl(hwndDlg, IDC_WORDMATCH, RESIZER_TOPLEFT); //+[JOJO] m_resizer.AddControl(hwndDlg, IDC_CASE_SENSITIVE, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_DOTMATCHNEWLINE, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_REGEXOKLABEL, RESIZER_TOPRIGHT); @@ -400,6 +402,16 @@ return FALSE; case WM_CLOSE: { +#ifdef RELOAD_TEST_1 + //////////////////////////////////////////////////////////// + // [JOJO] + if (bReload) // CSettingsDlg --> CSearchDlg --> WinMain + { + g_searchString = GetDlgItemText(IDC_SEARCHTEXT).get(); + g_replaceString = GetDlgItemText(IDC_REPLACETEXT).get(); + } + //////////////////////////////////////////////////////////// +#endif if (!DWORD(CRegStdDWORD(L"Software\\grepWin\\escclose", FALSE))) { if (m_dwThreadRunning) @@ -491,6 +503,7 @@ ShowWindow(GetDlgItem(*this, IDC_PROGRESS), SW_HIDE); SendDlgItemMessage(*this, IDC_PROGRESS, PBM_SETMARQUEE, 0, 0); KillTimer(*this, LABELUPDATETIMER); + SetFocus(GetDlgItem(*this, IDC_RESULTLIST)); //+[JOJO] } break; case WM_TIMER: @@ -607,7 +620,13 @@ ShowEditBalloon(IDC_SEARCHPATH, TranslatedString(hResource, IDS_ERR_INVALID_PATH).c_str(), TranslatedString(hResource, IDS_ERR_RELATIVEPATH).c_str()); break; } - +#if 1 // TODO: + if (m_searchString.empty()) + { + ShowEditBalloon(IDC_SEARCHTEXT, L"\u691C\u7D22\u6587\u5B57\u5217", L"\u691C\u7D22\u6587\u5B57\u5217\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044"); //TODO:TranslatedString + break; + } +#endif m_searchedItems = 0; m_totalitems = 0; @@ -632,20 +651,31 @@ if (m_bReplace) { - std::unique_ptr msgtext(new TCHAR[m_searchString.size() + m_replaceString.size() + MAX_PATH * 4]); - _stprintf_s(msgtext.get(), m_searchString.size() + m_replaceString.size() + MAX_PATH * 4, - (LPCWSTR)TranslatedString(hResource, IDS_REPLACECONFIRM).c_str(), - m_searchString.c_str(), - m_replaceString.empty() ? (LPCWSTR)TranslatedString(hResource, IDS_ANEMPTYSTRING).c_str() : m_replaceString.c_str()); - if (!m_bCreateBackup) + //////////////////////////////////////////////////////////// + // [JOJO] modify + size_t size = m_searchString.size() + m_replaceString.size() + MAX_PATH * 4; + std::unique_ptr msgtext(new WCHAR[size]); + std::wstring replaceString = m_replaceString.empty() ? TranslatedString(hResource, IDS_ANEMPTYSTRING) : m_replaceString; + if (m_bCreateBackup) { - if (::MessageBox(*this, msgtext.get(), _T("grepWin"), MB_ICONQUESTION | MB_YESNO) != IDYES) - { - break; - } + _stprintf_s(msgtext.get(), size, + L"Are you sure you want to replace\n%s\nwith\n%s", //TODO:TranslatedString + m_searchString.c_str(), + replaceString.c_str()); + if (::MessageBox(*this, msgtext.get(), _T("grepWin"), MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON3) != IDYES) + break; // switch (id) } + else + { + _stprintf_s(msgtext.get(), size, + (LPCWSTR)TranslatedString(hResource, IDS_REPLACECONFIRM).c_str(), + m_searchString.c_str(), + replaceString.c_str()); + if (::MessageBox(*this, msgtext.get(), _T("grepWin"), MB_ICONWARNING | MB_YESNOCANCEL | MB_DEFBUTTON3) != IDYES) + break; // switch (id) + } + //////////////////////////////////////////////////////////// } - InterlockedExchange(&m_dwThreadRunning, TRUE); InterlockedExchange(&m_Cancelled, FALSE); SetDlgItemText(*this, IDOK, TranslatedString(hResource, IDS_STOP).c_str()); @@ -691,6 +721,7 @@ SaveSettings(); CRegexTestDlg dlg(*this); + dlg.bWordMatch = m_bWordMatch; //+[JOJO] dlg.bCaseSensitive = m_bCaseSensitive; dlg.bDotMatchesNewline = m_bDotMatchesNewline; dlg.SetStrings(m_searchString, m_replaceString); @@ -710,8 +741,8 @@ auto path = GetDlgItemText(IDC_SEARCHPATH); if (!PathFileExists(path.get())) { - auto ptr = wcsstr(path.get(), L"|"); - if (ptr) + WCHAR *ptr = &path.get()[wcscspn(path.get(), _T(PATH_SEPARATORS))]; //[JOJO] + if (*ptr) *ptr = 0; else path.get()[0] = 0; @@ -741,7 +772,7 @@ int len = GetDlgItemTextLength(IDC_SEARCHTEXT); auto buf = GetDlgItemText(IDC_SEARCHPATH); bool bIsDir = !!PathIsDirectory(buf.get()); - if ((!bIsDir) && _tcschr(buf.get(), '|')) + if ((!bIsDir) && buf.get()[wcscspn(buf.get(), _T(PATH_SEPARATORS))]) //[JOJO] bIsDir = true; // assume directories in case of multiple paths bool bIncludeSubfolders = (IsDlgButtonChecked(*this, IDC_INCLUDESUBFOLDERS) == BST_CHECKED); DialogEnableWindow(IDC_ALLSIZERADIO, bIsDir); @@ -757,12 +788,19 @@ DialogEnableWindow(IDC_FILEPATTERNREGEX, bIsDir); DialogEnableWindow(IDC_FILEPATTERNTEXT, bIsDir); - // change the dialog title to "grepWin : search/path" - TCHAR compactPath[100] = {0}; - PathCompactPathEx(compactPath, buf.get(), 40, 0); - TCHAR titleBuf[MAX_PATH] = {0}; - _stprintf_s(titleBuf, _countof(titleBuf), _T("grepWin : %s"), compactPath); - SetWindowText(*this, titleBuf); + if (*buf.get()) + { + // change the dialog title to "grepWin : search/path" + TCHAR compactPath[100] = { 0 }; + PathCompactPathEx(compactPath, buf.get(), 40, 0); + TCHAR titleBuf[MAX_PATH] = { 0 }; + _stprintf_s(titleBuf, _countof(titleBuf), _T("%s - grepWin"), compactPath); //[JOJO] -"grepWin : %s" + SetWindowText(*this, titleBuf); + } + else + { + SetWindowText(*this, L"grepWin"); + } } } break; @@ -773,7 +811,7 @@ auto buf = GetDlgItemText(IDC_SEARCHPATH); bool bIncludeSubfolders = (IsDlgButtonChecked(*this, IDC_INCLUDESUBFOLDERS) == BST_CHECKED); bool bIsDir = !!PathIsDirectory(buf.get()); - if ((!bIsDir) && _tcschr(buf.get(), '|')) + if ((!bIsDir) && buf.get()[wcscspn(buf.get(), _T(PATH_SEPARATORS))]) //[JOJO] bIsDir = true; // assume directories in case of multiple paths DialogEnableWindow(IDC_EXCLUDEDIRSPATTERN, bIsDir || bIncludeSubfolders); } @@ -843,6 +881,7 @@ bk.Search = m_searchString; bk.Replace = m_replaceString; bk.UseRegex = bUseRegex; + bk.WordMatch = IsDlgButtonChecked(*this, IDC_WORDMATCH) == BST_CHECKED; //+[JOJO] bk.CaseSensitive = (IsDlgButtonChecked(*this, IDC_CASE_SENSITIVE) == BST_CHECKED); bk.DotMatchesNewline = (IsDlgButtonChecked(*this, IDC_DOTMATCHNEWLINE) == BST_CHECKED); bk.Backup = (IsDlgButtonChecked(*this, IDC_CREATEBACKUP) == BST_CHECKED); @@ -869,6 +908,7 @@ m_replaceString = dlg.GetSelectedReplaceString(); m_bUseRegex = dlg.GetSelectedUseRegex(); + m_bWordMatch = dlg.GetSelectedWordMatch(); //+[JOJO] m_bCaseSensitive = dlg.GetSelectedSearchCase(); m_bDotMatchesNewline = dlg.GetSelectedDotMatchNewline(); m_bCreateBackup = dlg.GetSelectedBackup(); @@ -893,6 +933,7 @@ SendDlgItemMessage(*this, IDC_INCLUDESYSTEM, BM_SETCHECK, m_bIncludeSystem ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(*this, IDC_INCLUDEHIDDEN, BM_SETCHECK, m_bIncludeHidden ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(*this, IDC_INCLUDEBINARY, BM_SETCHECK, m_bIncludeBinary ? BST_CHECKED : BST_UNCHECKED, 0); + SendDlgItemMessage(*this, IDC_WORDMATCH, BM_SETCHECK, m_bWordMatch ? BST_CHECKED : BST_UNCHECKED, 0); //+[JOJO] SendDlgItemMessage(*this, IDC_CASE_SENSITIVE, BM_SETCHECK, m_bCaseSensitive ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(*this, IDC_DOTMATCHNEWLINE, BM_SETCHECK, m_bDotMatchesNewline ? BST_CHECKED : BST_UNCHECKED, 0); @@ -1031,13 +1072,13 @@ { std::wstring sText; TCHAR buf[1024] = {0}; - _stprintf_s(buf, _countof(buf), TranslatedString(hResource, IDS_INFOLABEL).c_str(), + _stprintf_s(buf, _countof(buf), WSTR_INFOLABEL.c_str(), //[JOJO] -TranslatedString(...IDS_INFOLABEL) m_searchedItems, m_totalitems-m_searchedItems, m_totalmatches, m_items.size()); sText = buf; if (withCurrentFile && !m_searchedFile.empty()) { sText += L", "; - swprintf_s(buf, _countof(buf), TranslatedString(hResource, IDS_INFOLABELFILE).c_str(), m_searchedFile.c_str()); + swprintf_s(buf, _countof(buf), WSTR_INFOLABELFILE.c_str(), m_searchedFile.c_str()); //[JOJO] -TranslatedString(...IDS_INFOLABELFILE) sText += buf; } @@ -1218,6 +1259,7 @@ std::replace(line.begin(), line.end(), '\t', ' '); std::replace(line.begin(), line.end(), '\n', ' '); std::replace(line.begin(), line.end(), '\r', ' '); + SearchReplace(line, NULL_STR, NUL_SYMBOL); //+[JOJO] lv.pszText = (LPWSTR)line.c_str(); ListView_SetItem(hListControl, &lv); } @@ -1368,6 +1410,7 @@ std::replace(line.begin(), line.end(), '\t', ' '); std::replace(line.begin(), line.end(), '\n', ' '); std::replace(line.begin(), line.end(), '\r', ' '); + SearchReplace(line, NULL_STR, NUL_SYMBOL); //+[JOJO] lv.pszText = (LPWSTR)line.c_str(); ListView_SetItem(hListControl, &lv); index++; @@ -1456,6 +1499,49 @@ shellMenu.ShowContextMenu(hListControl, pt); } +//////////////////////////////////////////////////////////// +// [JOJO] +std::wstring CSearchDlg::ToText() +{ + std::wstring text; + + HWND hListControl = GetDlgItem(*this, IDC_RESULTLIST); + if (ListView_GetItemCount(hListControl) == 0) + return text; + + WCHAR numbuf[40] = { 0 }; + const int LVNI_XXX = ListView_GetNextItem(hListControl, -1, LVNI_SELECTED) != -1 ? LVNI_SELECTED : LVNI_ALL; + int iItem = -1; + while ((iItem = ListView_GetNextItem(hListControl, iItem, LVNI_XXX)) != -1) + { + const CSearchInfo inf = m_items[GetSelectedListIndex(iItem)]; + // ListView_GetItemText(hListControl, iItem, 0, pathbuf, _countof(pathbuf)); // 0. name + ListView_GetItemText(hListControl, iItem, 1, numbuf, _countof(numbuf)); // 1. line + // ListView_GetItemText(hListControl, iItem, 2, textbuf, _countof(textbuf)); // 2. text + const DWORD line = _wtoi(numbuf); + for (size_t lineindex = 0, size = inf.matchlinesnumbers.size(); lineindex < size; ++lineindex) + { + if (inf.matchlinesnumbers[lineindex] == line) + { + text += CStringUtils::Format(L"%s(%s):", inf.filepath.c_str(), numbuf); + if (inf.matchlines.size() > lineindex) + { + text += L"\t"; + text += inf.matchlines[lineindex]; + int c; if ((c = *text.rbegin()) != '\n' && c != '\r') { text += EOF_SYMBOL; text += inf.eol; } // EOF + } + else + { + text += inf.eol; + } + break; // for + } + } + } + return text; +} +//////////////////////////////////////////////////////////// + bool CSearchDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN) @@ -1504,6 +1590,9 @@ { if ((GetFocus() == hListControl)&&(GetKeyState(VK_CONTROL)&0x8000)) { + bool filelist = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); + if (filelist) + { // copy all selected entries to the clipboard std::wstring clipBoardText; HWND hHeader = ListView_GetHeader(hListControl); @@ -1534,7 +1623,21 @@ } clipBoardText += L"\r\n"; } + SearchReplace(clipBoardText, NULL_STR, NUL_SYMBOL); //+[JOJO] WriteAsciiStringToClipboard(clipBoardText.c_str(), *this); + } + //////////////////////////////////////////////////////////// + // [JOJO] + else + { + std::wstring clipBoardText = ToText(); + if (!clipBoardText.empty()) + { + SearchReplace(clipBoardText, NULL_STR, NUL_SYMBOL); //+[JOJO] + WriteAsciiStringToClipboard(clipBoardText.c_str(), *this); + } + } + //////////////////////////////////////////////////////////// } } break; @@ -1567,6 +1670,64 @@ break; } } + //////////////////////////////////////////////////////////// + // [JOJO] + else if (pMsg->message == WM_SYSKEYDOWN) + { + switch (pMsg->wParam) + { + case VK_F10: + { + bool filelist = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); + if (!filelist) + { + std::wstring cmd = bPortable ? g_iniFile.GetValue(L"global", L"editorcmd", L"") + : std::wstring(CRegStdString(L"Software\\grepWin\\editorcmd")); + if (!cmd.empty()) + { + std::wstring wtext = ToText(); + if (!wtext.empty()) + { + // "%TEMP%\grepWin0.txt" + DWORD tempLen = GetTempPath(0, NULL); + auto tempPath = std::make_unique(tempLen + 20); + GetTempPath(tempLen, tempPath.get()); + tempNumber = ++tempNumber % 10; + swprintf(tempPath.get() + tempLen - 1, 20, L"grepWin%d.txt", tempNumber); + + SearchReplace(cmd, L"%line%", L"0"); + SearchReplace(cmd, L"%path%", tempPath.get()); + + const int mbLen = WideCharToMultiByte(CP_UTF8, 0, wtext.c_str(), (int)wtext.length(), NULL, 0, NULL, NULL); + auto mbText = std::make_unique(mbLen); + WideCharToMultiByte(CP_UTF8, 0, wtext.c_str(), (int)wtext.length(), mbText.get(), mbLen, NULL, NULL); + + HANDLE hFile = CreateFile(tempPath.get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { wprintf(L"%S(%d) %S: Cannot open %s\n", __FILE__, __LINE__, __FUNCTION__, tempPath.get()); break; } + + DWORD n; + WriteFile(hFile, "\xEF\xBB\xBF", 3, &n, NULL); // UTF-8 BOM + WriteFile(hFile, mbText.get(), mbLen, &n, NULL); + CloseHandle(hFile); + + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInfo; + SecureZeroMemory(&startupInfo, sizeof(startupInfo)); + SecureZeroMemory(&processInfo, sizeof(processInfo)); + startupInfo.cb = sizeof(STARTUPINFO); + CreateProcess(NULL, (LPWSTR)cmd.c_str(), NULL, NULL, FALSE, 0, 0, NULL, &startupInfo, &processInfo); + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); + /* + * TODO: activate window + */ + } + } + } + } + } + } + //////////////////////////////////////////////////////////// return false; } @@ -1614,7 +1775,7 @@ SearchReplace(cmd, L"%line%", L"0"); } - SearchReplace(cmd, L"%path%", inf.filepath.c_str()); + SearchReplace(cmd, L"%path%", inf.filepath); STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; @@ -1650,11 +1811,10 @@ // resolve parameters if (application.find(_T("%1")) == std::wstring::npos) application += _T(" %1"); + // replace "%1" with %1 + SearchReplace(application, L"\"%1\"", L"%1"); // [JOJO] - bool filelist = (IsDlgButtonChecked(*this, IDC_RESULTFILES) == BST_CHECKED); - std::wstring linenumberparam_before; - std::wstring linenumberparam; if (!filelist) { HWND hListControl = GetDlgItem(*this, IDC_RESULTLIST); @@ -1667,87 +1827,74 @@ lv.cchTextMax = _countof(textlinebuf); if (ListView_GetItem(hListControl, &lv)) { - std::wstring appname = application; - std::transform(appname.begin(), appname.end(), appname.begin(), ::tolower); - // now find out if the application which opens the file is known to us // and if it has a 'linenumber' switch to jump directly to a specific // line number. - if (appname.find(_T("notepad++.exe")) != std::wstring::npos) + + //////////////////////////////////////////////////////////// + // [JOJO] + static std::vector JumpKey, JumpVal; //TODO: --> SearchDlg.h m_JumpKey, m_JumpVal + static int jumpCount = 0; //TODO: --> SearchDlg.h m_jumpCount + if (jumpCount == 0) { - // notepad++ - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("-n%s"), textlinebuf); - linenumberparam = buf; + std::wstring path = CPathUtils::GetModulePath(L"texteditors"); + FILE *file = _wfsopen(path.c_str(), L"rt,ccs=UTF-8", _SH_DENYNO); + if (file != NULL) + { + WCHAR line[1024]; + while (fgetws(line, 1024, file) != NULL) + { + if (line[0] == '#') continue; + WCHAR *ax, *bx; + if ((ax = wcsrchr(line, '\n')) != NULL) *ax = '\0'; + bx = ax = line; + if ((bx = wcsrchr(bx, '\t')) == NULL) continue; + while (*bx == '\t') *bx++ = '\0'; + if (*ax == '\0' || *bx == '\0' + || wcsstr(bx, L"%line%") == NULL || wcsstr(bx, L"%path%") == NULL ) continue; + // + std::wstring key = ax, val = bx; + std::transform(key.begin(), key.end(), key.begin(), std::tolower); // + JumpKey.push_back(key); + JumpVal.push_back(val); + ++jumpCount; + } + fclose(file); + } + else + { + jumpCount = -1; + } } - else if (appname.find(_T("xemacs.exe")) != std::wstring::npos) + if (jumpCount > 0) { - // XEmacs - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("+%s"), textlinebuf); - linenumberparam = buf; + std::wstring appname = application; + std::transform(appname.begin(), appname.end(), appname.begin(), ::tolower); // + for (int i = 0; i < jumpCount; ++i) + { + std::wstring key = JumpKey[i], val = JumpVal[i]; + size_t p; + if ((p = appname.find(key)) != std::wstring::npos + && (p == 0 || wcsrchr(L":/\\\"*?<>|", appname.at(p - 1)) != NULL)) + { + SearchReplace(application, L"%1", val); + SearchReplace(application, L"%line%", textlinebuf); + SearchReplace(application, L"%path%", L"%1"); + break; // for + } + } } - else if (appname.find(_T("uedit32.exe")) != std::wstring::npos) - { - // UltraEdit - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("-l%s"), textlinebuf); - linenumberparam = buf; - } - else if (appname.find(_T("codewright.exe")) != std::wstring::npos) - { - // CodeWright - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("-G%s"), textlinebuf); - linenumberparam = buf; - } - else if (appname.find(_T("notepad2.exe")) != std::wstring::npos) - { - // Notepad2 - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("/g %s"), textlinebuf); - linenumberparam_before = buf; - } - else if ((appname.find(_T("bowpad.exe")) != std::wstring::npos)||(appname.find(_T("bowpad64.exe")) != std::wstring::npos)) - { - // BowPad - TCHAR buf[MAX_PATH] = {0}; - _stprintf_s(buf, _countof(buf), _T("/line:%s"), textlinebuf); - linenumberparam_before = buf; - } + //////////////////////////////////////////////////////////// } } - // replace "%1" with %1 - std::wstring tag = _T("\"%1\""); - std::wstring repl = _T("%1"); - std::wstring::iterator it_begin = search(application.begin(), application.end(), tag.begin(), tag.end()); - if (it_begin != application.end()) - { - std::wstring::iterator it_end= it_begin + tag.size(); - application.replace(it_begin, it_end, repl); - } // replace %1 with "path/of/selected/file" - tag = _T("%1"); + std::wstring repl; if (application.find(L"rundll32.exe") == std::string::npos) repl = _T("\"") + inf.filepath + _T("\""); else repl = inf.filepath; - if (!linenumberparam_before.empty()) - { - repl = linenumberparam_before + L" " + repl; - } - it_begin = search(application.begin(), application.end(), tag.begin(), tag.end()); - if (it_begin != application.end()) - { - std::wstring::iterator it_end= it_begin + tag.size(); - application.replace(it_begin, it_end, repl); - } - if (!linenumberparam.empty()) - { - application += _T(" "); - application += linenumberparam; - } + SearchReplace(application, L"%1", repl); // [JOJO] STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; @@ -1789,9 +1936,9 @@ { case 0: if (m_bAscending) - sort(m_items.begin(), m_items.end(), NameCompareAsc); + sort(m_items.begin(), m_items.end(), NameCompare); else - sort(m_items.begin(), m_items.end(), NameCompareDesc); + sort(m_items.rbegin(), m_items.rend(), NameCompare); bDidSort = true; break; case 1: @@ -1798,9 +1945,9 @@ if (filelist) { if (m_bAscending) - sort(m_items.begin(), m_items.end(), SizeCompareAsc); + sort(m_items.begin(), m_items.end(), SizeCompare); else - sort(m_items.begin(), m_items.end(), SizeCompareDesc); + sort(m_items.rbegin(), m_items.rend(), SizeCompare); bDidSort = true; } break; @@ -1808,31 +1955,31 @@ if (filelist) { if (m_bAscending) - sort(m_items.begin(), m_items.end(), MatchesCompareAsc); + sort(m_items.begin(), m_items.end(), MatchesCompare); else - sort(m_items.begin(), m_items.end(), MatchesCompareDesc); + sort(m_items.rbegin(), m_items.rend(), MatchesCompare); bDidSort = true; } break; case 3: if (m_bAscending) - sort(m_items.begin(), m_items.end(), PathCompareAsc); + sort(m_items.begin(), m_items.end(), PathCompare); else - sort(m_items.begin(), m_items.end(), PathCompareDesc); + sort(m_items.rbegin(), m_items.rend(), PathCompare); bDidSort = true; break; case 4: if (m_bAscending) - sort(m_items.begin(), m_items.end(), EncodingCompareAsc); + sort(m_items.begin(), m_items.end(), EncodingCompare); else - sort(m_items.begin(), m_items.end(), EncodingCompareDesc); + sort(m_items.rbegin(), m_items.rend(), EncodingCompare); bDidSort = true; break; case 5: if (m_bAscending) - sort(m_items.begin(), m_items.end(), ModifiedTimeCompareAsc); + sort(m_items.begin(), m_items.end(), ModifiedTimeCompare); else - sort(m_items.begin(), m_items.end(), ModifiedTimeCompareDesc); + sort(m_items.rbegin(), m_items.rend(), ModifiedTimeCompare); bDidSort = true; break; } @@ -1937,7 +2084,7 @@ m_patterns.clear(); do { - pos = _tcscspn(pBuf, _T("|")); + pos = wcscspn(pBuf, _T(PATH_SEPARATORS)); //[JOJO] std::wstring s = std::wstring(pBuf, pos); if (!s.empty()) { @@ -2015,6 +2162,7 @@ m_bIncludeBinary = (IsDlgButtonChecked(*this, IDC_INCLUDEBINARY) == BST_CHECKED); m_bCreateBackup = (IsDlgButtonChecked(*this, IDC_CREATEBACKUP) == BST_CHECKED); m_bUTF8 = (IsDlgButtonChecked(*this, IDC_UTF8) == BST_CHECKED); + m_bWordMatch = IsDlgButtonChecked(*this, IDC_WORDMATCH) == BST_CHECKED; //+[JOJO] m_bCaseSensitive = (IsDlgButtonChecked(*this, IDC_CASE_SENSITIVE) == BST_CHECKED); m_bDotMatchesNewline = (IsDlgButtonChecked(*this, IDC_DOTMATCHNEWLINE) == BST_CHECKED); @@ -2027,6 +2175,7 @@ g_iniFile.SetValue(L"global", L"IncludeBinary", m_bIncludeBinary ? L"1" : L"0"); g_iniFile.SetValue(L"global", L"CreateBackup", m_bCreateBackup ? L"1" : L"0"); g_iniFile.SetValue(L"global", L"UTF8", m_bUTF8 ? L"1" : L"0"); + g_iniFile.SetValue(L"global", L"WordMatch", m_bWordMatch ? L"1" : L"0"); //+[JOJO] g_iniFile.SetValue(L"global", L"CaseSensitive", m_bCaseSensitive ? L"1" : L"0"); g_iniFile.SetValue(L"global", L"DotMatchesNewline", m_bDotMatchesNewline ? L"1" : L"0"); g_iniFile.SetValue(L"global", L"pattern", m_patternregex.c_str()); @@ -2041,6 +2190,7 @@ m_regIncludeBinary = (DWORD)m_bIncludeBinary; m_regCreateBackup = (DWORD)m_bCreateBackup; m_regUTF8 = (DWORD)m_bUTF8; + m_regWordMatch = (DWORD)m_bWordMatch; //+[JOJO] m_regCaseSensitive = (DWORD)m_bCaseSensitive; m_regDotMatchesNewline = (DWORD)m_bDotMatchesNewline; m_regPattern = m_patternregex; @@ -2052,7 +2202,7 @@ return true; } -bool CSearchDlg::NameCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::NameCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { std::wstring name1 = Entry1.filepath.substr(Entry1.filepath.find_last_of('\\')+1); std::wstring name2 = Entry2.filepath.substr(Entry2.filepath.find_last_of('\\')+1); @@ -2059,77 +2209,31 @@ return StrCmpLogicalW(name1.c_str(), name2.c_str()) < 0; } -bool CSearchDlg::SizeCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::SizeCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { return Entry1.filesize < Entry2.filesize; } -bool CSearchDlg::MatchesCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::MatchesCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { return Entry1.matchcount < Entry2.matchcount; } -bool CSearchDlg::PathCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::PathCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { - std::wstring name1 = Entry1.filepath.substr(Entry1.filepath.find_last_of('\\')+1); - std::wstring name2 = Entry2.filepath.substr(Entry2.filepath.find_last_of('\\')+1); - std::wstring path1 = Entry1.filepath.substr(0, Entry1.filepath.size()-name1.size()-1); - std::wstring path2 = Entry2.filepath.substr(0, Entry2.filepath.size()-name2.size()-1); - int cmp = path1.compare(path2); - if (cmp != 0) - return cmp < 0; - return StrCmpLogicalW(name1.c_str(), name2.c_str()) < 0; + return StrCmpLogicalW(Entry1.filepath.c_str(), Entry2.filepath.c_str()) < 0; } -bool CSearchDlg::EncodingCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::EncodingCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { return Entry1.encoding < Entry2.encoding; } -bool CSearchDlg::ModifiedTimeCompareAsc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) +bool CSearchDlg::ModifiedTimeCompare(const CSearchInfo &Entry1, const CSearchInfo& Entry2) { return CompareFileTime(&Entry1.modifiedtime, &Entry2.modifiedtime) < 0; } -bool CSearchDlg::NameCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - std::wstring name1 = Entry1.filepath.substr(Entry1.filepath.find_last_of('\\')+1); - std::wstring name2 = Entry2.filepath.substr(Entry2.filepath.find_last_of('\\')+1); - return StrCmpLogicalW(name1.c_str(), name2.c_str()) > 0; -} - -bool CSearchDlg::SizeCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - return Entry1.filesize > Entry2.filesize; -} - -bool CSearchDlg::MatchesCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - return Entry1.matchlinesnumbers.size() > Entry2.matchlinesnumbers.size(); -} - -bool CSearchDlg::PathCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - std::wstring name1 = Entry1.filepath.substr(Entry1.filepath.find_last_of('\\')+1); - std::wstring name2 = Entry2.filepath.substr(Entry2.filepath.find_last_of('\\')+1); - std::wstring path1 = Entry1.filepath.substr(0, Entry1.filepath.size()-name1.size()-1); - std::wstring path2 = Entry2.filepath.substr(0, Entry2.filepath.size()-name2.size()-1); - int cmp = path1.compare(path2); - if (cmp != 0) - return cmp > 0; - return StrCmpLogicalW(name1.c_str(), name2.c_str()) > 0; -} - -bool CSearchDlg::EncodingCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - return Entry1.encoding > Entry2.encoding; -} - -bool CSearchDlg::ModifiedTimeCompareDesc(const CSearchInfo &Entry1, const CSearchInfo& Entry2) -{ - return CompareFileTime(&Entry1.modifiedtime, &Entry2.modifiedtime) > 0; -} - bool grepWin_match_i(const std::wstring& the_regex, const TCHAR *pText) { try @@ -2159,19 +2263,24 @@ std::vector pathvector; do { - pos = _tcscspn(pBufSearchPath, _T("|")); + pos = wcscspn(pBufSearchPath, _T(PATH_SEPARATORS)); //[JOJO] std::wstring s = std::wstring(pBufSearchPath, pos); if (!s.empty()) { + //////////////////////////////////////////////////////////// + // [JOJO] + std::replace(s.begin(), s.end(), '/', '\\'); + if (isascii(s[0]) && isalpha(s[0]) && s[1] == ':' && s[2] != '\\') // "C:***" --> "C:\***" + s.insert(2, 1, '\\'); + //////////////////////////////////////////////////////////// // Remove extra backslashes except for the UNC identifier - std::string::size_type found = s.find_first_of('\\', 1); - while (found != std::string::npos) + for (std::string::size_type found = 1; (found = s.find_first_of('\\', found)) != std::string::npos; ) { - while (s[found + 1] == '\\') + ++found; + while (s[found] == '\\') { - s.erase(found + 1, 1); + s.erase(found, 1); } - found = s.find_first_of('\\', found + 1); } pathvector.push_back(s); } @@ -2204,6 +2313,8 @@ } SendMessage(*this, SEARCH_START, 0, 0); + WSTR_INFOLABEL = TranslatedString(hResource, IDS_INFOLABEL); //+[JOJO] + WSTR_INFOLABELFILE = TranslatedString(hResource, IDS_INFOLABELFILE); //+[JOJO] for (auto it = pathvector.begin(); it != pathvector.end(); ++it) { std::wstring searchpath = *it; @@ -2281,7 +2392,7 @@ } else { - nFound = SearchFile(sinfo, bAlwaysSearch, m_bIncludeBinary, m_bUseRegex, m_bCaseSensitive, m_bDotMatchesNewline, m_searchString); + nFound = SearchFile(sinfo, bAlwaysSearch, m_bIncludeBinary, m_bUseRegex, m_bWordMatch, m_bCaseSensitive, m_bDotMatchesNewline, m_searchString); if (nFound >= 0) SendMessage(*this, SEARCH_FOUND, nFound, (LPARAM)&sinfo); } @@ -2370,7 +2481,7 @@ return bPattern; } -int CSearchDlg::SearchFile(CSearchInfo& sinfo, bool bSearchAlways, bool bIncludeBinary, bool bUseRegex, bool bCaseSensitive, bool bDotMatchesNewline, const std::wstring& searchString) +int CSearchDlg::SearchFile(CSearchInfo& sinfo, bool bSearchAlways, bool bIncludeBinary, bool bUseRegex, bool bWordMatch, bool bCaseSensitive, bool bDotMatchesNewline, const std::wstring& searchString) { int nFound = 0; // we keep it simple: @@ -2379,20 +2490,21 @@ std::wstring localSearchString = searchString; if (!bUseRegex) localSearchString = _T("\\Q") + searchString + _T("\\E"); + //////////////////////////////////////////////////////////// + // [JOJO] + if (bWordMatch) + localSearchString = _T("\\b") + searchString + _T("\\b"); + //////////////////////////////////////////////////////////// - SearchReplace(localSearchString, L"${filepath}", sinfo.filepath); - std::wstring filenamefull = sinfo.filepath.substr(sinfo.filepath.find_last_of('\\') + 1); - auto dotpos = filenamefull.find_last_of('.'); - if (dotpos != std::string::npos) - { - std::wstring filename = filenamefull.substr(0, dotpos); - SearchReplace(localSearchString, L"${filepath}", filename); - if (filenamefull.size() > dotpos) - { - std::wstring fileext = filenamefull.substr(dotpos + 1); - SearchReplace(localSearchString, L"${fileext}", fileext); - } - } +#if 0 //-[JOJO] + //////////////////////////////////////////////////////////// + // [JOJO] http://stefanstools.sourceforge.net/regexhelp.html + SearchReplace(localSearchString, L"${filepath}", sinfo.filepath); // reference gets replaced with the full path of the current file + SearchReplace(localSearchString, L"${filename}", CPathUtils::GetFileNameWithoutExtension(sinfo.filepath)); // gets replaced with the filename without the file extension + SearchReplace(localSearchString, L"${.fileext}", CPathUtils::GetFileNameExtension(sinfo.filepath)); //+[JOJO] + SearchReplace(localSearchString, L"${fileext}", CPathUtils::GetFileExtension(sinfo.filepath)); // gets replaced with the file extension of the current file + //////////////////////////////////////////////////////////// +#endif CTextFile textfile; m_searchedFile = sinfo.filepath; @@ -2399,6 +2511,7 @@ CTextFile::UnicodeType type = CTextFile::AUTOTYPE; bool bLoadResult = textfile.Load(sinfo.filepath.c_str(), type, m_bUTF8); sinfo.encoding = type; + sinfo.eol = textfile.eol(); //+[JOJO] if ((bLoadResult) && ((type != CTextFile::BINARY)||(bIncludeBinary)||bSearchAlways)) { sinfo.readerror = false; @@ -2417,25 +2530,22 @@ if (!bDotMatchesNewline) flags |= boost::match_not_dot_newline; long prevlinestart = 0; - long prevlineend = 0; while (regex_search(start, end, whatc, expression, flags)) { if (whatc[0].matched) { nFound++; - long linestart = textfile.LineFromPosition(long(whatc[0].first-textfile.GetFileString().begin())); - long lineend = textfile.LineFromPosition(long(whatc[0].second-textfile.GetFileString().begin())); - if ((linestart != prevlinestart)||(lineend != prevlineend)) + //////////////////////////////////////////////////////////// + // [JOJO] + long linestart = textfile.LineFromPosition(whatc[0].first - textfile.GetFileString().begin()); + if (linestart != prevlinestart) { - for (long l = linestart; l <= lineend; ++l) - { - sinfo.matchlines.push_back(textfile.GetLineString(l)); - sinfo.matchlinesnumbers.push_back(l); - } + sinfo.matchlines.push_back(textfile.GetLineString(linestart)); + sinfo.matchlinesnumbers.push_back(linestart); } ++sinfo.matchcount; prevlinestart = linestart; - prevlineend = lineend; + //////////////////////////////////////////////////////////// } // update search position: if (start == whatc[0].second) @@ -2455,19 +2565,14 @@ flags &= ~boost::match_prev_avail; flags &= ~boost::match_not_bob; RegexReplaceFormatter replaceFmt(m_replaceString); - replaceFmt.SetReplacePair(L"${filepath}", sinfo.filepath); - std::wstring filenamefullW = sinfo.filepath.substr(sinfo.filepath.find_last_of('\\')+1); - auto dotposW = filenamefullW.find_last_of('.'); - if (dotposW != std::string::npos) - { - std::wstring filename = filenamefullW.substr(0, dotposW); - replaceFmt.SetReplacePair(L"${filename}", filename); - if (filenamefullW.size() > dotposW) - { - std::wstring fileext = filenamefullW.substr(dotposW+1); - replaceFmt.SetReplacePair(L"${fileext}", fileext); - } - } + + //////////////////////////////////////////////////////////// + // [JOJO] + replaceFmt.SetReplacePair(L"${filepath}", sinfo.filepath); // reference gets replaced with the full path of the current file + replaceFmt.SetReplacePair(L"${filename}", CPathUtils::GetFileNameWithoutExtension(sinfo.filepath)); // gets replaced with the filename without the file extension + replaceFmt.SetReplacePair(L"${.fileext}", CPathUtils::GetFileNameExtension(sinfo.filepath)); //+[JOJO] + replaceFmt.SetReplacePair(L"${fileext}", CPathUtils::GetFileExtension(sinfo.filepath)); // gets replaced with the file extension of the current file + //////////////////////////////////////////////////////////// std::wstring replaced = regex_replace(textfile.GetFileString(), expression, replaceFmt, flags); if (replaced.compare(textfile.GetFileString())) { @@ -2533,6 +2638,11 @@ searchfor += CUnicodeUtils::StdGetUTF8(searchString); searchfor += "\\E"; } + //////////////////////////////////////////////////////////// + // [JOJO] + if (bWordMatch) + searchfor = "\\b" + searchfor + "\\b"; + //////////////////////////////////////////////////////////// boost::match_results what; boost::match_flag_type flags = boost::match_default | boost::format_all; @@ -2545,7 +2655,7 @@ try { boost::regex expression = boost::regex(searchfor, ft); - std::vector matchlinesnumbers; + std::vector matchpositions; bool bFound = false; { boost::spirit::classic::file_iterator<> start(filepath.c_str()); @@ -2555,7 +2665,7 @@ while (boost::regex_search(start, end, whatc, expression, flags)) { nFound++; - matchlinesnumbers.push_back(DWORD(whatc[0].first - fbeg)); + matchpositions.push_back(DWORD(whatc[0].first - fbeg)); ++sinfo.matchcount; // update search position: start = whatc[0].second; @@ -2568,9 +2678,9 @@ if (bFound) { + std::vector matchlinesnumbers; if (!bLoadResult && (type != CTextFile::BINARY)) { - linepositions.clear(); // open the file and set up a vector of all lines HANDLE hFile = INVALID_HANDLE_VALUE; int retrycounter = 0; @@ -2584,6 +2694,9 @@ } while (hFile == INVALID_HANDLE_VALUE && retrycounter < 5); if (hFile != INVALID_HANDLE_VALUE) { + //////////////////////////////////////////////////////////// + // [JOJO] + std::map linepositions; std::unique_ptr fbuf(new char[4096]); DWORD bytesread = 0; size_t pos = 0; @@ -2591,27 +2704,26 @@ { if (bytesread == 0) break; - for (DWORD br = 0; br < bytesread; ++br) + for (DWORD br = 0; br < bytesread; ++br, ++pos) { if (fbuf[br] == '\r') { - ++br; - ++pos; - if (br < bytesread) + ++br, ++pos; + if (br >= bytesread) { - if (fbuf[br] == '\n') - { - // crlf lineending - linepositions[pos] = (DWORD)linepositions.size(); - } - else - { - // cr lineending - linepositions[pos-1] = (DWORD)linepositions.size(); - } + ReadFile(hFile, fbuf.get(), 4096, &bytesread, NULL); + br = 0; } + if (br < bytesread && fbuf[br] == '\n') + { + // crlf lineending + linepositions[pos] = (DWORD)linepositions.size(); + } else - break; + { + // cr lineending + linepositions[pos-1] = (DWORD)linepositions.size(); + } } else if (fbuf[br] == '\n') { @@ -2618,16 +2730,19 @@ // lf lineending linepositions[pos] = (DWORD)linepositions.size(); } - ++pos; } } + linepositions[pos] = (DWORD)linepositions.size(); CloseHandle(hFile); - for (size_t mp = 0; mp < matchlinesnumbers.size(); ++mp) + DWORD prevlinesnumber = (DWORD)-1; + for (size_t mp = 0; mp < matchpositions.size(); ++mp) { - auto fp = linepositions.lower_bound(matchlinesnumbers[mp]); - if (fp != linepositions.end()) - matchlinesnumbers[mp] = fp->second; + auto fp = linepositions.lower_bound(matchpositions[mp]); + // if (fp != linepositions.end()) + if (prevlinesnumber != fp->second) + matchlinesnumbers.push_back(prevlinesnumber = fp->second); } + //////////////////////////////////////////////////////////// } } sinfo.matchlinesnumbers = matchlinesnumbers; @@ -2646,15 +2761,15 @@ flags &= ~boost::match_not_bob; RegexReplaceFormatterA replaceFmt(CUnicodeUtils::StdGetUTF8(m_replaceString)); replaceFmt.SetReplacePair("${filepath}", CUnicodeUtils::StdGetUTF8(sinfo.filepath)); - std::string filenamefullA = CUnicodeUtils::StdGetUTF8(sinfo.filepath.substr(sinfo.filepath.find_last_of('\\') + 1)); - auto dotposA = filenamefullA.find_last_of('.'); - if (dotposA != std::string::npos) + std::string filenamefull = CUnicodeUtils::StdGetUTF8(sinfo.filepath.substr(sinfo.filepath.find_last_of('\\') + 1)); + auto dotpos = filenamefull.find_last_of('.'); + if (dotpos != std::string::npos) { - std::string filename = filenamefullA.substr(0, dotposA); + std::string filename = filenamefull.substr(0, dotpos); replaceFmt.SetReplacePair("${filename}", filename); - if (filenamefull.size() > dotposA) + if (filenamefull.size() > dotpos) { - std::string fileext = filenamefullA.substr(dotposA + 1); + std::string fileext = filenamefull.substr(dotpos + 1); replaceFmt.SetReplacePair("${fileext}", fileext); } } @@ -2742,9 +2857,12 @@ try { std::wstring localSearchString = buf.get(); +#if 0 //-[JOJO] SearchReplace(localSearchString, L"${filepath}", L""); - SearchReplace(localSearchString, L"${filepath}", L""); + SearchReplace(localSearchString, L"${filename}", L""); + SearchReplace(localSearchString, L"${.fileext}", L""); //+[JOJO] SearchReplace(localSearchString, L"${fileext}", L""); +#endif boost::wregex expression = boost::wregex(localSearchString); } Index: src/SearchDlg.h =================================================================== --- src/SearchDlg.h (revision 632) +++ src/SearchDlg.h (working copy) @@ -56,6 +56,7 @@ void SetReplaceWith(const std::wstring& replace) { m_replaceString = replace; } void SetUseRegex(bool reg) { m_bUseRegex = reg; } + void SetWordMatch(bool bSet) {m_bWordMatchC = true; m_bWordMatch = bSet;} //+[JOJO] void SetCaseSensitive(bool bSet) {m_bCaseSensitiveC = true; m_bCaseSensitive = bSet;} void SetMatchesNewline(bool bSet) {m_bDotMatchesNewlineC = true; m_bDotMatchesNewline = bSet;} void SetCreateBackups(bool bSet) {m_bCreateBackupC = true; m_bCreateBackup = bSet;} @@ -73,7 +74,7 @@ bool PreTranslateMessage(MSG* pMsg); static LRESULT CALLBACK EditProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); - int SearchFile(CSearchInfo& sinfo, bool bSearchAlways, bool bIncludeBinary, bool bUseRegex, bool bCaseSensitive, bool bDotMatchesNewline, const std::wstring& searchString); + int SearchFile(CSearchInfo& sinfo, bool bSearchAlways, bool bIncludeBinary, bool bUseRegex, bool bWordMatch, bool bCaseSensitive, bool bDotMatchesNewline, const std::wstring& searchString); bool InitResultList(); void FillResultList(); @@ -91,19 +92,14 @@ int GetSelectedListIndex(int index); private: - static bool NameCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool SizeCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool MatchesCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool PathCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool EncodingCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool ModifiedTimeCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool NameCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool SizeCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool MatchesCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool PathCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool EncodingCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + static bool ModifiedTimeCompare(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool NameCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool SizeCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool MatchesCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool PathCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool EncodingCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); - static bool ModifiedTimeCompareDesc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); + std::wstring CSearchDlg::ToText(); //+[JOJO] private: HWND m_hParent; @@ -132,6 +128,8 @@ bool m_bCreateBackupC; bool m_bUTF8; bool m_bUTF8C; + bool m_bWordMatch; //+[JOJO] + bool m_bWordMatchC; //+[JOJO] bool m_bCaseSensitive; bool m_bCaseSensitiveC; bool m_bDotMatchesNewline; @@ -182,6 +180,7 @@ CRegStdDWORD m_regIncludeBinary; CRegStdDWORD m_regCreateBackup; CRegStdDWORD m_regUTF8; + CRegStdDWORD m_regWordMatch; //+[JOJO] CRegStdDWORD m_regCaseSensitive; CRegStdDWORD m_regDotMatchesNewline; CRegStdDWORD m_regUseRegexForPaths; Index: src/SearchInfo.h =================================================================== --- src/SearchInfo.h (revision 632) +++ src/SearchInfo.h (working copy) @@ -36,6 +36,7 @@ std::vector matchlines; __int64 matchcount; CTextFile::UnicodeType encoding; + std::wstring eol; //+[JOJO] FILETIME modifiedtime; bool readerror; bool folder; Index: src/Settings.cpp =================================================================== --- src/Settings.cpp (revision 632) +++ src/Settings.cpp (working copy) @@ -18,11 +18,9 @@ // #include "stdafx.h" #include "resource.h" -#include "maxpath.h" #include "Settings.h" -#include "BrowseFolder.h" -#include "DirFileEnum.h" #include +#include "PathUtils.h" CSettingsDlg::CSettingsDlg(HWND hParent) @@ -49,41 +47,32 @@ SetDlgItemText(hwndDlg, IDC_EDITORCMD, bPortable ? g_iniFile.GetValue(L"global", L"editorcmd", L"") : std::wstring(m_regEditorCmd).c_str()); - wchar_t modulepath[MAX_PATH] = {0}; - GetModuleFileName(NULL, modulepath, MAX_PATH); - std::wstring path = modulepath; - path = path.substr(0, path.find_last_of('\\')); - CDirFileEnum fileEnumerator(path.c_str()); - bool bRecurse = false; - bool bIsDirectory = false; std::wstring sPath; - CRegStdString regLang(L"Software\\grepWin\\languagefile"); - std::wstring setLang = regLang; - if (bPortable) - setLang = g_iniFile.GetValue(L"global", L"languagefile", L""); + //////////////////////////////////////////////////////////// + // [JOJO] modify + std::wstring languagefile = bPortable ? g_iniFile.GetValue(L"global", L"languagefile", L"") : std::wstring(CRegStdString(L"Software\\grepWin\\languagefile")); + languagefile = CPathUtils::GetFileName(languagefile); // without directory - int index = 1; + int index = 0; int langIndex = 0; SendDlgItemMessage(hwndDlg, IDC_LANGUAGE, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)L"English"); - while (fileEnumerator.NextFile(sPath, &bIsDirectory, bRecurse)) - { - size_t dotpos = sPath.find_last_of('.'); - if (dotpos == std::wstring::npos) - continue; - std::wstring ext = sPath.substr(dotpos); - if (ext.compare(L".lang")) - continue; - m_langpaths.push_back(sPath); - if (sPath.compare(setLang)==0) - langIndex = index; - size_t slashpos = sPath.find_last_of('\\'); - if (slashpos == std::wstring::npos) - continue; - sPath = sPath.substr(slashpos+1); - sPath = sPath.substr(0, dotpos); - SendDlgItemMessage(hwndDlg, IDC_LANGUAGE, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)sPath.c_str()); - ++index; + WIN32_FIND_DATA findFileData; + HANDLE hFindFile = FindFirstFile(CPathUtils::GetModulePath(L"*.lang").c_str(), &findFileData); + if (hFindFile != INVALID_HANDLE_VALUE) { + do { + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY || findFileData.cFileName[0] == '.') + continue; + if (StrCmpI(findFileData.cFileName, L"English.lang") == 0) + continue; + ++index; + m_langpaths.push_back(findFileData.cFileName); + SendDlgItemMessage(hwndDlg, IDC_LANGUAGE, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)findFileData.cFileName); + if (StrCmpI(findFileData.cFileName, languagefile.c_str()) == 0) + langIndex = index; + } while (FindNextFile(hFindFile, &findFileData)); + FindClose(hFindFile); } + //////////////////////////////////////////////////////////// SendDlgItemMessage(hwndDlg, IDC_LANGUAGE, CB_SETCURSEL, langIndex, 0); SendDlgItemMessage(hwndDlg, IDC_ESCKEY, BM_SETCHECK, DWORD(CRegStdDWORD(L"Software\\grepWin\\escclose", FALSE)) ? BST_CHECKED : BST_UNCHECKED, 0); @@ -138,6 +127,11 @@ g_iniFile.SetValue(L"global", L"editorcmd", buf.get()); else m_regEditorCmd = buf.get(); + //////////////////////////////////////////////////////////// + // [JOJO] + std::wstring languagefile = bPortable ? g_iniFile.GetValue(L"global", L"languagefile", L"") : std::wstring(CRegStdString(L"Software\\grepWin\\languagefile")); + languagefile = CPathUtils::GetFileName(languagefile); // without directory + //////////////////////////////////////////////////////////// int langIndex = (int)SendDlgItemMessage(*this, IDC_LANGUAGE, CB_GETCURSEL, 0, 0); std::wstring langpath = langIndex==0 ? L"" : m_langpaths[langIndex-1]; if (bPortable) @@ -154,10 +148,25 @@ regLang = langpath; } } - CLanguage::Instance().LoadFile(langpath); - CLanguage::Instance().TranslateWindow(::GetParent(*this)); + //////////////////////////////////////////////////////////// + // [JOJO] + if (StrCmpI(languagefile.c_str(), langpath.c_str()) != 0) + { + CLanguage::Instance().LoadFile(CPathUtils::GetModulePath(langpath)); + if (languagefile.empty()) // from english to another language + CLanguage::Instance().TranslateWindow(m_hParent); + else + bReload = TRUE; // CSettingsDlg --> CSearchDlg --> WinMain + } + //////////////////////////////////////////////////////////// CRegStdDWORD esc(L"Software\\grepWin\\escclose", FALSE); esc = (IsDlgButtonChecked(*this, IDC_ESCKEY) == BST_CHECKED); + + //////////////////////////////////////////////////////////// + // [JOJO] + if (bReload) + SendMessage(m_hParent, WM_CLOSE, 0, 0); + //////////////////////////////////////////////////////////// } // fall through case IDCANCEL: Index: src/Setup/Setup.wxs =================================================================== --- src/Setup/Setup.wxs (revision 632) +++ src/Setup/Setup.wxs (working copy) @@ -42,6 +42,8 @@ + + Index: src/Setup/Setup64.wxs =================================================================== --- src/Setup/Setup64.wxs (revision 632) +++ src/Setup/Setup64.wxs (working copy) @@ -40,6 +40,8 @@ + + Index: src/Setup/Setup64_user.wxs =================================================================== --- src/Setup/Setup64_user.wxs (revision 632) +++ src/Setup/Setup64_user.wxs (working copy) @@ -40,6 +40,8 @@ + + Index: src/Setup/Setup_user.wxs =================================================================== --- src/Setup/Setup_user.wxs (revision 632) +++ src/Setup/Setup_user.wxs (working copy) @@ -42,6 +42,8 @@ + + Index: src/ShellContextMenu.cpp =================================================================== --- src/ShellContextMenu.cpp (revision 632) +++ src/ShellContextMenu.cpp (working copy) @@ -24,6 +24,7 @@ #include "SearchInfo.h" #include "LineData.h" #include "ResString.h" +#include "PathUtils.h" //+[JOJO] #include "resource.h" #include #include @@ -306,9 +307,7 @@ { if (!pathnames.empty()) pathnames += _T("\r\n"); - std::wstring p = it->filepath; - p = p.substr(p.find_last_of('\\')+1); - pathnames += p; + pathnames += CPathUtils::GetFileName(it->filepath); //[JOJO] } WriteAsciiStringToClipboard(pathnames.c_str(), hWnd); } @@ -316,19 +315,21 @@ case 4: { std::wstring lines; + //////////////////////////////////////////////////////////// + // [JOJO] for (auto it = m_lineVector.begin(); it != m_lineVector.end(); ++it) { - if (!lines.empty()) - lines += _T("\r\n"); for (auto it2 = it->lines.cbegin(); it2 != it->lines.cend(); ++it2) { - std::wstring l = it2->text; - std::replace(l.begin(), l.end(), '\n', ' '); - std::replace(l.begin(), l.end(), '\r', ' '); - - lines += l; + if (!lines.empty()) + { + int c; if ((c = *lines.rbegin()) != '\n' && c != '\r') { lines += EOF_SYMBOL; lines += L"\n"; } // EOF + } + lines += it2->text; } } + SearchReplace(lines, NULL_STR, NUL_SYMBOL); //+[JOJO] + //////////////////////////////////////////////////////////// WriteAsciiStringToClipboard(lines.c_str(), hWnd); } break; @@ -341,7 +342,7 @@ for (auto it2 = it->lines.cbegin(); it2 != it->lines.cend(); ++it2) { std::wstring cmd = regEditorCmd; - SearchReplace(cmd, L"%path%", it->path.c_str()); + SearchReplace(cmd, L"%path%", it->path); wchar_t buf[40] = {0}; swprintf_s(buf, L"%ld", it2->number); SearchReplace(cmd, L"%line%", buf); @@ -362,7 +363,7 @@ for (auto it = m_strVector.begin(); it != m_strVector.end(); ++it) { std::wstring cmd = regEditorCmd; - SearchReplace(cmd, L"%path%", it->filepath.c_str()); + SearchReplace(cmd, L"%path%", it->filepath); if (!it->matchlinesnumbers.empty()) { wchar_t buf[40] = {0}; @@ -423,8 +424,11 @@ // that means that it's a fully qualified PIDL, which is what we need m_nItems = strVector.size(); - m_pidlArray = (LPITEMIDLIST *)CoTaskMemAlloc((m_nItems + 10) * sizeof (LPITEMIDLIST)); - SecureZeroMemory(m_pidlArray, (m_nItems + 10) * sizeof (LPITEMIDLIST)); + //////////////////////////////////////////////////////////// + // [JOJO] + m_pidlArray = (LPITEMIDLIST *)CoTaskMemAlloc(1 * sizeof (LPITEMIDLIST)); + SecureZeroMemory(m_pidlArray, 1 * sizeof (LPITEMIDLIST)); + //////////////////////////////////////////////////////////// m_pidlArrayItems = 0; int succeededItems = 0; LPITEMIDLIST pidl = NULL; @@ -437,19 +441,23 @@ std::unique_ptr filepath(new WCHAR[bufsize]); for (size_t i = 0; i < m_nItems; i++) { - if (bufsize < strVector[i].filepath.size()) + //////////////////////////////////////////////////////////// + // [JOJO] + if (succeededItems == 0) { - bufsize = strVector[i].filepath.size() + 3; - filepath = std::unique_ptr(new WCHAR[bufsize]); + if (bufsize < strVector[i].filepath.size()) + { + bufsize = strVector[i].filepath.size() + 3; + filepath = std::unique_ptr(new WCHAR[bufsize]); + } + wcscpy_s(filepath.get(), bufsize, strVector[i].filepath.c_str()); + if (SUCCEEDED(m_psfFolder->ParseDisplayName(NULL, 0, filepath.get(), NULL, &pidl, NULL))) + m_pidlArray[succeededItems++] = pidl; // copy pidl to pidlArray } - wcscpy_s(filepath.get(), bufsize, strVector[i].filepath.c_str()); - if (SUCCEEDED(m_psfFolder->ParseDisplayName(NULL, 0, filepath.get(), NULL, &pidl, NULL))) - { - m_pidlArray[succeededItems++] = pidl; // copy pidl to pidlArray - m_strVector.push_back(strVector[i]); - if (lineVector.size() > (size_t)i) - m_lineVector.push_back(lineVector[i]); - } + m_strVector.push_back(strVector[i]); + if (lineVector.size() > i) + m_lineVector.push_back(lineVector[i]); + //////////////////////////////////////////////////////////// } m_pidlArrayItems = succeededItems; Index: src/grepWin.cpp =================================================================== --- src/grepWin.cpp (revision 632) +++ src/grepWin.cpp (working copy) @@ -30,6 +30,12 @@ HINSTANCE g_hInst; // current instance bool bPortable = false; CSimpleIni g_iniFile; +std::wstring NULL_STR(L"\0", 1); //+[JOJO] +bool bReload = false; //+[JOJO] +#ifdef RELOAD_TEST_1 +std::wstring g_searchString; //+[JOJO] +std::wstring g_replaceString; //+[JOJO] +#endif static std::wstring SanitizeSearchPaths(const std::wstring& searchpath) { @@ -98,6 +104,28 @@ LPTSTR lpCmdLine, int nCmdShow) { + //////////////////////////////////////////////////////////// + // [JOJO] +#ifdef _DEBUG + /* + * grepWin.exe >#grepWin.log 2>&1 + */ + std::wstring log = CPathUtils::GetModulePath(L"#grepWin.log"); + // WCHAR modulepath[MAX_PATH] = {0}; + // GetModuleFileName(0, modulepath, MAX_PATH); + // std::wstring log = modulepath; + // log = log.substr(0, log.find_last_of('\\') + 1) + L"#grepWin.log"; + setlocale(LC_ALL, ""); +#pragma warning(push) +#pragma warning(disable:4996) + _wfreopen(log.c_str(), L"w", stdout); +#pragma warning(pop) + setvbuf(stdout, NULL, _IONBF, 0); + *stderr = *stdout; + SetStdHandle(STD_ERROR_HANDLE, GetStdHandle(STD_OUTPUT_HANDLE)); // POSIX: dup2(1, 2) + wprintf(L"%S(%d) %S(%08x,%08x,\"%s\",%d)\n", __FILE__, __LINE__, __FUNCTION__, (int)hInstance, (int)hPrevInstance, lpCmdLine, nCmdShow); +#endif + //////////////////////////////////////////////////////////// UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); @@ -168,15 +196,15 @@ auto modulename = CPathUtils::GetFileName(CPathUtils::GetModulePath(0)); bPortable = ((_tcsstr(modulename.c_str(), _T("portable"))) || (parser.HasKey(_T("portable")))); - std::wstring iniPath = CPathUtils::GetModuleDir(0); - iniPath += L"\\grepwin.ini"; - if (parser.HasVal(L"inipath")) - iniPath = parser.GetVal(L"inipath"); - + //////////////////////////////////////////////////////////// + // [JOJO] + std::wstring iniPath = parser.HasVal(L"inipath") ? parser.GetVal(L"inipath") : CPathUtils::GetModulePath(L"grepwin.ini"); if (bPortable) + { g_iniFile.LoadFile(iniPath.c_str()); + } + //////////////////////////////////////////////////////////// - if (hWnd) { bool bOnlyOne = !!DWORD(CRegStdDWORD(_T("Software\\grepWin\\onlyone"), 0)); @@ -212,7 +240,9 @@ int ret = 0; if (!bQuit) { - CLanguage::Instance().LoadFile(bPortable ? g_iniFile.GetValue(L"global", L"languagefile", L"") : std::wstring(CRegStdString(L"Software\\grepWin\\languagefile"))); + std::wstring languagefile = bPortable ? g_iniFile.GetValue(L"global", L"languagefile", L"") : std::wstring(CRegStdString(L"Software\\grepWin\\languagefile")); + languagefile = CPathUtils::GetFileName(languagefile); // without directory + CLanguage::Instance().LoadFile(CPathUtils::GetModulePath(languagefile)); if (parser.HasKey(_T("about"))||parser.HasKey(_T("?"))||parser.HasKey(_T("help"))) { CAboutDlg aboutDlg(NULL); @@ -238,6 +268,8 @@ if (parser.HasVal(_T("replacewith"))) searchDlg.SetReplaceWith(parser.GetVal(_T("replacewith"))); + if (parser.HasVal(_T("w"))) + searchDlg.SetWordMatch(_tcsicmp(parser.GetVal(_T("w")), _T("yes"))!=0); //+[JOJO] if (parser.HasVal(_T("i"))) searchDlg.SetCaseSensitive(_tcsicmp(parser.GetVal(_T("i")), _T("yes"))!=0); if (parser.HasVal(_T("n"))) @@ -269,7 +301,21 @@ if (parser.HasKey(_T("execute"))) searchDlg.SetExecute(true); +RELOAD: + bReload = false; ret = (int)searchDlg.DoModal(hInstance, IDD_SEARCHDLG, NULL, IDR_SEARCHDLG); + //////////////////////////////////////////////////////////// + // [JOJO] + if (bReload) // CSettingsDlg --> CSearchDlg --> WinMain + { + searchDlg = CSearchDlg(NULL); +#ifdef RELOAD_TEST_1 + searchDlg.SetSearchString(g_searchString); g_searchString = L""; + searchDlg.SetReplaceWith(g_replaceString); g_replaceString = L""; +#endif + goto RELOAD; + } + //////////////////////////////////////////////////////////// } if (bPortable) { Index: src/grepWin.vcxproj =================================================================== --- src/grepWin.vcxproj (revision 632) +++ src/grepWin.vcxproj (working copy) @@ -1,5 +1,5 @@  - + Debug @@ -30,23 +30,23 @@ Unicode Application true - v140 + v120 Unicode Application true - v140 + v120 Unicode Application - v140 + v120 Unicode Application - v140 + v120 @@ -91,6 +91,7 @@ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDebug Level4 + /FC %(AdditionalOptions) true @@ -109,6 +110,7 @@ WIN64;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDebug Level4 + /FC %(AdditionalOptions) true @@ -127,6 +129,7 @@ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded Level4 + /FC %(AdditionalOptions) true @@ -148,6 +151,7 @@ WIN64;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded Level4 + /FC %(AdditionalOptions) true Index: src/resource.h =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: src/stdafx.h =================================================================== --- src/stdafx.h (revision 632) +++ src/stdafx.h (working copy) @@ -47,6 +47,22 @@ extern HINSTANCE g_hInst; extern bool bPortable; extern CSimpleIni g_iniFile; +extern std::wstring NULL_STR; //+[JOJO] +extern bool bReload; //+[JOJO] +#define RELOAD_TEST_1 +#ifdef RELOAD_TEST_1 +extern std::wstring g_searchString; //+[JOJO] +extern std::wstring g_replaceString; //+[JOJO] +#endif +#if _DEBUG +#define NUL_SYMBOL _T("") //+[JOJO] +#define EOF_SYMBOL _T("") //+[JOJO] +//#define EOF_SYMBOL _T("\032") //+[JOJO] +#else +#define NUL_SYMBOL _T(" ") //+[JOJO] +#define EOF_SYMBOL _T("") //+[JOJO] +#endif +#define PATH_SEPARATORS "|;," //+[JOJO] #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") Index: sktoolslib/Language.cpp =================================================================== --- sktoolslib/Language.cpp (revision 171) +++ sktoolslib/Language.cpp (working copy) @@ -29,49 +29,33 @@ #include #include #include +#include //wcsrchr -#define MAX_STRING_LENGTH (64*1024) +#define MAX_STRING_LENGTH (4*1024) bool CLanguage::LoadFile( const std::wstring& path ) { - // revert to original language - std::map langmap2; - for (auto it = langmap.cbegin(); it != langmap.cend(); ++it) - { - langmap2[it->second] = it->first; - } - langmap = langmap2; - + langmap.clear(); //[JOJO] if (!PathFileExists(path.c_str())) return false; - // since stream classes still expect the filepath in char and not wchar_t - // we need to convert the filepath to multibyte first - char filepath[MAX_PATH+1]; - SecureZeroMemory(filepath, sizeof(filepath)); - WideCharToMultiByte(CP_ACP, NULL, path.c_str(), -1, filepath, _countof(filepath)-1, NULL, NULL); - - std::wifstream File; - File.imbue(std::locale(std::locale(), new utf8_conversion())); - try + FILE *file = _wfsopen(path.c_str(), L"rt,ccs=UTF-8", _SH_DENYNO); //[JOJO] + if (file == NULL) { - } - catch (std::ios_base::failure &) - { return false; } - File.open(filepath); - if (!File.good()) - { - return false; - } - std::unique_ptr line(new TCHAR[2*MAX_STRING_LENGTH]); + WCHAR line[MAX_STRING_LENGTH]; std::vector entry; do { - File.getline(line.get(), 2*MAX_STRING_LENGTH); - if (line.get()[0]==0) + //////////////////////////////////////////////////////////// + // [JOJO] + line[0] = '\0'; + fgetws(line, MAX_STRING_LENGTH, file); + WCHAR *p; if ((p = wcsrchr(line, '\n')) != NULL) *p = '\0'; + //////////////////////////////////////////////////////////// + if (line[0] == '\0') { //empty line means end of entry! std::wstring msgid; @@ -79,25 +63,26 @@ int type = 0; for (auto I = entry.begin(); I != entry.end(); ++I) { - if (wcsncmp(I->c_str(), L"# ", 2)==0) + const WCHAR *str = I->c_str(); + if (wcsncmp(str, L"# ", 2)==0) { //user comment type = 0; } - if (wcsncmp(I->c_str(), L"#.", 2)==0) + else if (wcsncmp(str, L"#.", 2)==0) { //automatic comments type = 0; } - if (wcsncmp(I->c_str(), L"#,", 2)==0) + else if (wcsncmp(str, L"#,", 2)==0) { //flag type = 0; } - if (wcsncmp(I->c_str(), L"msgid", 5)==0) + else if (wcsncmp(str, L"msgid", 5)==0) { //message id - msgid = I->c_str(); + msgid = str; msgid = std::wstring(msgid.substr(7, msgid.size() - 8)); std::wstring s = msgid; @@ -104,27 +89,20 @@ s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); type = 1; } - if (wcsncmp(I->c_str(), L"msgstr", 6)==0) + else if (wcsncmp(str, L"msgstr", 6)==0) { //message string - msgstr = I->c_str(); + msgstr = str; msgstr = msgstr.substr(8, msgstr.length() - 9); type = 2; } - if (wcsncmp(I->c_str(), L"\"", 1)==0) + else if (wcsncmp(str, L"\"", 1)==0) { + std::wstring temp = str; if (type == 1) - { - std::wstring temp = I->c_str(); - temp = temp.substr(1, temp.length()-2); - msgid += temp; - } - if (type == 2) - { - std::wstring temp = I->c_str(); - temp = temp.substr(1, temp.length()-2); - msgstr += temp; - } + msgid += temp.substr(1, temp.length()-2); + else if (type == 2) + msgstr += temp.substr(1, temp.length()-2); } } entry.clear(); @@ -143,10 +121,10 @@ } else { - entry.push_back(line.get()); + entry.push_back(line); } - } while (File.gcount() > 0); - File.close(); + } while (!feof(file)); + fclose(file); return true; } @@ -243,6 +221,14 @@ BOOL CALLBACK CLanguage::TranslateWindowProc( HWND hwnd, LPARAM lParam ) { + //////////////////////////////////////////////////////////// + // [JOJO] + WCHAR classname[1024] = {0}; + GetClassName(hwnd, classname, _countof(classname)); + if (wcscmp(classname, L"Edit") == 0) + return TRUE; + //////////////////////////////////////////////////////////// + std::map * pLangMap = (std::map *)lParam; int length = GetWindowTextLength(hwnd); std::unique_ptr text(new wchar_t[length+1]); @@ -253,8 +239,7 @@ SetWindowText(hwnd, translatedString.c_str()); } - wchar_t classname[1024] = {0}; - if (GetClassName(hwnd, classname, _countof(classname))) + if (*classname) //[JOJO] { if (wcscmp(classname, L"ComboBox")==0) { Index: sktoolslib/PathUtils.cpp =================================================================== --- sktoolslib/PathUtils.cpp (revision 171) +++ sktoolslib/PathUtils.cpp (working copy) @@ -43,6 +43,8 @@ const wchar_t OtherOSPathSeparator = L'/'; const wchar_t DeviceSeparator = L':'; +static const WCHAR SEPARATORS[] = { DeviceSeparator, OtherOSPathSeparator, ThisOSPathSeparator, L'\0' }; //[JOJO] ":/\\" + // Check if the character given is either type of folder separator. // if we want to remove support for "other"separators we can just // change this function and force callers to use NormalizeFolderSeparators on @@ -131,69 +133,18 @@ return L"\\\\?\\" + path; } -// Return the parent directory for a given path. -// Note if the path is just a device like "c:" -// or a device and a root like "c:\" -// or a server name like "\\my_server" -// then there is no parent, so "" is returned. - -std::wstring CPathUtils::GetParentDirectory( const std::wstring& path ) +//////////////////////////////////////////////////////////// +// [JOJO] +static ptrdiff_t find_file_extention(const std::wstring& path) { - static std::wstring no_parent; - size_t filenameLen; - size_t pathLen = path.length(); - size_t pos; - - for (pos = pathLen; pos > 0; ) - { - --pos; - if (IsFolderSeparator(path[pos])) - { - filenameLen = pathLen - (pos + 1); - // If the path in it's entirety is just a root, i.e. "\", it has no parent. - if (pos == 0 && filenameLen == 0) - return no_parent; - // If the path in it's entirety is server name, i.e. "\\x", it has no parent. - if (pos == 1 && IsFolderSeparator(path[0]) && IsFolderSeparator(path[1]) - && filenameLen > 0) - return no_parent; - // If the parent begins with a device and root, i.e. "?:\" then - // include both in the parent. - if (pos == 2 && path[pos - 1] == DeviceSeparator) - { - // If the path is just a device i.e. not followed by a filename, it has no parent. - if (filenameLen == 0) - return no_parent; - ++pos; - } - // In summary, return everything before the last "\" of a filename unless the - // whole path given is: - // a server name, a device name, a root directory, or - // a device followed by a root directory, in which case return "". - std::wstring parent = path.substr(0, pos); - return parent; - } - } - // The path doesn't have a directory separator, we must be looking at either: - // 1. just a name, like "apple" - // 2. just a device, like "c:" - // 3. a device followed by a name "c:apple" - - // 1. and 2. specifically have no parent, - // For 3. the parent is the device including the separator. - // We'll return just the separator if that's all there is. - // It's an odd corner case but allow it through so the caller - // yields an error if it uses it concatenated with another name rather - // than something that might work. - pos = path.find_first_of(DeviceSeparator); - if (pos != std::wstring::npos) - { - // A device followed by a path. The device is the parent. - std::wstring parent = path.substr(0, pos+1); - return parent; - } - return no_parent; + ptrdiff_t start = path.find_last_of(SEPARATORS) + 1; + if (path[start] == '.') ++start; + for (ptrdiff_t pos = path.length(); --pos >= start;) + if (path[pos] == '.') + return pos; + return std::wstring::npos; } +//////////////////////////////////////////////////////////// // Finds the last "." after the last path separator and returns // everything after it, NOT including the ".". @@ -207,52 +158,25 @@ // Start at the last character and work back stopping at the // first . or path separator. If we find a dot take the rest // after it as the extension. - for (size_t i = path.length(); i > 0;) - { - --i; - if (IsFolderSeparator(path[i])) - break; - if (path[i] == L'.') - { - std::wstring ext = path.substr(i+1); - return ext; - } - } - return std::wstring(); + + //////////////////////////////////////////////////////////// + // [JOJO] + ptrdiff_t pos = find_file_extention(path); + return pos == std::wstring::npos ? std::wstring() : path.substr(pos + 1); + //////////////////////////////////////////////////////////// } -// Finds the first "." after the last path separator and returns -// everything after it, NOT including the ".". -// Handles leading folders with dots. -// Example, if given: "c:\product version 1.0\test.aspx.cs" -// returns: "aspx.cs" -std::wstring CPathUtils::GetLongFileExtension( const std::wstring& path ) +//////////////////////////////////////////////////////////// +// [JOJO] +// including the "." +// Example, if given: "c:\product version 1.0\test.txt" +// returns: ".txt" +std::wstring CPathUtils::GetFileNameExtension(const std::wstring& path) { - // Find the last dot after the first path separator as - // folders can have dots in them too. - // Start at the last character and work back stopping at the - // first . or path separator. If we find a dot take the rest - // after it as the extension. - size_t foundPos = size_t(-1); - bool found = false; - for (size_t i = path.length(); i > 0;) - { - --i; - if (IsFolderSeparator(path[i])) - break; - if (path[i] == L'.') - { - foundPos = i; - found = true; - } - } - if (found && foundPos > 0) - { - std::wstring ext = path.substr(foundPos+1); - return ext; - } - return std::wstring(); + ptrdiff_t pos = find_file_extention(path); + return pos == std::wstring::npos ? std::wstring() : path.substr(pos); } +//////////////////////////////////////////////////////////// // Given "c:\folder\test.txt", yields "test.txt". // Isn't tripped up by path names having both separators @@ -260,23 +184,10 @@ // Handles c:test.txt as can sometimes appear too. std::wstring CPathUtils::GetFileName(const std::wstring& path) { - bool gotSep = false; - size_t sepPos = 0; - - for (size_t i = path.length(); i > 0;) - { - --i; - if (IsFolderSeparator(path[i]) || path[i] == DeviceSeparator) - { - gotSep = true; - sepPos = i; - break; - } - } - size_t nameStart = gotSep ? sepPos + 1 : 0; - size_t nameLen = path.length() - nameStart; - std::wstring name = path.substr(nameStart, nameLen); - return name; + //////////////////////////////////////////////////////////// + // [JOJO] + return path.substr(path.find_last_of(SEPARATORS) + 1); + //////////////////////////////////////////////////////////// } // Returns only the filename without extension, i.e. will not include a path. @@ -285,12 +196,6 @@ return RemoveExtension(GetFileName(path)); } -// Returns only the filename without extension, i.e. will not include a path. -std::wstring CPathUtils::GetFileNameWithoutLongExtension( const std::wstring& path ) -{ - return RemoveLongExtension(GetFileName(path)); -} - // Finds the last "." after the last path separator and returns // everything before it. // Does not include the dot. Handles leading folders with dots. @@ -298,50 +203,13 @@ // returns: "c:\product version 1.0\test" std::wstring CPathUtils::RemoveExtension( const std::wstring& path ) { - for (size_t i = path.length(); i > 0;) - { - --i; - if (IsFolderSeparator(path[i])) - break; - if (path[i] == L'.') - return path.substr(0, i); - } - return path; + //////////////////////////////////////////////////////////// + // [JOJO] + ptrdiff_t pos = find_file_extention(path); + return pos == std::wstring::npos ? path : path.substr(0, pos); + //////////////////////////////////////////////////////////// } -// Finds the first "." after the last path separator and returns -// everything before it, NOT including the ".". -// Handles leading folders with dots. -// Example, if given: "c:\product version 1.0\test.aspx.cs" -// returns: "aspx.cs" -std::wstring CPathUtils::RemoveLongExtension( const std::wstring& path ) -{ - // Find the last dot after the first path separator as - // folders can have dots in them too. - // Start at the last character and work back stopping at the - // first . or path separator. If we find a dot take the rest - // after it as the extension. - size_t foundPos = size_t(-1); - bool found = false; - for (size_t i = path.length(); i > 0;) - { - --i; - if (IsFolderSeparator(path[i])) - break; - if (path[i] == L'.') - { - foundPos = i; - found = true; - } - } - if (found && foundPos > 0) - { - std::wstring pathWithoutExt = path.substr(0, foundPos); - return pathWithoutExt; - } - return path; -} - std::wstring CPathUtils::GetModulePath( HMODULE hMod /*= nullptr*/ ) { DWORD len = 0; @@ -357,9 +225,22 @@ return sPath; } +//////////////////////////////////////////////////////////// +// [JOJO] +std::wstring CPathUtils::GetModulePath(const std::wstring& name, HMODULE hMod /*= nullptr*/) +{ + std::wstring path = GetModulePath(hMod); + return path.substr(0, path.find_last_of(SEPARATORS) + 1) + name; +} +//////////////////////////////////////////////////////////// + std::wstring CPathUtils::GetModuleDir( HMODULE hMod /*= nullptr*/ ) { - return GetParentDirectory(GetModulePath(hMod)); + //////////////////////////////////////////////////////////// + // [JOJO] + std::wstring path = GetModulePath(hMod); + return path.substr(0, path.find_last_of(SEPARATORS) + 1); + //////////////////////////////////////////////////////////// } // Append one path onto another such that "path" + "append" = "path\append" @@ -659,11 +540,14 @@ { assert(CPathUtils::AdjustForMaxPath(L"c:\\") == L"c:\\"); assert(CPathUtils::AdjustForMaxPath(L"c:\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz") == L"\\\\?\\c:\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz\\abcdefghijklmnopqrstuvwxyz"); - assert(CPathUtils::GetParentDirectory(L"c:\\windows\\system32") == L"c:\\windows"); - assert(CPathUtils::GetParentDirectory(L"c:\\") == L""); - assert(CPathUtils::GetParentDirectory(L"\\myserver") == L""); assert(CPathUtils::GetFileExtension(L"d:\\test.file.ext1.ext2") == L"ext2"); - assert(CPathUtils::GetLongFileExtension(L"d:\\test.file.ext1.ext2") == L"file.ext1.ext2"); + assert(CPathUtils::GetFileExtension(L"test.file.ext1.ext2") == L"ext2"); //[JOJO] + assert(CPathUtils::GetFileExtension(L".htaccess.01.bak") == L"bak"); //[JOJO] + assert(CPathUtils::GetFileExtension(L".htaccess") == L""); //[JOJO] + assert(CPathUtils::GetFileNameExtension(L"d:\\test.file.ext1.ext2") == L".ext2"); //[JOJO] + assert(CPathUtils::GetFileNameExtension(L"test.file.ext1.ext2") == L".ext2"); //[JOJO] + assert(CPathUtils::GetFileNameExtension(L".htaccess.01.bak") == L".bak"); //[JOJO] + assert(CPathUtils::GetFileNameExtension(L".htaccess") == L""); //[JOJO] assert(!CPathUtils::PathIsChild(L"c:\\windows\\", L"c:\\windows")); assert(!CPathUtils::PathIsChild(L"c:\\windows\\", L"c:\\windows\\")); assert(CPathUtils::PathIsChild(L"c:\\windows\\", L"c:\\windows\\child\\")); @@ -671,6 +555,17 @@ assert(CPathUtils::PathIsChild(L"c:\\windows", L"c:\\windows\\child")); assert(!CPathUtils::PathIsChild(L"c:\\windows", L"c:\\windowsnotachild")); assert(!CPathUtils::PathIsChild(L"c:\\windows\\", L"c:\\windowsnotachild")); + + assert(CPathUtils::GetFileNameWithoutExtension(L"A:\\grepWin") == L"grepWin"); //[JOJO] + assert(CPathUtils::GetFileNameWithoutExtension(L"A:\\grepWin.exe") == L"grepWin"); //[JOJO] + assert(CPathUtils::GetFileNameWithoutExtension(L"A:grepWin.exe") == L"grepWin"); //[JOJO] + assert(CPathUtils::GetFileNameWithoutExtension(L"\\\\1.0\\grepWin.exe") == L"grepWin"); //[JOJO] + assert(CPathUtils::GetFileNameWithoutExtension(L"grepWin.exe") == L"grepWin"); //[JOJO] + assert(CPathUtils::GetFileNameWithoutExtension(L"grepWin") == L"grepWin"); //[JOJO] + assert(CPathUtils::RemoveExtension(L"A:\\grepWin.exe") == L"A:\\grepWin"); //[JOJO] + assert(CPathUtils::RemoveExtension(L"C:\\1.0\\.htaccess.bak") == L"C:\\1.0\\.htaccess"); //[JOJO] + assert(CPathUtils::RemoveExtension(L"C:\\1.0\\.htaccess") == L"C:\\1.0\\.htaccess"); //[JOJO] + assert(CPathUtils::RemoveExtension(L"C:\\1.0\\.htaccess.1.0.bak") == L"C:\\1.0\\.htaccess.1.0"); //[JOJO] } } CPathTests; #endif \ No newline at end of file Index: sktoolslib/PathUtils.h =================================================================== --- sktoolslib/PathUtils.h (revision 171) +++ sktoolslib/PathUtils.h (working copy) @@ -32,12 +32,15 @@ static std::wstring GetLongPathname(const std::wstring& path); static std::wstring AdjustForMaxPath(const std::wstring& path); - static std::wstring GetParentDirectory(const std::wstring& path); + // static std::wstring GetParentDirectory(const std::wstring& path); //-[JOJO] static std::wstring GetFileExtension(const std::wstring& path); - static std::wstring GetLongFileExtension(const std::wstring& path); + static std::wstring GetFileNameExtension(const std::wstring& path); //+[JOJO] + // static std::wstring GetLongFileExtension(const std::wstring& path); //-[JOJO] + // static std::wstring GetLongFileNameExtension(const std::wstring& path); //+[JOJO] static std::wstring GetFileName(const std::wstring& path); // module/app paths static std::wstring GetModulePath(HMODULE hMod = NULL); + static std::wstring GetModulePath(const std::wstring& name, HMODULE hMod = NULL); //+[JOJO] static std::wstring GetModuleDir(HMODULE hMod = NULL); static std::wstring Append(const std::wstring& path, const std::wstring& append); static std::wstring GetTempFilePath(); @@ -49,7 +52,7 @@ static int PathCompareN(const std::wstring& path1, const std::wstring& path2, size_t limit); static bool PathIsChild(const std::wstring& parent, const std::wstring& child); static std::wstring GetFileNameWithoutExtension( const std::wstring& path ); - static std::wstring GetFileNameWithoutLongExtension( const std::wstring& path ); + // static std::wstring GetFileNameWithoutLongExtension( const std::wstring& path ); //-[JOJO] static std::wstring RemoveExtension( const std::wstring& path ); static std::wstring RemoveLongExtension( const std::wstring& path ); static bool Unzip2Folder(LPCWSTR lpZipFile, LPCWSTR lpFolder); Index: sktoolslib/StringUtils.cpp =================================================================== --- sktoolslib/StringUtils.cpp (revision 171) +++ sktoolslib/StringUtils.cpp (working copy) @@ -278,43 +278,19 @@ void SearchReplace(std::wstring& str, const std::wstring& toreplace, const std::wstring& replacewith) { - std::wstring result; - std::wstring::size_type pos = 0; - for (;;) // while (true) - { - std::wstring::size_type next = str.find(toreplace, pos); - result.append(str, pos, next-pos); - if (next != std::string::npos) - { - result.append(replacewith); - pos = next + toreplace.size(); - } - else - { - break; // exit loop - } - } - str.swap(result); + //////////////////////////////////////////////////////////// + // [JOJO] + for (size_t pos = 0; (pos = str.find(toreplace, pos)) != std::wstring::npos; pos += replacewith.length()) + str.replace(pos, toreplace.length(), replacewith); + //////////////////////////////////////////////////////////// } void SearchReplace( std::string& str, const std::string& toreplace, const std::string& replacewith ) { - std::string result; - std::string::size_type pos = 0; - for (;;) // while (true) - { - std::string::size_type next = str.find(toreplace, pos); - result.append(str, pos, next-pos); - if (next != std::string::npos) - { - result.append(replacewith); - pos = next + toreplace.size(); - } - else - { - break; // exit loop - } - } - str.swap(result); + //////////////////////////////////////////////////////////// + // [JOJO] + for (size_t pos = 0; (pos = str.find(toreplace, pos)) != std::string::npos; pos += replacewith.length()) + str.replace(pos, toreplace.length(), replacewith); + //////////////////////////////////////////////////////////// } Index: sktoolslib/TextFile.cpp =================================================================== --- sktoolslib/TextFile.cpp (revision 171) +++ sktoolslib/TextFile.cpp (working copy) @@ -19,6 +19,7 @@ #include "stdafx.h" #include +#include "PathUtils.h" //+[JOJO] #include "TextFile.h" #include "maxpath.h" @@ -82,7 +83,7 @@ { if (retrycounter) Sleep(20); - hFile = CreateFile(pathbuf.get(), GENERIC_READ, FILE_SHARE_READ, + hFile = CreateFile(pathbuf.get(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //[JOJO] +FILE_SHARE_WRITE FILE_SHARE_DELETE NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); retrycounter++; } while (hFile == INVALID_HANDLE_VALUE && retrycounter < 5); @@ -89,9 +90,7 @@ if (hFile == INVALID_HANDLE_VALUE) return false; - std::wstring wpath(path); - size_t pos = wpath.find_last_of('\\'); - filename = wpath.substr(pos+1); + filename = CPathUtils::GetFileName(path); if (!GetFileSizeEx(hFile, &lint)) { CloseHandle(hFile); @@ -387,92 +386,121 @@ return ANSI; } +//////////////////////////////////////////////////////////// +// [JOJO] add +WCHAR* CTextFile::eol() +{ + for (auto it = textcontent.begin(), end = textcontent.end(); it != end; ++it) { + if (*it == '\r') + { + if (++it == end || *it != '\n') + return L"\r"; + } + else if (*it == '\n') + { + return L"\n"; + } + } + return L"\r\n"; +} +//////////////////////////////////////////////////////////// + bool CTextFile::CalculateLines() { + //////////////////////////////////////////////////////////// + // [JOJO] fix // fill an array with starting positions for every line in the loaded file + linepositions.clear(); + linepositions.push_back(0); if (pFileBuf == NULL) return false; if (textcontent.empty()) return true; - linepositions.clear(); - size_t pos = 0; - for (auto it = textcontent.begin(); it != textcontent.end(); ++it) + const auto start = textcontent.begin(); + const auto end = textcontent.end(); + auto it = start; + for (;;) { if (*it == '\r') { - ++it; - ++pos; - if (it != textcontent.end()) + if (++it == end) break; + if (*it == '\n') { - if (*it == '\n') - { - // crlf lineending - linepositions.push_back(pos); - } - else - { - // cr lineending - linepositions.push_back(pos-1); - } + // crlf lineending + if (++it == end) break; + linepositions.push_back(it - start); } else - break; + { + // cr lineending + linepositions.push_back(it - start); + } } else if (*it == '\n') { // lf lineending - linepositions.push_back(pos); + if (++it == end) break; + linepositions.push_back(it - start); } - ++pos; + else + { + if (++it == end) break; + } } - linepositions.push_back(pos); + //////////////////////////////////////////////////////////// + linepositions.push_back(it - start); return true; } -long CTextFile::LineFromPosition(long pos) const +long CTextFile::LineFromPosition(size_t pos) const { - long line = 0; - for (auto it = linepositions.begin(); it != linepositions.end(); ++it) + //////////////////////////////////////////////////////////// + // [JOJO] fix + long low = 0, high = (long)linepositions.size() - 1; + if (pos >= textcontent.length()) + return high; + + // binary search + while (low <= high) { - line++; - if (pos <= long(*it)) - break; + long mid = (low + high) / 2; + size_t value = linepositions[mid]; + if (value < pos) + low = mid + 1; + else if (value > pos) + high = mid - 1; + else + return 1 + mid; } - return line; + return low; + //////////////////////////////////////////////////////////// } std::wstring CTextFile::GetLineString(long lineNumber) const { - if ((lineNumber-2) >= (long)linepositions.size()) + //////////////////////////////////////////////////////////// + // [JOJO] fix + if (lineNumber < 1 || lineNumber >= (long)linepositions.size()) return std::wstring(); - if (lineNumber <= 0) - return std::wstring(); - long startpos = 0; - if (lineNumber > 1) - startpos = (long)linepositions[lineNumber-2]; - size_t endpos = textcontent.find(_T("\n"), startpos+1); - std::wstring line; - if (endpos != std::wstring::npos) - line = std::wstring(textcontent.begin()+startpos, textcontent.begin() + endpos); - else - line = std::wstring(textcontent.begin()+startpos, textcontent.end()); - - return line; + size_t startpos = linepositions[lineNumber - 1]; + size_t endpos = linepositions[lineNumber ]; + return std::wstring(textcontent.begin() + startpos, textcontent.begin() + endpos); + //////////////////////////////////////////////////////////// } std::wstring CTextFile::GetFileNameWithoutExtension() { - size_t pos = filename.find_last_of('.'); - if (pos != std::string::npos) - return filename.substr(0, pos); - return filename; + //////////////////////////////////////////////////////////// + // [JOJO] + return CPathUtils::GetFileNameWithoutExtension(filename); + //////////////////////////////////////////////////////////// } std::wstring CTextFile::GetFileNameExtension() { - size_t pos = filename.find_last_of('.'); - if (pos != std::string::npos) - return filename.substr(pos); - return L""; + //////////////////////////////////////////////////////////// + // [JOJO] + return CPathUtils::GetFileNameExtension(filename); + //////////////////////////////////////////////////////////// } Index: sktoolslib/TextFile.h =================================================================== --- sktoolslib/TextFile.h (revision 171) +++ sktoolslib/TextFile.h (working copy) @@ -63,7 +63,7 @@ /** * Returns the line number from a given character position inside the file. */ - long LineFromPosition(long pos) const; + long LineFromPosition(size_t pos) const; //[JOJO] -long /** * Returns the line from a given line number @@ -111,6 +111,12 @@ * Replaces the file content. */ void SetFileContent(const std::wstring& content); + + /** + * Returns the end of line + */ + WCHAR* eol(); //+[JOJO] + protected: /** * Tries to find out the encoding of the file (utf8, utf16, ansi)