diff --git a/diff_ext_for_kdiff3/diff_ext.cpp b/diff_ext_for_kdiff3/diff_ext.cpp index 17ab1b5..d77a007 100644 --- a/diff_ext_for_kdiff3/diff_ext.cpp +++ b/diff_ext_for_kdiff3/diff_ext.cpp @@ -1,478 +1,480 @@ /* * Copyright (c) 2003-2006, Sergey Zorin. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #define _CRT_SECURE_NO_DEPRECATE #include "diff_ext.h" #include #include #include #include #include DIFF_EXT::DIFF_EXT() : m_nrOfSelectedFiles(0), _ref_count(0L), m_recentFiles( SERVER::instance()->recent_files() ) { LOG(); _resource = SERVER::instance()->handle(); SERVER::instance()->lock(); } DIFF_EXT::~DIFF_EXT() { LOG(); if(_resource != SERVER::instance()->handle()) { FreeLibrary(_resource); } SERVER::instance()->release(); } STDMETHODIMP DIFF_EXT::QueryInterface(REFIID refiid, void** ppv) { HRESULT ret = E_NOINTERFACE; *ppv = 0; if(IsEqualIID(refiid, IID_IShellExtInit) || IsEqualIID(refiid, IID_IUnknown)) { *ppv = static_cast(this); } else if (IsEqualIID(refiid, IID_IContextMenu)) { *ppv = static_cast(this); } if(*ppv != 0) { AddRef(); ret = NOERROR; } return ret; } STDMETHODIMP_(ULONG) DIFF_EXT::AddRef() { return InterlockedIncrement((LPLONG)&_ref_count); } STDMETHODIMP_(ULONG) DIFF_EXT::Release() { ULONG ret = 0L; if(InterlockedDecrement((LPLONG)&_ref_count) != 0) { ret = _ref_count; } else { delete this; } return ret; } STDMETHODIMP DIFF_EXT::Initialize(LPCITEMIDLIST /*folder not used*/, IDataObject* data, HKEY /*key not used*/) { LOG(); FORMATETC format = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium; medium.tymed = TYMED_HGLOBAL; HRESULT ret = E_INVALIDARG; if(data->GetData(&format, &medium) == S_OK) { HDROP drop = (HDROP)medium.hGlobal; m_nrOfSelectedFiles = DragQueryFile(drop, 0xFFFFFFFF, 0, 0); TCHAR tmp[MAX_PATH]; if (m_nrOfSelectedFiles >= 1 && m_nrOfSelectedFiles <= 3) { DragQueryFile(drop, 0, tmp, MAX_PATH); _file_name1 = tmp; if(m_nrOfSelectedFiles >= 2) { DragQueryFile(drop, 1, tmp, MAX_PATH); _file_name2 = tmp; } if( m_nrOfSelectedFiles == 3) { DragQueryFile(drop, 2, tmp, MAX_PATH); _file_name3 = tmp; } ret = S_OK; } } else { SYSERRORLOG(TEXT("GetData")); } return ret; } static int insertMenuItemHelper( HMENU menu, UINT id, UINT position, const tstring& text, UINT fState = MFS_ENABLED, HMENU hSubMenu=0 ) { MENUITEMINFO item_info; ZeroMemory(&item_info, sizeof(item_info)); item_info.cbSize = sizeof(MENUITEMINFO); item_info.wID = id; if (text.empty()) { // Separator item_info.fMask = MIIM_TYPE; item_info.fType = MFT_SEPARATOR; item_info.dwTypeData = 0; } else { item_info.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | (hSubMenu!=0 ? MIIM_SUBMENU : 0); item_info.fType = MFT_STRING; item_info.fState = fState; item_info.dwTypeData = (LPTSTR)text.c_str(); item_info.hSubMenu = hSubMenu; } if ( 0 == InsertMenuItem(menu, position, TRUE, &item_info) ) SYSERRORLOG(TEXT("InsertMenuItem")); return id; } STDMETHODIMP DIFF_EXT::QueryContextMenu(HMENU menu, UINT position, UINT first_cmd, UINT /*last_cmd not used*/, UINT flags) { LOG(); SERVER::instance()->recent_files(); // updates recent files list (reads from registry) m_id_Diff = UINT(-1); m_id_DiffWith = UINT(-1); m_id_DiffLater = UINT(-1); m_id_MergeWith = UINT(-1); m_id_Merge3 = UINT(-1); m_id_Diff3 = UINT(-1); m_id_DiffWith_Base = UINT(-1); m_id_ClearList = UINT(-1); m_id_About = UINT(-1); HRESULT ret = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); if(!(flags & CMF_DEFAULTONLY)) { /* Menu structure: KDiff3 -> (1 File selected): Save 'selection' for later comparison (push onto history stack) Compare 'selection' with first file on history stack. Compare 'selection' with -> choice from history stack Merge 'selection' with first file on history stack. Merge 'selection' with last two files on history stack. (2 Files selected): Compare 's1' with 's2' Merge 's1' with 's2' (3 Files selected): Compare 's1', 's2' and 's3' */ HMENU subMenu = CreateMenu(); UINT id = first_cmd; m_id_FirstCmd = first_cmd; insertMenuItemHelper( menu, id++, position++, TEXT("") ); // begin separator tstring menuString; UINT pos2=0; if(m_nrOfSelectedFiles == 1) { size_t nrOfRecentFiles = m_recentFiles.size(); - tstring menuStringCompare = i18n("Compare with %1"); - tstring menuStringMerge = i18n("Merge with %1"); + tstring menuStringCompare; + tstring menuStringMerge; tstring firstFileName; if( nrOfRecentFiles>=1 ) { firstFileName = TEXT("'") + cut_to_length( m_recentFiles.front() ) + TEXT("'"); } - replaceArgs( menuStringCompare, firstFileName ); - replaceArgs( menuStringMerge, firstFileName ); + + menuStringCompare = i18n("Compare with %1", firstFileName); + menuStringMerge = i18n("Merge with %1", firstFileName); + m_id_DiffWith = insertMenuItemHelper( subMenu, id++, pos2++, menuStringCompare, nrOfRecentFiles >=1 ? MFS_ENABLED : MFS_DISABLED ); m_id_MergeWith = insertMenuItemHelper( subMenu, id++, pos2++, menuStringMerge, nrOfRecentFiles >=1 ? MFS_ENABLED : MFS_DISABLED ); //if( nrOfRecentFiles>=2 ) //{ // tstring firstFileName = cut_to_length( m_recentFiles.front() ); // tstring secondFileName = cut_to_length( *(++m_recentFiles.begin()) ); //} m_id_Merge3 = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("3-way merge with base")), nrOfRecentFiles >=2 ? MFS_ENABLED : MFS_DISABLED ); - menuString = fromQString(i18n("Save '%1' for later").arg(toQString(_file_name1))); + menuString = fromQString(i18n("Save '%1' for later", toQString(_file_name1))); m_id_DiffLater = insertMenuItemHelper( subMenu, id++, pos2++, menuString ); HMENU file_list = CreateMenu(); std::list::iterator i; m_id_DiffWith_Base = id; int n = 0; for( i = m_recentFiles.begin(); i!=m_recentFiles.end(); ++i ) { tstring s = cut_to_length( *i ); insertMenuItemHelper( file_list, id++, n, s ); ++n; } insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("Compare with ...")), nrOfRecentFiles > 0 ? MFS_ENABLED : MFS_DISABLED, file_list ); m_id_ClearList = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("Clear list")), nrOfRecentFiles >=1 ? MFS_ENABLED : MFS_DISABLED ); } else if(m_nrOfSelectedFiles == 2) { //= "Diff " + cut_to_length(_file_name1, 20)+" and "+cut_to_length(_file_name2, 20); m_id_Diff = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("Compare")) ); } else if ( m_nrOfSelectedFiles == 3 ) { m_id_Diff3 = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("3 way comparison")) ); } else { // More than 3 files selected? } m_id_About = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("About Diff-Ext ...")) ); insertMenuItemHelper( menu, id++, position++, TEXT("KDiff3"), MFS_ENABLED, subMenu ); insertMenuItemHelper( menu, id++, position++, TEXT("") ); // final separator ret = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, id-first_cmd); } return ret; } STDMETHODIMP DIFF_EXT::InvokeCommand(LPCMINVOKECOMMANDINFO ici) { HRESULT ret = NOERROR; _hwnd = ici->hwnd; if(HIWORD(ici->lpVerb) == 0) { UINT id = m_id_FirstCmd + LOWORD(ici->lpVerb); if(id == m_id_Diff) { LOG(); diff( TEXT("\"") + _file_name1 + TEXT("\" \"") + _file_name2 + TEXT("\"") ); } else if(id == m_id_Diff3) { LOG(); diff( TEXT("\"") + _file_name1 + TEXT("\" \"") + _file_name2 + TEXT("\" \"") + _file_name3 + TEXT("\"") ); } else if(id == m_id_Merge3) { LOG(); std::list< tstring >::iterator iFrom = m_recentFiles.begin(); std::list< tstring >::iterator iBase = iFrom; ++iBase; diff( TEXT("-m \"") + *iBase + TEXT("\" \"") + *iFrom + TEXT("\" \"") + _file_name1 + TEXT("\"") ); } else if(id == m_id_DiffWith) { LOG(); diff_with(0, false); } else if(id == m_id_MergeWith) { LOG(); diff_with(0, true); } else if(id == m_id_ClearList) { LOG(); m_recentFiles.clear(); SERVER::instance()->save_history(); } else if(id == m_id_DiffLater) { MESSAGELOG(TEXT("Diff Later: ")+_file_name1); m_recentFiles.remove( _file_name1 ); m_recentFiles.push_front( _file_name1 ); SERVER::instance()->save_history(); } else if(id >= m_id_DiffWith_Base && id < m_id_DiffWith_Base+m_recentFiles.size()) { LOG(); diff_with(id-m_id_DiffWith_Base, false); } else if(id == m_id_About) { LOG(); QString sBits = i18n("(32 Bit)"); if (sizeof(void*)==8) MessageBox( _hwnd, (fromQString(i18n("Diff-Ext Copyright (c) 2003-2006, Sergey Zorin. All rights reserved.\n") + i18n("This software is distributable under the BSD-2-Clause license.\n") + i18n("Some extensions for KDiff3 (c) 2006-2013 by Joachim Eibl.\n") + i18n("Homepage for Diff-Ext: http://diff-ext.sourceforge.net\n"))).c_str() , fromQString(i18n("About Diff-Ext for KDiff3 ")+sBits).c_str(), MB_OK ); } else { ret = E_INVALIDARG; TCHAR verb[80]; _sntprintf(verb, 79, TEXT("Command id: %d"), LOWORD(ici->lpVerb)); verb[79]=0; ERRORLOG(verb); } } else { ret = E_INVALIDARG; } return ret; } STDMETHODIMP DIFF_EXT::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT*, LPSTR pszName, UINT cchMax) { // LOG(); // Gets called very often HRESULT ret = NOERROR; if(uFlags == GCS_HELPTEXT) { QString helpString; if( idCmd == m_id_Diff ) { helpString = i18n("Compare selected files"); } else if( idCmd == m_id_DiffWith ) { if(!m_recentFiles.empty()) { - helpString = i18n("Compare '%1' with '%2'").arg(toQString(_file_name1), toQString(m_recentFiles.front())); + helpString = i18n("Compare '%1' with '%2'", toQString(_file_name1), toQString(m_recentFiles.front())); } } else if(idCmd == m_id_DiffLater) { - helpString = i18n("Save '%1' for later operation").arg(_file_name1); + helpString = i18n("Save '%1' for later operation", _file_name1); } else if((idCmd >= m_id_DiffWith_Base) && (idCmd < m_id_DiffWith_Base+m_recentFiles.size())) { if( !m_recentFiles.empty() ) { unsigned int num = idCmd - m_id_DiffWith_Base; std::list::iterator i = m_recentFiles.begin(); for(unsigned int j = 0; j < num && i != m_recentFiles.end(); j++) i++; if ( i!=m_recentFiles.end() ) { - helpString = i18n("Compare '%1' with '%2'").arg(toQString(_file_name1), toQString(*i)); + helpString = i18n("Compare '%1' with '%2'", toQString(_file_name1), toQString(*i)); } } } lstrcpyn( (LPTSTR)pszName, fromQString(helpString).c_str(), cchMax ); } else { ret = E_INVALIDARG; } return ret; } void DIFF_EXT::diff( const tstring& arguments ) { LOG(); STARTUPINFO si; PROCESS_INFORMATION pi; bool bError = true; tstring command = SERVER::instance()->getRegistryKeyString( TEXT(""), TEXT("diffcommand") ); tstring commandLine = TEXT("\"") + command + TEXT("\" ") + arguments; if ( ! command.empty() ) { ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (CreateProcess(command.c_str(), (LPTSTR)commandLine.c_str(), 0, 0, FALSE, 0, 0, 0, &si, &pi) == 0) { SYSERRORLOG(TEXT("CreateProcess") + command); } else { bError = false; CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } } if (bError) { tstring message = fromQString(i18n("Could not start KDiff3. Please rerun KDiff3 installation.")); message += TEXT("\n") + fromQString(i18n("Command")) + TEXT(": ") + command; message += TEXT("\n") + fromQString(i18n("CommandLine")) + TEXT(": ") + commandLine; MessageBox(_hwnd, message.c_str(), fromQString(i18n("Diff-Ext For KDiff3")).c_str(), MB_OK); } } void DIFF_EXT::diff_with(unsigned int num, bool bMerge) { LOG(); std::list::iterator i = m_recentFiles.begin(); for(unsigned int j = 0; j < num && i!=m_recentFiles.end(); j++) { i++; } if ( i!=m_recentFiles.end() ) _file_name2 = *i; diff( (bMerge ? TEXT("-m \"") : TEXT("\"") ) + _file_name2 + TEXT("\" \"") + _file_name1 + TEXT("\"") ); } tstring DIFF_EXT::cut_to_length(const tstring& in, size_t max_len) { tstring ret; if( in.length() > max_len) { ret = in.substr(0, (max_len-3)/2); ret += TEXT("..."); ret += in.substr( in.length()-(max_len-3)/2 ); } else { ret = in; } return ret; } diff --git a/src/CommentParser.cpp b/src/CommentParser.cpp index b12f207..a5c7824 100644 --- a/src/CommentParser.cpp +++ b/src/CommentParser.cpp @@ -1,120 +1,120 @@ /** * Copyright (C) 2019 Michael Reeves * * This file is part of KDiff3. * * KDiff3 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * KDiff3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KDiff3. If not, see . */ #include "CommentParser.h" #include #include #include #include void DefaultCommentParser::processChar(const QString &line, const QChar &inChar) { if(!bIsEscaped) { switch(inChar.unicode()) { case '\\': if(bInString) bIsEscaped = true; break; case '\'': case '"': if(!inComment()) { if(!bInString) { bInString = true; mStartChar = inChar; } else if(mStartChar == inChar) { bInString = false; } } break; case '/': if(bInString) break; if(!inComment() && mLastChar == '/') { mCommentType = singleLine; - mIsPureComment = line.startsWith("//") ? yes : no; + mIsPureComment = line.startsWith(QLatin1String("//")) ? yes : no; } else if(mLastChar == '*' && mCommentType == multiLine) { //ending multi-line comment mCommentType = none; if(!isFirstLine) - mIsPureComment = line.endsWith("*/") ? yes : mIsPureComment; + mIsPureComment = line.endsWith(QLatin1String("*/")) ? yes : mIsPureComment; } break; case '*': if(bInString) break; if(mLastChar == '/' && !inComment()) { mCommentType = multiLine; - mIsPureComment = line.startsWith("/*") ? yes : mIsPureComment; + mIsPureComment = line.startsWith(QLatin1String("/*")) ? yes : mIsPureComment; isFirstLine = true; } break; case '\n': if(mCommentType == singleLine) { mCommentType = none; } if(mCommentType == multiLine && !isFirstLine) { mIsPureComment = yes; } isFirstLine = false; break; default: if(inComment()) { break; } mIsPureComment = no; break; } mLastChar = inChar; } else { bIsEscaped = false; mLastChar = QChar(); } }; void DefaultCommentParser::processLine(const QString &line) { for(const QChar &c : line) { processChar(line, c); } processChar(line, '\n'); } diff --git a/src/LineRef.h b/src/LineRef.h index fa1bda9..75ee4e5 100644 --- a/src/LineRef.h +++ b/src/LineRef.h @@ -1,97 +1,97 @@ /** * - * Copyright (C) 2018 Michael Reeves + * Copyright (C) 2018 Michael Reeves * * This file is part of Kdiff3. * * Kdiff3 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Kdiff3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kdiff3. If not, see . * */ #ifndef LINEREF_H #define LINEREF_H #include "TypeUtils.h" #include #include #include class LineRef { public: typedef qint32 LineType; inline LineRef() = default; inline LineRef(const LineType i) { mLineNumber = i; } inline LineRef(const qint64 i) { if(i <= TYPE_MAX(LineType)) mLineNumber = (LineType)i; else mLineNumber = -1; } inline operator LineType() const { return mLineNumber; } inline LineRef& operator=(const LineType lineIn) { mLineNumber = lineIn; return *this; } inline LineRef& operator+=(const LineType& inLine) { mLineNumber += inLine; return *this; }; LineRef& operator++() { ++mLineNumber; return *this; }; const LineRef operator++(int) { LineRef line(*this); ++mLineNumber; return line; }; LineRef& operator--() { --mLineNumber; return *this; }; const LineRef operator--(int) { LineRef line(*this); --mLineNumber; return line; }; inline void invalidate() { mLineNumber = -1; } inline bool isValid() const { return mLineNumber != -1; } private: LineType mLineNumber = -1; }; static_assert(std::is_copy_constructible::value, "LineRef must be copt constuctible."); static_assert(std::is_copy_assignable::value, "LineRef must copy assignable."); static_assert(std::is_move_constructible::value, "LineRef must be move constructible."); static_assert(std::is_move_assignable::value, "LineRef must be move assignable."); static_assert(std::is_convertible::value, "Can not convert LineRef to int."); static_assert(std::is_convertible::value, "Can not convert int to LineRef."); typedef LineRef::LineType LineCount; typedef LineRef::LineType LineIndex; #endif diff --git a/src/TypeUtils.h b/src/TypeUtils.h index 17230aa..f08c71f 100644 --- a/src/TypeUtils.h +++ b/src/TypeUtils.h @@ -1,37 +1,37 @@ /** * - * Copyright (C) 2018 Michael Reeves + * Copyright (C) 2018 Michael Reeves * * This file is part of Kdiff3. * * Kdiff3 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Kdiff3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kdiff3. If not, see . * */ #ifndef TYPEUTILS_H #define TYPEUTILS_H #include #include #include #define TYPE_MAX(x) std::numeric_limits::max() #define TYPE_MIN(x) std::numeric_limits::min() typedef size_t PtrDiffRef; typedef qint32 QtNumberType;//Qt insists on one type for all but does not create a typedef for it. static_assert(sizeof(int) >= sizeof(qint32), "Legacy LP32 systems/compilers not supported"); // e.g. Windows 16-bit #endif