KompareDiff2

kompareprocess.cpp
1/*
2 SPDX-FileCopyrightText: 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com>
3 SPDX-FileCopyrightText: 2001-2003 John Firebaugh <jfirebaugh@kde.org>
4 SPDX-FileCopyrightText: 2007-2008 Kevin Kofler <kevin.kofler@chello.at>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "kompareprocess.h"
10
11// lib
12#include "diffsettings.h"
13#include <komparediff2_logging.h>
14// KF
15#include <KIO/Global>
16// Qt
17#include <QDir>
18#include <QStringList>
19#include <QUrl>
20
21namespace
22{
23/// TODO: This should be replaced to QDir::relativeFilePath
24static QString constructRelativePath(const QString &from, const QString &to)
25{
26 QUrl fromURL(from);
27 QUrl toURL(to);
28 QUrl root;
29 int upLevels = 0;
30
31 // Find a common root.
32 root = fromURL;
33 while (root.isValid() && !root.isParentOf(toURL)) {
34 root = KIO::upUrl(root);
35 ++upLevels;
36 }
37
38 if (!root.isValid())
39 return to;
40
41 QString relative;
42 for (; upLevels > 0; --upLevels) {
43 relative += QStringLiteral("../");
44 }
45
46 relative += QString(to).remove(0, root.path().length());
47 return relative;
48}
49}
50
51KompareProcess::KompareProcess(KompareDiff2::DiffSettings *diffSettings,
53 const QString &source,
54 const QString &destination,
55 const QString &dir,
57 : KProcess()
58 , m_diffSettings(diffSettings)
59 , m_diffMode(diffMode)
60 , m_mode(mode)
61{
62 // connect the signal that indicates that the process has exited
63 connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &KompareProcess::slotFinished);
64
65 setEnv(QStringLiteral("LANG"), QStringLiteral("C"));
66
67 // Write command and options
68 if (m_diffMode == KompareDiff2::Default) {
69 writeDefaultCommandLine();
70 } else {
71 writeCommandLine();
72 }
73
74 if (!dir.isEmpty()) {
75 setWorkingDirectory(dir);
76 }
77
78 // Write file names
79 *this << QStringLiteral("--");
80
81 // Add the option for diff to read from stdin(QIODevice::write), and save a pointer to the string
83 *this << QStringLiteral("-");
84 m_customString = source;
85 } else {
86 *this << constructRelativePath(dir, source);
87 }
88
90 *this << QStringLiteral("-");
91 m_customString = destination;
92 } else {
93 *this << constructRelativePath(dir, destination);
94 }
95}
96
97void KompareProcess::writeDefaultCommandLine()
98{
99 if (!m_diffSettings || m_diffSettings->m_diffProgram.isEmpty()) {
100 *this << QStringLiteral("diff") << QStringLiteral("-dr");
101 } else {
102 *this << m_diffSettings->m_diffProgram << QStringLiteral("-dr");
103 }
104
105 *this << QStringLiteral("-U") << QString::number(m_diffSettings->m_linesOfContext);
106}
107
108void KompareProcess::writeCommandLine()
109{
110 // load the executable into the KProcess
111 if (m_diffSettings->m_diffProgram.isEmpty()) {
112 qCDebug(KOMPAREDIFF2_LOG) << "Using the first diff in the path...";
113 *this << QStringLiteral("diff");
114 } else {
115 qCDebug(KOMPAREDIFF2_LOG) << "Using a user specified diff, namely: " << m_diffSettings->m_diffProgram;
116 *this << m_diffSettings->m_diffProgram;
117 }
118
119 switch (m_diffSettings->m_format) {
120 case KompareDiff2::Unified:
121 *this << QStringLiteral("-U") << QString::number(m_diffSettings->m_linesOfContext);
122 break;
123 case KompareDiff2::Context:
124 *this << QStringLiteral("-C") << QString::number(m_diffSettings->m_linesOfContext);
125 break;
126 case KompareDiff2::RCS:
127 *this << QStringLiteral("-n");
128 break;
129 case KompareDiff2::Ed:
130 *this << QStringLiteral("-e");
131 break;
132 case KompareDiff2::SideBySide:
133 *this << QStringLiteral("-y");
134 break;
135 case KompareDiff2::Normal:
136 case KompareDiff2::UnknownFormat:
137 default:
138 break;
139 }
140
141 if (m_diffSettings->m_largeFiles
142// default diff does not have -H on OpenBSD
143// so don't pass this option unless the user overrode the default program
144#if defined(__OpenBSD__)
145 && !m_diffSettings->m_diffProgram.isEmpty()
146#endif
147 ) {
148 *this << QStringLiteral("-H");
149 }
150
151 if (m_diffSettings->m_ignoreWhiteSpace) {
152 *this << QStringLiteral("-b");
153 }
154
155 if (m_diffSettings->m_ignoreAllWhiteSpace) {
156 *this << QStringLiteral("-w");
157 }
158
159 if (m_diffSettings->m_ignoreEmptyLines) {
160 *this << QStringLiteral("-B");
161 }
162
163 if (m_diffSettings->m_ignoreChangesDueToTabExpansion) {
164 *this << QStringLiteral("-E");
165 }
166
167 if (m_diffSettings->m_createSmallerDiff) {
168 *this << QStringLiteral("-d");
169 }
170
171 if (m_diffSettings->m_ignoreChangesInCase) {
172 *this << QStringLiteral("-i");
173 }
174
175 if (m_diffSettings->m_ignoreRegExp && !m_diffSettings->m_ignoreRegExpText.isEmpty()) {
176 *this << QStringLiteral("-I") << m_diffSettings->m_ignoreRegExpText;
177 }
178
179 if (m_diffSettings->m_showCFunctionChange) {
180 *this << QStringLiteral("-p");
181 }
182
183 if (m_diffSettings->m_convertTabsToSpaces) {
184 *this << QStringLiteral("-t");
185 }
186
187 if (m_diffSettings->m_recursive) {
188 *this << QStringLiteral("-r");
189 }
190
191 if (m_diffSettings->m_newFiles) {
192 *this << QStringLiteral("-N");
193 }
194
195// This option is more trouble than it is worth... please do not ever enable it unless you want really weird crashes
196// if ( m_diffSettings->m_allText )
197// {
198// *this << QStringLiteral("-a");
199// }
200
201 if (m_diffSettings->m_excludeFilePattern) {
202 for (const QString &it : std::as_const(m_diffSettings->m_excludeFilePatternList)) {
203 *this << QStringLiteral("-x") << it;
204 }
205 }
206
207 if (m_diffSettings->m_excludeFilesFile && !m_diffSettings->m_excludeFilesFileURL.isEmpty()) {
208 *this << QStringLiteral("-X") << m_diffSettings->m_excludeFilesFileURL;
209 }
210}
211
212KompareProcess::~KompareProcess() = default;
213
214void KompareProcess::setEncoding(const QString &encoding)
215{
216 if (!encoding.compare(QLatin1String("default"), Qt::CaseInsensitive)) {
217 m_textDecoder = QStringDecoder(QStringDecoder::System);
218 m_textEncoder = QStringEncoder(QStringEncoder::System);
219 } else {
220 m_textDecoder = QStringDecoder(encoding.toUtf8().constData());
221 m_textEncoder = QStringEncoder(encoding.toUtf8().constData());
222 if (!m_textDecoder.isValid() || !m_textEncoder.isValid()) {
223 qCDebug(KOMPAREDIFF2_LOG) << "Using locale codec as backup...";
224 m_textDecoder = QStringDecoder(QStringDecoder::System);
225 m_textEncoder = QStringEncoder(QStringEncoder::System);
226 }
227 }
228}
229
230void KompareProcess::start()
231{
232#ifndef NDEBUG
233 QString cmdLine;
235 for (const QString &arg : program)
236 cmdLine += QLatin1Char('\"') + arg + QLatin1String("\" ");
237 qCDebug(KOMPAREDIFF2_LOG) << cmdLine;
238#endif
242
243 // If we have a string to compare against input it now
245 write(m_textEncoder.encode(m_customString));
247}
248
249void KompareProcess::slotFinished(int exitCode, QProcess::ExitStatus exitStatus)
250{
251 // add all output to m_stdout/m_stderr
252 m_textDecoder.resetState();
253 m_stdout = m_textDecoder.decode(readAllStandardOutput());
254 m_textDecoder.resetState();
255 m_stderr = m_textDecoder.decode(readAllStandardError());
256
257 // exit code of 0: no differences
258 // 1: some differences
259 // 2: error but there may be differences !
260 qCDebug(KOMPAREDIFF2_LOG) << "Exited with exit code : " << exitCode;
261 Q_EMIT diffHasFinished(exitStatus == NormalExit && exitCode != 0);
262}
263
264#include "moc_kompareprocess.cpp"
void start()
void setNextOpenMode(QIODevice::OpenMode mode)
QStringList program() const
void setOutputChannelMode(OutputChannelMode mode)
The settings for a diff.
QString m_excludeFilesFileURL
The filename to -X.
QString m_ignoreRegExpText
the RE for -I
QStringList m_excludeFilePatternList
The list of patterns for -x.
KIOCORE_EXPORT QUrl upUrl(const QUrl &url)
KIOCORE_EXPORT QString dir(const QString &fileClass)
DiffMode
DiffMode.
Definition global.h:60
Mode
Mode.
Definition global.h:46
@ ComparingFileString
Compare a source file with a destination string.
Definition global.h:48
@ ComparingStringFile
Compare a source string with a destination file.
Definition global.h:49
const char * constData() const const
qint64 write(const QByteArray &data)
Q_EMITQ_EMIT
void closeWriteChannel()
int exitCode() const const
QProcess::ExitStatus exitStatus() const const
void finished(int exitCode, QProcess::ExitStatus exitStatus)
QByteArray readAllStandardError()
QByteArray readAllStandardOutput()
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool isEmpty() const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QByteArray toUtf8() const const
bool isValid() const const
EncodedData< QByteArrayView > decode(QByteArrayView ba)
DecodedData< QStringView > encode(QStringView in)
CaseInsensitive
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isParentOf(const QUrl &childUrl) const const
bool isValid() const const
QString path(ComponentFormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:13:14 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.