KompareDiff2

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

KDE's Doxygen guidelines are available online.