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 <string>
 #include <Richedit.h>
 #include <boost/regex.hpp>
+#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 <string>
 #include <map>
@@ -59,7 +53,8 @@
 DWORD WINAPI SearchThreadEntry(LPVOID lpParam);
 
 UINT CSearchDlg::GREPWIN_STARTUPMSG = RegisterWindowMessage(_T("grepWin_StartupMessage"));
-std::map<size_t, DWORD> 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<TCHAR[]> 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<WCHAR[]> 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<WCHAR[]>(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<char[]>(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<std::wstring> 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<std::wstring> 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<std::string::const_iterator> 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<DWORD> matchlinesnumbers;
+                std::vector<DWORD> 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<DWORD> 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<size_t, DWORD> linepositions;
                             std::unique_ptr<char[]> 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<std::wstring>   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 <Commdlg.h>
+#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 @@
             <File Id="Deutsch.lang" Name="Deutsch.lang" DiskId="1" Source="../../translations/Deutsch.lang" />
             <File Id="Chinese.lang" Name="Chinese.lang" DiskId="1" Source="../../translations/Chinese.lang" />
             <File Id="Nederlands.lang" Name="Nederlands.lang" DiskId="1" Source="../../translations/Nederlands.lang" />
+            <File Id="Japanese.lang" Name="Japanese.lang" DiskId="1" Source="../../translations/Japanese.lang" />
+            <File Id="texteditors" Name="texteditors" DiskId="1" Source="../../translations/texteditors" />
             <RegistryKey Root="HKLM" Key="Software\Classes\Directory\shell\grepWin..." />
             <RegistryValue Root="HKLM" Key="Software\Classes\Directory\shell\grepWin...\command" Value='[INSTALLDIR]grepWin.exe /searchpath:"%1"' Type="string" />
             <RegistryValue Root="HKLM" Key="Software\Classes\Directory\shell\grepWin..." Name="Icon" Value='[INSTALLDIR]grepWin.exe,-107' Type="string" />
Index: src/Setup/Setup64.wxs
===================================================================
--- src/Setup/Setup64.wxs	(revision 632)
+++ src/Setup/Setup64.wxs	(working copy)
@@ -40,6 +40,8 @@
             <File Id="Deutsch.lang" Name="Deutsch.lang" DiskId="1" Source="../../translations/Deutsch.lang" />
             <File Id="Chinese.lang" Name="Chinese.lang" DiskId="1" Source="../../translations/Chinese.lang" />
             <File Id="Nederlands.lang" Name="Nederlands.lang" DiskId="1" Source="../../translations/Nederlands.lang" />
+            <File Id="Japanese.lang" Name="Japanese.lang" DiskId="1" Source="../../translations/Japanese.lang" />
+            <File Id="texteditors" Name="texteditors" DiskId="1" Source="../../translations/texteditors" />
             <RegistryKey Root="HKLM" Key="Software\Classes\Directory\shell\grepWin..." />
             <RegistryValue Root="HKLM" Key="Software\Classes\Directory\shell\grepWin...\command" Value='[INSTALLDIR]grepWin.exe /searchpath:"%1"' Type="string" />
             <RegistryValue Root="HKLM" Key="Software\Classes\Directory\shell\grepWin..." Name="Icon" Value='[INSTALLDIR]grepWin.exe,-107' Type="string" />
Index: src/Setup/Setup64_user.wxs
===================================================================
--- src/Setup/Setup64_user.wxs	(revision 632)
+++ src/Setup/Setup64_user.wxs	(working copy)
@@ -40,6 +40,8 @@
             <File Id="grepWin.EXE" Name="grepWin.exe" DiskId="1" Source="../../bin/release64/grepWin.exe" Vital="yes" />
             <File Id="Deutsch.lang" Name="Deutsch.lang" DiskId="1" Source="../../translations/Deutsch.lang" />
             <File Id="Chinese.lang" Name="Chinese.lang" DiskId="1" Source="../../translations/Chinese.lang" />
+            <File Id="Japanese.lang" Name="Japanese.lang" DiskId="1" Source="../../translations/Japanese.lang" />
+            <File Id="texteditors" Name="texteditors" DiskId="1" Source="../../translations/texteditors" />
             <RegistryKey Root="HKCU" Key="Software\Classes\Directory\shell\grepWin..." />
             <RegistryValue Root="HKCU" Key="Software\Classes\Directory\shell\grepWin...\command" Value='[INSTALLDIR]grepWin.exe /searchpath:"%1"' Type="string" KeyPath="yes" />
             <RegistryValue Root="HKCU" Key="Software\Classes\Directory\shell\grepWin..." Name="Icon" Value='[INSTALLDIR]grepWin.exe,-107' Type="string" />
Index: src/Setup/Setup_user.wxs
===================================================================
--- src/Setup/Setup_user.wxs	(revision 632)
+++ src/Setup/Setup_user.wxs	(working copy)
@@ -42,6 +42,8 @@
             <File Id="grepWin.EXE" Name="grepWin.exe" DiskId="1" Source="../../bin/release/grepWin.exe" Vital="yes" />
             <File Id="Deutsch.lang" Name="Deutsch.lang" DiskId="1" Source="../../translations/Deutsch.lang" />
             <File Id="Chinese.lang" Name="Chinese.lang" DiskId="1" Source="../../translations/Chinese.lang" />
+            <File Id="Japanese.lang" Name="Japanese.lang" DiskId="1" Source="../../translations/Japanese.lang" />
+            <File Id="texteditors" Name="texteditors" DiskId="1" Source="../../translations/texteditors" />
             <RegistryKey Root="HKCU" Key="Software\Classes\Directory\shell\grepWin..." />
             <RegistryValue Root="HKCU" Key="Software\Classes\Directory\shell\grepWin...\command" Value='[INSTALLDIR]grepWin.exe /searchpath:"%1"' Type="string" KeyPath="yes" />
             <RegistryValue Root="HKCU" Key="Software\Classes\Directory\shell\grepWin..." Name="Icon" Value='[INSTALLDIR]grepWin.exe,-107' Type="string" />
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 <set>
 #include <algorithm>
@@ -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<WCHAR[]> 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<WCHAR[]>(new WCHAR[bufsize]);
+            if (bufsize < strVector[i].filepath.size())
+            {
+                bufsize = strVector[i].filepath.size() + 3;
+                filepath = std::unique_ptr<WCHAR[]>(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 @@
 ﻿<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
@@ -30,23 +30,23 @@
     <CharacterSet>Unicode</CharacterSet>
     <ConfigurationType>Application</ConfigurationType>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <PlatformToolset>v140</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <CharacterSet>Unicode</CharacterSet>
     <ConfigurationType>Application</ConfigurationType>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <PlatformToolset>v140</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <CharacterSet>Unicode</CharacterSet>
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v140</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <CharacterSet>Unicode</CharacterSet>
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v140</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -91,6 +91,7 @@
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <WarningLevel>Level4</WarningLevel>
+      <AdditionalOptions>/FC %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,6 +110,7 @@
       <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <WarningLevel>Level4</WarningLevel>
+      <AdditionalOptions>/FC %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -127,6 +129,7 @@
       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <WarningLevel>Level4</WarningLevel>
+      <AdditionalOptions>/FC %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -148,6 +151,7 @@
       <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <WarningLevel>Level4</WarningLevel>
+      <AdditionalOptions>/FC %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
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("<NUL>")	//+[JOJO]
+#define EOF_SYMBOL _T("<EOF>")	//+[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 <cctype>
 #include <memory>
 #include <functional>
+#include <wchar.h> //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<std::wstring, std::wstring> 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<TCHAR[]> line(new TCHAR[2*MAX_STRING_LENGTH]);
+    WCHAR line[MAX_STRING_LENGTH];
     std::vector<std::wstring> 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<int, int>(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<std::wstring,std::wstring> * pLangMap = (std::map<std::wstring,std::wstring> *)lParam;
     int length = GetWindowTextLength(hwnd);
     std::unique_ptr<wchar_t[]> 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 <memory>
+#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)
