...
 
Commits (115)
{
"phabricator.uri" : "https://phabricator.kde.org/"
}
stages:
- build
- test
build_ubuntu_18_04:
stage: build
image: reporter123/cmake:bionic
before_script:
- apt-get update
- apt-get install -y libqt5test5 gettext qtbase5-dev extra-cmake-modules libkf5i18n-dev libkf5coreaddons-dev libkf5iconthemes-dev libkf5parts-dev libkf5doctools-dev libkf5crash-dev
script:
- cmake -DBUILD_TESTING=YES .
- make
artifacts:
untracked: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
ubuntu_18_04_test:
stage: test
needs: ["build_ubuntu_18_04"]
image: reporter123/cmake:bionic
before_script:
- apt-get update
- apt-get install -y libqt5test5
script:
- make ARGS="-V -E appstreamtest" test #exclude appstreamtest this does not run properly in my image
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
......@@ -3,11 +3,12 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(kdiff3)
set(CMAKE_CXX_EXTENSIONS OFF ) #don't use non-standard extensions
set(CMAKE_CXX_EXTENSIONS ON ) #disable trigraphs in clang/gcc -- officially removed in c++17
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(ECM_MIN_VERSION "5.10.0")
set(QT_MIN_VERSION "5.6.0")
set(KF5_MIN_VERSION "5.23.0")
#KF5 5.27 fixes a crash bug triggered on exit.
set(KF5_MIN_VERSION "5.27.0")
find_package(ECM ${ECM_MIN_VERSION} CONFIG REQUIRED)
set(
......@@ -25,7 +26,7 @@ include(ECMInstallIcons)
include(ECMAddAppIcon)
include(ECMSetupVersion)
ecm_setup_version(1.8.0 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR}/src/version.h)
ecm_setup_version(1.8.2 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR}/src/version.h)
find_package(
Qt5 ${QT_MIN_VERSION}
......@@ -49,6 +50,7 @@ find_package(
IconThemes
)
option(ENABLE_AUTO "Enable kdiff3's '--auto' flag" ON)
option(ENABLE_CLANG_TIDY "Run clang-tidy if available and cmake version >=3.6" OFF)
set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5::Crash KF5::IconThemes )
......@@ -56,14 +58,16 @@ set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5:
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
#Adjust clang specific warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow")
set(CLANG_WARNING_FLAGS "-Wno-invalid-pp-token -Wno-comment -Wshorten-64-to-32 -Wstring-conversion -Wc++11-narrowing -fstack-protector-all")
set(CLANG_WARNING_FLAGS "-Wno-trigraphs -Wno-invalid-pp-token -Wno-comment -Wshorten-64-to-32 -Wstring-conversion -Wc++11-narrowing -fstack-protector-all")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_WARNING_FLAGS}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_definitions(-DNOMINMAX) #Suppress MSVCs min/max macros
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-check")
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wduplicated-cond -Wduplicated-branches -Wshadow")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-trigraphs -Wduplicated-cond -Wduplicated-branches -Wshadow")
endif()
endif()
......@@ -89,6 +93,12 @@ set(
cxx_static_assert
)
if(ENABLE_AUTO)
add_definitions(
-DENABLE_AUTO
)
endif()
add_definitions(
-DQT_DEPRECATED_WARNINGS #Get warnings from QT about deprecated functions.
-DQT_NO_URL_CAST_FROM_STRING # casting from string to url does not always behave as you might think
......
Version 1.8.2 - 2020-03-29
===========================
Bug 411472 Allowing editing of blank lines and don't mark newly intserted lines as a confilict
2ba20222 - Remove broken attempt to optimize drawing on horizonal scroll.
Bug 418813 - Fix line numbers not shown. Use QString::number directly not through a format string.
11e93232 - Correcly support "Print Current Page"
64804a64 - Don't attempt to free nullptr in SourceData::FileData::reset()
f4c66ace - Make Preferance dialog panes scrollable if too large to fit on screen.
de06e561 - Fix dialog filter on windows.
e8d06774 - Switch to QElapsedTime for timing avoids explictly undefined behavior inside qt if time is changed.
05e2d6fb - Fix sync mode.
f9bd88a1 - Make matching in CvsIngnoreList always honor bCaseSensitive setting.
418ea78c - Don't use temporary with QLatin1String constructor strange things will happen.
b058c060 - ignore over size cvsignore files
Bug 410962 - Fix '-L' parameter handling
b4b2c970 - Restore acciedently deleted --auto option
Bug 411602 - Fixing missing menu items also resolves a potiential crash in MergeResultWindow::slotUpdateAvailabilities (Bug 407745).
d4239b92 - Prevent intermient crash during reload/refresh
Bug 410008 - Show diff for empty/missing files.
3bb755c5 - Don't give false error when comparing empty folders
Bug 408991 - 4ad69790,0737cc3e,0402f84a - Close files when not in use - Fixes "Too many open files" bug.
Bug 407829 - Avoid crash when recieving mouse or key events during earily startup.
cc6d76e3 - Don't try to manually build url if parent is not set.
85052379 - Fix crash when canceling by using only one event loop in ProgressDialog.
d151f151 - Don't append to already complete url.
d3cb2def - Fix manual url building in FileAccess::setFromUdsEntry - scheme should not change now.
Bug 405918 - Fix craft install instructions for windows
Bug 411586 - Fix crash in OptionDialog::slotApply()
Bug 407745 - Fix crash in MergeResultWindow::slotUpdateAvailabilities
Bug 407894,399070 - Fixed redraw for horizonal scrolling.
Version 1.8 - 2019-03-22
===========================
-Don't enable "Choose C for Everthing" on two way merge.
......
Building KDiff3 requires the fallowing minimium versions:
1)Qt 5.6 or later
2)KF5 5.14+
2)KF5 5.27+
3)CMake 3.1
4)ECM 1.8
Support compilers:
......@@ -33,14 +33,30 @@ Run the fallowing.
1)Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
2)iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/KDE/craft/master/setup/install_craft.ps1'))
You may also have exempt your craft directory from virus scans as these can interefer with the build process.
You may also have to exempt your craft directory from virus scans as these can interefer with the build process.
1)cd to your craft root
Run:
2)C:\CraftRoot\craft\craftenv.ps1
3)craft --package kdiff3
3)craft png2ico
4)craft kdiff3
If you what to build 1.8x than use:
4) craft --target 1.8 kdiff3
This will be a time consuming process on first run as craft will have download all dependencies.
KDiff3 does not require special configuration for craft.
Otherwise craft will use master which is the developement branch and therefor more likely to experiance breakage.
At this point you can run kdiff3 itself via the following:
cb kdiff3
bin/kdiff3
If you want to create an install package you would run:
5)craft nsis
6)craft --package kdiff3 or craft --target 1.8 --package kdiff3
This will be a time consuming process on first run as craft will have to download all dependencies.
KDiff3 does not require special configuration for craft.
There should be an installer package generated in CraftRoot/tmp
Please contact kde-windows@kde.org before filing a bug report regarding this process.
\ No newline at end of file
......@@ -3,18 +3,20 @@ KDiff3-Readme
Author: Joachim Eibl (joachim.eibl at gmx.de)
Port to KF5/Qt5 by Michael Reeves (reeves.87@gmail.com)
KDiff3-Version: 1.8
KDiff3-Version: 1.8.2
Now requires Qt 5.6 or later and KF5 5.14+. Legacy 0.9.98 and earlier builds are not supported.
Now requires Qt 5.6 or later and KF5 5.27+. Legacy 0.9.98 and earlier builds are not supported.
MacOSX build is untested since port. The Konqueror specific plugin is not ported and no longer maintained.
This plugin would only apply to KDE before 4.6. Support as been removed from main CMakeLists.txt.
As of 1/13/17 cmake 3.1+ is the targeted cmake version.
This plugin would only apply to KDE before 4.6. As of 1/13/17 cmake 3.1+ is the targeted cmake version.
cmake is now the only build system supported. KF5/Qt5 was big jump. A lot changed besides just the API.
I am not against a Qt5-only build variant but see no reason to maintain two separate build systems.
At present KF5 is my focus.
The current reprository is at https://invent.kde.org/kde/kdiff3
Bugs can be reported at https://bugs.kde.org
The original pre KF5/Qt5 Readme follows old build instructions have been removed to avoid confusion:
......
......@@ -34,169 +34,6 @@
#include <map>
#include <vector>
#ifdef UNICODE
static void parseString( const std::wstring& s, size_t& i /*pos*/, std::wstring& r /*result*/ )
{
size_t size = s.size();
++i; // Skip initial '"'
for( ; i<size; ++i )
{
if ( s[i]=='"' )
{
++i;
break;
}
else if ( s[i]==L'\\' && i+1<size )
{
++i;
switch( s[i] ) {
case L'n': r+=L'\n'; break;
case L'r': r+=L'\r'; break;
case L'\\': r+=L'\\'; break;
case L'"': r+=L'"'; break;
case L't': r+=L'\t'; break;
default: r+=L'\\'; r+=s[i]; break;
}
}
else
r+=s[i];
}
}
static std::map< std::wstring, std::wstring > s_translationMap;
static tstring s_translationFileName;
void readTranslationFile()
{
s_translationMap.clear();
FILE* pFile = _tfopen( s_translationFileName.c_str(), TEXT("rb") );
if ( pFile )
{
MESSAGELOG( TEXT( "Reading translations: " ) + s_translationFileName );
std::vector<char> buffer;
try {
if ( fseek(pFile, 0, SEEK_END)==0 )
{
size_t length = ftell(pFile); // Get the file length
buffer.resize(length);
fseek(pFile, 0, SEEK_SET );
fread(&buffer[0], 1, length, pFile );
}
}
catch(...)
{
}
fclose(pFile);
if (buffer.size()>0)
{
size_t bufferSize = buffer.size();
int offset = 0;
if ( buffer[0]=='\xEF' && buffer[1]=='\xBB' && buffer[2]=='\xBF' )
{
offset += 3;
bufferSize -= 3;
}
size_t sLength = MultiByteToWideChar(CP_UTF8,0,&buffer[offset], (int)bufferSize, 0, 0 );
std::wstring s( sLength, L' ' );
MultiByteToWideChar(CP_UTF8,0,&buffer[offset], (int)bufferSize, &s[0], (int)s.size() );
// Now analyze the file and extract translation strings
std::wstring msgid;
std::wstring msgstr;
msgid.reserve( 1000 );
msgstr.reserve( 1000 );
bool bExpectingId = true;
for( size_t i=0; i<sLength; ++i )
{
wchar_t c = s[i];
if( c == L'\n' || c == L'\r' || c==L' ' || c==L'\t' )
continue;
else if ( s[i]==L'#' ) // Comment
while( s[i]!='\n' && s[i]!=L'\r' && i<sLength )
++i;
else if ( s[i]==L'"' )
{
if ( bExpectingId ) parseString(s,i,msgid);
else parseString(s,i,msgstr);
}
else if ( sLength-i>5 && wcsncmp( &s[i], L"msgid", 5 )==0 )
{
if ( !msgid.empty() && !msgstr.empty() )
{
s_translationMap[msgid] = msgstr;
}
bExpectingId = true;
msgid.clear();
i+=4;
}
else if ( sLength-i>6 && wcsncmp( &s[i], L"msgstr", 6 )==0 )
{
bExpectingId = false;
msgstr.clear();
i+=5;
}
else
{
// Unexpected ?
}
}
}
}
else
{
ERRORLOG( TEXT( "Reading translations failed: " ) + s_translationFileName );
}
}
static tstring getTranslation( const tstring& fallback )
{
std::map< std::wstring, std::wstring >::iterator i = s_translationMap.find( fallback );
if (i!=s_translationMap.end())
return i->second;
return fallback;
}
#else
static tstring getTranslation( const tstring& fallback )
{
return fallback;
}
#endif
static void replaceArgs( tstring& s, const tstring& r1, const tstring& r2=TEXT(""), const tstring& r3=TEXT("") )
{
tstring arg1 = TEXT("%1");
size_t pos1 = s.find( arg1 );
tstring arg2 = TEXT("%2");
size_t pos2 = s.find( arg2 );
tstring arg3 = TEXT("%3");
size_t pos3 = s.find( arg3 );
if ( pos1 != size_t(-1) )
{
s.replace( pos1, arg1.length(), r1 );
if ( pos2 != size_t(-1) && pos1<pos2 )
pos2 += r1.length() - arg1.length();
if ( pos3 != size_t(-1) && pos1<pos3 )
pos3 += r1.length() - arg1.length();
}
if ( pos2 != size_t(-1) )
{
s.replace( pos2, arg2.length(), r2 );
if ( pos3 != size_t(-1) && pos2<pos3 )
pos3 += r2.length() - arg2.length();
}
if ( pos3 != size_t(-1) )
{
s.replace( pos3, arg3.length(), r3 );
}
}
DIFF_EXT::DIFF_EXT()
: m_nrOfSelectedFiles(0), _ref_count(0L),
m_recentFiles( SERVER::instance()->recent_files() )
......@@ -265,17 +102,6 @@ DIFF_EXT::Initialize(LPCITEMIDLIST /*folder not used*/, IDataObject* data, HKEY
{
LOG();
#ifdef UNICODE
tstring installDir = SERVER::instance()->getRegistryKeyString( TEXT(""), TEXT("InstallDir") );
tstring language = SERVER::instance()->getRegistryKeyString( TEXT(""), TEXT("Language") );
tstring translationFileName = installDir + TEXT("\\translations\\diff_ext_") + language + TEXT(".po");
if ( s_translationFileName != translationFileName )
{
s_translationFileName = translationFileName;
readTranslationFile();
}
#endif
FORMATETC format = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium;
medium.tymed = TYMED_HGLOBAL;
......@@ -288,8 +114,6 @@ DIFF_EXT::Initialize(LPCITEMIDLIST /*folder not used*/, IDataObject* data, HKEY
TCHAR tmp[MAX_PATH];
//initialize_language();
if (m_nrOfSelectedFiles >= 1 && m_nrOfSelectedFiles <= 3)
{
DragQueryFile(drop, 0, tmp, MAX_PATH);
......@@ -388,15 +212,17 @@ DIFF_EXT::QueryContextMenu(HMENU menu, UINT position, UINT first_cmd, UINT /*las
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 );
......@@ -405,11 +231,10 @@ DIFF_EXT::QueryContextMenu(HMENU menu, UINT position, UINT first_cmd, UINT /*las
// tstring firstFileName = cut_to_length( m_recentFiles.front() );
// tstring secondFileName = cut_to_length( *(++m_recentFiles.begin()) );
//}
m_id_Merge3 = insertMenuItemHelper( subMenu, id++, pos2++, i18n("3-way merge with base"),
m_id_Merge3 = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("3-way merge with base")),
nrOfRecentFiles >=2 ? MFS_ENABLED : MFS_DISABLED );
menuString = i18n("Save '%1' for later");
replaceArgs( menuString, _file_name1 );
menuString = fromQString(i18n("Save '%1' for later", toQString(_file_name1)));
m_id_DiffLater = insertMenuItemHelper( subMenu, id++, pos2++, menuString );
HMENU file_list = CreateMenu();
......@@ -423,25 +248,25 @@ DIFF_EXT::QueryContextMenu(HMENU menu, UINT position, UINT first_cmd, UINT /*las
++n;
}
insertMenuItemHelper( subMenu, id++, pos2++, i18n("Compare with ..."),
insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("Compare with ...")),
nrOfRecentFiles > 0 ? MFS_ENABLED : MFS_DISABLED, file_list );
m_id_ClearList = insertMenuItemHelper( subMenu, id++, pos2++, i18n("Clear list"), nrOfRecentFiles >=1 ? MFS_ENABLED : MFS_DISABLED );
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++, i18n("Compare") );
m_id_Diff = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("Compare")) );
}
else if ( m_nrOfSelectedFiles == 3 )
{
m_id_Diff3 = insertMenuItemHelper( subMenu, id++, pos2++, i18n("3 way comparison") );
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++, i18n("About Diff-Ext ...") );
m_id_About = insertMenuItemHelper( subMenu, id++, pos2++, fromQString(i18n("About Diff-Ext ...")) );
insertMenuItemHelper( menu, id++, position++, TEXT("KDiff3"), MFS_ENABLED, subMenu );
......@@ -512,14 +337,13 @@ DIFF_EXT::InvokeCommand(LPCMINVOKECOMMANDINFO ici)
else if(id == m_id_About)
{
LOG();
std::wstring sBits = i18n("(32 Bit)");
QString sBits = i18n("(32 Bit)");
if (sizeof(void*)==8)
sBits = i18n("(64 Bit)");
MessageBox( _hwnd, (i18n("Diff-Ext Copyright (c) 2003-2006, Sergey Zorin. All rights reserved.\n")
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()
, (i18n("About Diff-Ext for KDiff3 ")+sBits).c_str(), MB_OK );
+ 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
{
......@@ -545,7 +369,7 @@ DIFF_EXT::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT*, LPSTR pszName, UI
HRESULT ret = NOERROR;
if(uFlags == GCS_HELPTEXT) {
tstring helpString;
QString helpString;
if( idCmd == m_id_Diff )
{
helpString = i18n("Compare selected files");
......@@ -554,14 +378,12 @@ DIFF_EXT::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT*, LPSTR pszName, UI
{
if(!m_recentFiles.empty())
{
helpString = i18n("Compare '%1' with '%2'");
replaceArgs( helpString, _file_name1, 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");
replaceArgs( helpString, _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()))
{
......@@ -574,12 +396,11 @@ DIFF_EXT::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT*, LPSTR pszName, UI
if ( i!=m_recentFiles.end() )
{
helpString = i18n("Compare '%1' with '%2'");
replaceArgs( helpString, _file_name1, *i );
helpString = i18n("Compare '%1' with '%2'", toQString(_file_name1), toQString(*i));
}
}
}
lstrcpyn( (LPTSTR)pszName, helpString.c_str(), cchMax );
lstrcpyn( (LPTSTR)pszName, fromQString(helpString).c_str(), cchMax );
}
else
{
......@@ -616,10 +437,10 @@ DIFF_EXT::diff( const tstring& arguments )
if (bError)
{
tstring message = i18n("Could not start KDiff3. Please rerun KDiff3 installation.");
message += TEXT("\n") + i18n("Command") + TEXT(": ") + command;
message += TEXT("\n") + i18n("CommandLine") + TEXT(": ") + commandLine;
MessageBox(_hwnd, message.c_str(), i18n("Diff-Ext For KDiff3").c_str(), MB_OK);
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);
}
}
......
......@@ -58,7 +58,6 @@ class DIFF_EXT : public IContextMenu, IShellExtInit {
void diff( const tstring& arguments );
void diff_with(unsigned int num, bool bMerge);
tstring cut_to_length(const tstring&, size_t length = 64);
void initialize_language();
private:
UINT m_nrOfSelectedFiles;
......
/*
* Copyright (c) 2003, 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.
*
*/
#ifndef __string_h__
#define __string_h__
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <stdlib.h>
class STRING;
inline STRING operator+( const STRING& s1, const STRING& s2);
class STRING {
public:
static const int begin = 0;
static const int end = -1;
public:
STRING(const STRING& s) {
_str = new TCHAR[s.length()+1];
lstrcpy(_str, s);
}
STRING(const TCHAR* str = TEXT("")) {
_str = new TCHAR[lstrlen(str)+1];
lstrcpy(_str, str);
}
~STRING() {
delete[] _str;
}
void resize( size_t newLength )
{
size_t oldLength = length();
if ( newLength < oldLength ) {
_str[newLength] = 0; // Just truncate the string
} else if( newLength>oldLength) {
TCHAR* p = new TCHAR[ newLength + 1 ];
lstrcpy(p, _str);
for( size_t i=oldLength; i<newLength; ++i)
p[i]=TEXT(' ');
p[newLength]=0;
}
}
STRING& operator=(const STRING& s) {
delete[] _str;
_str = new TCHAR[s.length()+1];
lstrcpy(_str, s);
return *this;
}
operator TCHAR*() {
return _str;
}
operator const TCHAR*() const {
return _str;
}
const TCHAR* c_str() const {
return _str;
}
size_t length() const {
return _tcslen(_str);
}
// Also returns the length. Behaviour like std::basic_string::size.
// See also sizeInBytes() below.
size_t size() const {
return length();
}
// String length in bytes. May differ from length() for Unicode or MBCS
size_t sizeInBytes() const {
return length()*sizeof(TCHAR);
}
bool empty() const
{
return length()==0;
}
STRING substr(size_t from, size_t len=size_t(-1)) const {
STRING tmp;
size_t to = len==size_t(-1) ? length() : from + len;
if(from < to && (to <= length())) {
size_t new_len = to - from + 1;
TCHAR* new_str = new TCHAR[new_len+1];
lstrcpyn(new_str, &_str[from], int(new_len) );
new_str[new_len] = 0;
tmp = new_str;
delete[] new_str;
}
return tmp;
}
STRING& replace( size_t pos, size_t num, const STRING& s )
{
*this = substr( 0, pos ) + s + substr( pos+num );
return *this;
}
bool operator ==(const STRING& s) const {
return (lstrcmp(_str, s) == 0);
}
size_t find(const STRING& s) const
{
const TCHAR* p = _tcsstr( _str, s._str );
if (p)
return p - _str;
else
return size_t(-1);
}
STRING& operator +=(const STRING& s) {
TCHAR* str = new TCHAR[lstrlen(_str)+s.length()+1];
lstrcpy(str, _str);
lstrcat(str, s);
delete[] _str;
_str = str;
return *this;
}
private:
TCHAR* _str;
};
inline STRING operator+( const STRING& s1, const STRING& s2) {
STRING tmp(s1);
tmp+=s2;
return tmp;
}
#endif // __string_h__
......@@ -41,10 +41,6 @@
#include <initguid.h>
#include <KLocalizedString>
//#include <log/log.h>
//#include <log/log_message.h>
//#include <log/file_sink.h>
//#include <debug/trace.h>
#include "server.h"
#include "class_factory.h"
......
......@@ -32,8 +32,16 @@
#ifdef UNICODE
typedef std::wstring tstring;
#define toQString(s) QString::fromStdWString(s)
#define fromQString(s) (s).toStdWString()
#else
typedef std::string tstring;
#define toQString(s) { QString::fromStdString(s);}
#define fromQString(s) { (s).toStdString();}
#endif
#define MESSAGELOG( msg ) SERVER::logMessage( __FUNCTION__, __FILE__, __LINE__, msg )
......@@ -53,34 +61,34 @@ class SERVER {
public:
static SERVER* instance();
void initLogging();
public:
virtual ~SERVER();
tstring getRegistryKeyString( const tstring& subKey, const tstring& value );
HINSTANCE handle() const;
HRESULT do_register();
HRESULT do_unregister();
void lock();
void release();
ULONG reference_count() const {
return _reference_count;
}
std::list< tstring >& recent_files();
void save_history() const;
static void logMessage( const char* function, const char* file, int line, const tstring& msg );
private:
SERVER();
SERVER(const SERVER&) {}
private:
LONG _reference_count;
std::list<tstring>* m_pRecentFiles;
......
......@@ -54,7 +54,7 @@ Please respect the format of the date (YYYY-MM-DD) and of the version
Do NOT change these in the translation. -->
<date>2019-02-22</date>
<releaseinfo>1.08.00</releaseinfo>
<releaseinfo>1.08.02</releaseinfo>
<abstract>
......
......@@ -49,7 +49,7 @@ private Q_SLOTS:
private:
QList<QUrl> m_list;
QWidget* m_pParentWidget;
QWidget* m_pParentWidget = nullptr;
//KFileItemListProperties m_fileItemInfos;
};
#endif
......@@ -11,18 +11,24 @@
"Name[de]": "Dateien und Ordner vergleichen und zusammenführen mit KDiff3",
"Name[en_GB]": "Compare/Merge Files/Directories with KDiff3",
"Name[es]": "Comparar o fusionar archivos o directorios con KDiff3",
"Name[eu]": "Alderatu/bateratu fitxategiak/direktorioak KDiff3 erabiliz",
"Name[fi]": "Vertaa ja yhdistä tiedostoja ja kansioita KDiff3:lla",
"Name[fr]": "Comparaison et fusion de fichiers ou de dossiers à l'aide de « KDiff3 »",
"Name[gl]": "Comparar ou mesturar ficheiros ou directorios con KDiff3",
"Name[ia]": "Compara/Fusiona Files/Directorios con KDiff3",
"Name[it]": "Confronta e fonde i file o le cartelle con KDiff3",
"Name[ko]": "KDiff3으로 파일과 디렉터리를 비교하거나 병합",
"Name[nl]": "Vergelijk/Voeg samen bestanden/mappen met KDiff3",
"Name[nn]": "Samanlikna/flett filer/mapper med KDiff3",
"Name[pl]": "Porównuj/Scalaj pliki/katalogi z KDiff3",
"Name[pt]": "Comparar/Reunir os Ficheiros/Pastas com o KDiff3",
"Name[pt_BR]": "Comparar/Mesclar arquivos/pastas com o KDiff3",
"Name[ru]": "Сравнение и слияние файлов и каталогов с использованием приложения KDiff3",
"Name[sk]": "Porovnať/zlúčiť súbory/adresáre s KDiff3",
"Name[sv]": "Jämför/Sammanfoga filer/kataloger med KDiff3",
"Name[uk]": "Порівняння та об'єднання файлів та каталогів за допомогою KDiff3",
"Name[x-test]": "xxCompare/Merge Files/Directories with KDiff3xx",
"Name[zh_CN]": "使用KDiff3比较/合并文件或文件夹",
"Name[zh_TW]": "使用 KDiff3 比較/合併檔案或資料夾",
"ServiceTypes": [
"KFileItemAction/Plugin"
......
......@@ -31,6 +31,10 @@ set(kdiff3part_PART_SRCS
Logging.cpp
FileNameLineEdit.cpp )
ki18n_wrap_ui(kdiff3part_PART_SRCS
scroller.ui
)
add_library(kdiff3part MODULE ${kdiff3part_PART_SRCS})
set_target_properties(kdiff3part PROPERTIES DEFINE_SYMBOL KDIFF3_PART)
......@@ -49,12 +53,33 @@ set(kdiff3_SRCS
${kdiff3part_PART_SRCS}
)
#cann't use add_subdirectory because it changes the scope.
include(icons/CMakeLists.txt)
add_executable(kdiff3 ${kdiff3_SRCS})
target_link_libraries(kdiff3 KF5::ConfigCore KF5::ConfigGui KF5::Parts KF5::Crash ${KDiff3_LIBRARIES} )
target_compile_features(kdiff3 PRIVATE ${needed_features})
install(TARGETS kdiff3 ${INSTALL_TARGETS_DEFAULT_ARGS})
# See https://cmake.org/cmake/help/v3.15/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.html
if(APPLE)
set_property(
TARGET kdiff3
PROPERTY MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in
)
# These are substituted by CMake into plist.in.
set(MACOSX_BUNDLE_DISPLAY_NAME "KDiff3")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.KDiff3")
set(MACOSX_BUNDLE_BUNDLE_NAME "KDiff3")
set(MACOSX_BUNDLE_DISPLAY_NAME "KDiff3")
set(MACOSX_BUNDLE_INFO_STRING "KDiff3 - Diff/Patch Frontend")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "KDiff3 ${KDIFF3_VERSION}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDIFF3_VERSION_MAJOR}.${KDIFF3_VERSION_MINOR}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${KDIFF3_VERSION}")
set(MACOSX_BUNDLE_COPYRIGHT "2003-2020 The KDiff3 Authors")
endif()
install(TARGETS kdiff3 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
......@@ -66,4 +91,3 @@ install( FILES kdiff3_shell.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kdiff3 )
install( PROGRAMS org.kde.kdiff3.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES org.kde.kdiff3.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
add_subdirectory(icons)
......@@ -49,6 +49,8 @@ class DirectoryInfo
return m_dirC.isValid() ? m_dirC : m_dirB;
}
inline bool allowSyncMode() { return !m_dirC.isValid() && !m_dirDest.isValid(); }
inline bool listDirA(const Options& options)
{
return m_dirA.listDir(&m_dirListA,
......
......@@ -20,3 +20,4 @@
#include "Logging.h"
Q_LOGGING_CATEGORY(kdeMain, "org.kde.kdiff3")
Q_LOGGING_CATEGORY(kdiffFileAccess, "org.kde.kdiff3.fileAccess")
......@@ -22,4 +22,5 @@
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(kdeMain)
Q_DECLARE_LOGGING_CATEGORY(kdiffFileAccess)
#endif // !LOGGING_H
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>LSMultipleInstancesProhibited</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>LSItemContentTypes</key>
<array>
<string>*</string>
</array>
<key>CFBundleTypeName</key>
<string>NSStringPboardType</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
</dict>
</plist>
......@@ -18,18 +18,17 @@
* along with KDiff3. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPTIONITEMS_H
#define OPTIONITEMS_H
#include "common.h"
#include <QString>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include <QTextCodec>
#include <QLineEdit>
#include <KLocalizedString>
......@@ -50,18 +49,21 @@ class OptionItemBase
virtual void read(ValueMap*) = 0;
void doPreserve()
{
if(!m_bPreserved) {
if(!m_bPreserved)
{
m_bPreserved = true;
preserve();
}
}
void doUnpreserve()
{
if(m_bPreserved) {
if(m_bPreserved)
{
unpreserve();
}
}
QString getSaveName() { return m_saveName; }
protected:
virtual void preserve() = 0;
virtual void unpreserve() = 0;
......@@ -87,12 +89,14 @@ class Option : public OptionItemBase
explicit Option(const T& defaultVal, const QString& saveName, T* pVar)
: Option<T>(pVar, defaultVal, saveName)
{}
{
}
explicit Option(T* pVar, const T& defaultValue, const QString& saveName)
: OptionItemBase(saveName)
{
m_pVar = pVar;
m_defaultVal = defaultValue;
m_pVar = pVar;
m_defaultVal = defaultValue;
}
void setToDefault() override {};
......@@ -100,24 +104,25 @@ class Option : public OptionItemBase
const T& getDefault() const { return m_defaultVal; };
const T getCurrent() const { return *m_pVar; };
virtual void setCurrent(const T inValue) { *m_pVar= inValue; }
virtual void setCurrent(const T inValue) { *m_pVar = inValue; }
void apply() override {};
virtual void apply(const T& inValue) { *m_pVar = inValue; }
void write(ValueMap* config) override { config->writeEntry(m_saveName, *m_pVar); }
void read(ValueMap* config) override { *m_pVar = config->readEntry(m_saveName, m_defaultVal); }
protected:
void preserve() override { m_preservedVal = *m_pVar; }
void unpreserve() override { *m_pVar = m_preservedVal; }
T* m_pVar;
T m_preservedVal;
T m_defaultVal;
private:
Q_DISABLE_COPY(Option)
Q_DISABLE_COPY(Option)
};
template <class T>
class OptionNum : public Option<T>
{
......@@ -126,19 +131,15 @@ class OptionNum : public Option<T>
explicit OptionNum(T* pVar, const QString& saveName)
: Option<T>(pVar, saveName)
{
stringValue = QLocale().toString(*pVar);
}
explicit OptionNum(T* pVar, const T& defaultValue, const QString& saveName)
: Option<T>(pVar, defaultValue, saveName)
{
stringValue = QLocale().toString(*pVar);
}
void setCurrent(const T inValue) override
{
//setNum does not use locale formatting instead it always use QLocale::C.
stringValue = QLocale().toString(inValue);
Option<T>::setCurrent(inValue);
}
......@@ -147,14 +148,13 @@ class OptionNum : public Option<T>
//QString::setNum does not use locale formatting instead it always use QLocale::C.
return QLocale().toString(inValue);
}
const QString& getString() const
const QString getString() const
{
return stringValue;
//QString::setNum does not use locale formatting instead it always use QLocale::C.
return QLocale().toString(Option<T>::getCurrent());
}
private:
QString stringValue;
Q_DISABLE_COPY(OptionNum)
};
......
......@@ -66,6 +66,8 @@ void SourceData::reset()
m_tempFile.remove();
m_tempInputFileName = "";
}
mErrors.clear();
}
void SourceData::setFilename(const QString& filename)
......@@ -125,6 +127,8 @@ void SourceData::setFileAccess(const FileAccess& fileAccess)
m_tempFile.remove();
m_tempInputFileName = "";
}
mErrors.clear();
}
void SourceData::setEncoding(QTextCodec* pEncoding)
{
......@@ -133,8 +137,7 @@ void SourceData::setEncoding(QTextCodec* pEncoding)
QStringList SourceData::setData(const QString& data)
{
QStringList errors;
mErrors.clear();
// Create a temp file for preprocessing:
if(m_tempInputFileName.isEmpty())
{
......@@ -147,7 +150,7 @@ QStringList SourceData::setData(const QString& data)
bool bSuccess = f.writeFile(ba.constData(), ba.length());
if(!bSuccess)
{
errors.append(i18n("Writing clipboard data to temp file failed."));
mErrors.append(i18n("Writing clipboard data to temp file failed."));
}
else
{
......@@ -155,7 +158,7 @@ QStringList SourceData::setData(const QString& data)
m_fileAccess = FileAccess(""); // Effect: m_fileAccess.isValid() is false
}
return errors;
return mErrors;
}
const LineData* SourceData::getLineDataForDiff() const
......@@ -193,7 +196,7 @@ const QString& SourceData::getText() const
bool SourceData::isText()
{
return m_normalData.isText();
return m_normalData.isText() || m_normalData.isEmpty();
}
bool SourceData::isIncompleteConversion()
......@@ -215,12 +218,15 @@ bool SourceData::isBinaryEqualWith(const SourceData& other) const
void SourceData::FileData::reset()
{
delete[](char*) m_pBuf;
m_pBuf = nullptr;
if(m_pBuf != nullptr)
{
delete[](char*) m_pBuf;
m_pBuf = nullptr;
}
m_v.clear();
m_size = 0;
m_vSize = 0;
m_bIsText = true;
m_bIsText = false;
m_bIncompleteConversion = false;
m_eLineEndStyle = eLineEndStyleUndefined;
}
......@@ -249,6 +255,14 @@ bool SourceData::FileData::readFile(FileAccess& file)
m_pBuf = nullptr;
m_size = 0;
}
else
{
//null terminate buffer
pBuf[m_size + 1] = 0;
pBuf[m_size + 2] = 0;
pBuf[m_size + 3] = 0;
pBuf[m_size + 4] = 0;
}
return bSuccess;
}
......@@ -320,7 +334,7 @@ QTextCodec* SourceData::detectEncoding(const QString& fileName, QTextCodec* pFal
return pFallbackCodec;
}
QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode)
const QStringList& SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode)
{
m_pEncoding = pEncoding;
QTemporaryFile fileIn1, fileOut1;
......@@ -328,12 +342,11 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
QString fileNameOut1;
QString fileNameIn2;
QString fileNameOut2;
QStringList errors;
if(m_fileAccess.isValid() && !m_fileAccess.isNormal())
{
errors.append(i18n("%1 is not a normal file.", m_fileAccess.prettyAbsPath()));
return errors;
mErrors.append(i18n("%1 is not a normal file.", m_fileAccess.prettyAbsPath()));
return mErrors;
}
bool bTempFileFromClipboard = !m_fileAccess.isValid();
......@@ -382,8 +395,8 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
// No preprocessing: Read the file directly:
if(!m_normalData.readFile(faIn))
{
errors.append(faIn.getStatusText());
return errors;
mErrors.append(faIn.getStatusText());
return mErrors;
}
}
else
......@@ -423,12 +436,12 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
{
if(!m_normalData.readFile(faIn))
{
errors.append(faIn.getStatusText());
errors.append(i18n(" Temp file is: %1", fileNameIn1));
return errors;
mErrors.append(faIn.getStatusText());
mErrors.append(i18n(" Temp file is: %1", fileNameIn1));
return mErrors;
}
//Don't fail the preprocessor command if the file cann't be read.
errors.append(
mErrors.append(
i18n("Preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe preprocessing command will be disabled now.", ppCmd) +
errorReason);
......@@ -440,12 +453,12 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
if(!m_normalData.preprocess(m_pOptions->m_bPreserveCarriageReturn, pEncoding1))
{
errors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return errors;
mErrors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return mErrors;
}
//exit early for non text data further processing assumes a text file as input
if(!m_normalData.isText())
return errors;
return mErrors;
// LineMatching Preprocessor
if(!m_pOptions->m_LineMatchingPreProcessorCmd.isEmpty())
......@@ -483,15 +496,15 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
bool bSuccess = errorReason.isEmpty() && m_lmppData.readFile(fileNameOut2);
if(FileAccess(fileNameIn2).size() > 0 && (!bSuccess || m_lmppData.m_size == 0))
{
errors.append(
mErrors.append(
i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n %1"
"\n\nThe line-matching-preprocessing command will be disabled now.", ppCmd) +
errorReason);
m_pOptions->m_LineMatchingPreProcessorCmd = "";
if(!m_lmppData.readFile(fileNameIn2))
{
errors.append(i18n("Failed to read file: %1", fileNameIn2));
return errors;
mErrors.append(i18n("Failed to read file: %1", fileNameIn2));
return mErrors;
}
}
}
......@@ -501,11 +514,16 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
m_lmppData.copyBufFrom(m_normalData);
}
}
else
{
//exit early for non-existant files
return mErrors;
}
if(!m_lmppData.preprocess(false, pEncoding2))
{
errors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return errors;
mErrors.append(i18n("File %1 too large to process. Skipping.", fileNameIn1));
return mErrors;
}
Q_ASSERT(m_lmppData.isText());
......@@ -533,7 +551,7 @@ QStringList SourceData::readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetec
}
}
return errors;
return mErrors;
}
/** Prepare the linedata vector for every input line.*/
......@@ -597,6 +615,9 @@ bool SourceData::FileData::preprocess(bool bPreserveCR, QTextCodec* pEncoding)
{
if(i >= ucSize || p[i] == '\n')
{
if(lines >= INT_MAX - 5)
return false;
++lines;
}
if(p[i].isNull())
......
......@@ -51,7 +51,7 @@ class SourceData
bool isValid(); // Either no file is specified or reading was successful
// Returns a list of error messages if anything went wrong
QStringList readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode);
const QStringList& readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode);
bool saveNormalDataAs(const QString& fileName);
bool isBinaryEqualWith(const SourceData& other) const;
......@@ -61,6 +61,7 @@ class SourceData
QTextCodec* getEncoding() const { return m_pEncoding; }
e_LineEndStyle getLineEndStyle() const { return m_normalData.m_eLineEndStyle; }
const QStringList& getErrors() { return mErrors; }
private:
bool convertFileEncoding(const QString& fileNameIn, QTextCodec* pCodecIn,
const QString& fileNameOut, QTextCodec* pCodecOut);
......@@ -76,6 +77,8 @@ class SourceData
QString m_tempInputFileName;
QTemporaryFile m_tempFile; //Created from clipboard content.
QStringList mErrors;
class FileData
{
private:
......@@ -111,11 +114,11 @@ class SourceData
bool isEmpty() { return m_size == 0; }
bool isText() { return m_bIsText; }
bool isText() { return m_bIsText || isEmpty(); }
};
FileData m_normalData;
FileData m_lmppData;
QTextCodec* m_pEncoding;
QTextCodec* m_pEncoding = nullptr;
};
#endif // !SOURCEDATA_H
/**
* Copyright (C) 2018 Michael Reeves reeves.87@gmail.com
*
*
* 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 <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef UTILS_H
#define UTILS_H
#include <QFontMetrics>
#include <QStringList>
#include <QString>
......@@ -28,6 +29,27 @@ class Utils{
public:
static bool wildcardMultiMatch(const QString& wildcard, const QString& testString, bool bCaseSensitive);
static QString getArguments(QString cmd, QString& program, QStringList& args);
//Where posiable use QTextLayout in place of these functions especially when dealing with non-latin scripts.
inline static int getHorizontalAdvance(const QFontMetrics &metrics, const QString& s, int len = -1)
{
//Warning: The Qt API used here is not accurate for some non-latin characters.
#if QT_VERSION < QT_VERSION_CHECK(5,12,0)
return metrics.width(s, len);
#else
return metrics.horizontalAdvance(s, len);
#endif
}
inline static int getHorizontalAdvance(const QFontMetrics &metrics, const QChar& c)
{
//Warning: The Qt API used here is not accurate for some non-latin characters.
#if QT_VERSION < QT_VERSION_CHECK(5,12,0)
return metrics.width(c);
#else
return metrics.horizontalAdvance(c);
#endif
}
};
#endif
......@@ -15,6 +15,7 @@
#include <QDir>
#include <QTextStream>
#include <qregexp.h>
void CvsIgnoreList::init(FileAccess& dir, const t_DirectoryList* pDirList)
{
......@@ -36,7 +37,7 @@ void CvsIgnoreList::init(FileAccess& dir, const t_DirectoryList* pDirList)
FileAccess file(dir);
file.addPath(".cvsignore");
qint64 size = file.exists() ? file.sizeForReading() : 0;
if(size > 0)
if(size > 0 && size <= (qint64)std::numeric_limits<int>::max())
{
char* buf = new char[size];
if(buf != nullptr)
......@@ -147,7 +148,12 @@ void CvsIgnoreList::addEntry(const QString& pattern)
bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
{
if(m_exactPatterns.indexOf(text) >= 0)
/*
Don't let the compilier create a temporary QRegExp explictly create one to prevent a possiable crash
QString::indexOf and therefor QStringList::indexOf may modify the QRegExp passed to it.
*/
QRegExp regexp(text, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
if(m_exactPatterns.indexOf(regexp) >= 0)
{
return true;
}
......@@ -156,7 +162,7 @@ bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
QStringList::ConstIterator itEnd;
for(it = m_startPatterns.begin(), itEnd = m_startPatterns.end(); it != itEnd; ++it)
{
if(text.startsWith(*it))
if(text.startsWith(*it, bCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive))
{
return true;
}
......@@ -164,7 +170,7 @@ bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive) const
for(it = m_endPatterns.begin(), itEnd = m_endPatterns.end(); it != itEnd; ++it)
{