File indexing completed on 2024-04-21 05:44:09
0001 /* 0002 SPDX-FileCopyrightText: 2001-2005,2009 Otto Bruggeman <bruggie@gmail.com> 0003 SPDX-FileCopyrightText: 2001-2003 John Firebaugh <jfirebaugh@kde.org> 0004 SPDX-FileCopyrightText: 2007-2008 Kevin Kofler <kevin.kofler@chello.at> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kompareprocess.h" 0010 0011 // lib 0012 #include "diffsettings.h" 0013 #include <komparediff2_logging.h> 0014 // KF 0015 #include <KIO/Global> 0016 // Qt 0017 #include <QDir> 0018 #include <QStringList> 0019 #include <QTextCodec> 0020 #include <QUrl> 0021 0022 namespace 0023 { 0024 /// TODO: This should be replaced to QDir::relativeFilePath 0025 static QString constructRelativePath(const QString &from, const QString &to) 0026 { 0027 QUrl fromURL(from); 0028 QUrl toURL(to); 0029 QUrl root; 0030 int upLevels = 0; 0031 0032 // Find a common root. 0033 root = fromURL; 0034 while (root.isValid() && !root.isParentOf(toURL)) { 0035 root = KIO::upUrl(root); 0036 ++upLevels; 0037 } 0038 0039 if (!root.isValid()) 0040 return to; 0041 0042 QString relative; 0043 for (; upLevels > 0; --upLevels) { 0044 relative += QStringLiteral("../"); 0045 } 0046 0047 relative += QString(to).remove(0, root.path().length()); 0048 return relative; 0049 } 0050 } 0051 0052 KompareProcess::KompareProcess(KompareDiff2::DiffSettings *diffSettings, 0053 KompareDiff2::DiffMode diffMode, 0054 const QString &source, 0055 const QString &destination, 0056 const QString &dir, 0057 KompareDiff2::Mode mode) 0058 : KProcess() 0059 , m_diffSettings(diffSettings) 0060 , m_diffMode(diffMode) 0061 , m_mode(mode) 0062 { 0063 // connect the signal that indicates that the process has exited 0064 connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &KompareProcess::slotFinished); 0065 0066 setEnv(QStringLiteral("LANG"), QStringLiteral("C")); 0067 0068 // Write command and options 0069 if (m_diffMode == KompareDiff2::Default) { 0070 writeDefaultCommandLine(); 0071 } else { 0072 writeCommandLine(); 0073 } 0074 0075 if (!dir.isEmpty()) { 0076 setWorkingDirectory(dir); 0077 } 0078 0079 // Write file names 0080 *this << QStringLiteral("--"); 0081 0082 // Add the option for diff to read from stdin(QIODevice::write), and save a pointer to the string 0083 if (m_mode == KompareDiff2::ComparingStringFile) { 0084 *this << QStringLiteral("-"); 0085 m_customString = source; 0086 } else { 0087 *this << constructRelativePath(dir, source); 0088 } 0089 0090 if (m_mode == KompareDiff2::ComparingFileString) { 0091 *this << QStringLiteral("-"); 0092 m_customString = destination; 0093 } else { 0094 *this << constructRelativePath(dir, destination); 0095 } 0096 } 0097 0098 void KompareProcess::writeDefaultCommandLine() 0099 { 0100 if (!m_diffSettings || m_diffSettings->m_diffProgram.isEmpty()) { 0101 *this << QStringLiteral("diff") << QStringLiteral("-dr"); 0102 } else { 0103 *this << m_diffSettings->m_diffProgram << QStringLiteral("-dr"); 0104 } 0105 0106 *this << QStringLiteral("-U") << QString::number(m_diffSettings->m_linesOfContext); 0107 } 0108 0109 void KompareProcess::writeCommandLine() 0110 { 0111 // load the executable into the KProcess 0112 if (m_diffSettings->m_diffProgram.isEmpty()) { 0113 qCDebug(KOMPAREDIFF2_LOG) << "Using the first diff in the path..."; 0114 *this << QStringLiteral("diff"); 0115 } else { 0116 qCDebug(KOMPAREDIFF2_LOG) << "Using a user specified diff, namely: " << m_diffSettings->m_diffProgram; 0117 *this << m_diffSettings->m_diffProgram; 0118 } 0119 0120 switch (m_diffSettings->m_format) { 0121 case KompareDiff2::Unified: 0122 *this << QStringLiteral("-U") << QString::number(m_diffSettings->m_linesOfContext); 0123 break; 0124 case KompareDiff2::Context: 0125 *this << QStringLiteral("-C") << QString::number(m_diffSettings->m_linesOfContext); 0126 break; 0127 case KompareDiff2::RCS: 0128 *this << QStringLiteral("-n"); 0129 break; 0130 case KompareDiff2::Ed: 0131 *this << QStringLiteral("-e"); 0132 break; 0133 case KompareDiff2::SideBySide: 0134 *this << QStringLiteral("-y"); 0135 break; 0136 case KompareDiff2::Normal: 0137 case KompareDiff2::UnknownFormat: 0138 default: 0139 break; 0140 } 0141 0142 if (m_diffSettings->m_largeFiles 0143 // default diff does not have -H on OpenBSD 0144 // so don't pass this option unless the user overrode the default program 0145 #if defined(__OpenBSD__) 0146 && !m_diffSettings->m_diffProgram.isEmpty() 0147 #endif 0148 ) { 0149 *this << QStringLiteral("-H"); 0150 } 0151 0152 if (m_diffSettings->m_ignoreWhiteSpace) { 0153 *this << QStringLiteral("-b"); 0154 } 0155 0156 if (m_diffSettings->m_ignoreAllWhiteSpace) { 0157 *this << QStringLiteral("-w"); 0158 } 0159 0160 if (m_diffSettings->m_ignoreEmptyLines) { 0161 *this << QStringLiteral("-B"); 0162 } 0163 0164 if (m_diffSettings->m_ignoreChangesDueToTabExpansion) { 0165 *this << QStringLiteral("-E"); 0166 } 0167 0168 if (m_diffSettings->m_createSmallerDiff) { 0169 *this << QStringLiteral("-d"); 0170 } 0171 0172 if (m_diffSettings->m_ignoreChangesInCase) { 0173 *this << QStringLiteral("-i"); 0174 } 0175 0176 if (m_diffSettings->m_ignoreRegExp && !m_diffSettings->m_ignoreRegExpText.isEmpty()) { 0177 *this << QStringLiteral("-I") << m_diffSettings->m_ignoreRegExpText; 0178 } 0179 0180 if (m_diffSettings->m_showCFunctionChange) { 0181 *this << QStringLiteral("-p"); 0182 } 0183 0184 if (m_diffSettings->m_convertTabsToSpaces) { 0185 *this << QStringLiteral("-t"); 0186 } 0187 0188 if (m_diffSettings->m_recursive) { 0189 *this << QStringLiteral("-r"); 0190 } 0191 0192 if (m_diffSettings->m_newFiles) { 0193 *this << QStringLiteral("-N"); 0194 } 0195 0196 // This option is more trouble than it is worth... please do not ever enable it unless you want really weird crashes 0197 // if ( m_diffSettings->m_allText ) 0198 // { 0199 // *this << QStringLiteral("-a"); 0200 // } 0201 0202 if (m_diffSettings->m_excludeFilePattern) { 0203 for (const QString &it : std::as_const(m_diffSettings->m_excludeFilePatternList)) { 0204 *this << QStringLiteral("-x") << it; 0205 } 0206 } 0207 0208 if (m_diffSettings->m_excludeFilesFile && !m_diffSettings->m_excludeFilesFileURL.isEmpty()) { 0209 *this << QStringLiteral("-X") << m_diffSettings->m_excludeFilesFileURL; 0210 } 0211 } 0212 0213 KompareProcess::~KompareProcess() = default; 0214 0215 void KompareProcess::setEncoding(const QString &encoding) 0216 { 0217 if (!encoding.compare(QLatin1String("default"), Qt::CaseInsensitive)) { 0218 m_codec = QTextCodec::codecForLocale(); 0219 m_textDecoder.reset(m_codec->makeDecoder()); 0220 } else { 0221 m_codec = QTextCodec::codecForName(encoding.toUtf8()); 0222 if (m_codec) 0223 m_textDecoder.reset(m_codec->makeDecoder()); 0224 else { 0225 qCDebug(KOMPAREDIFF2_LOG) << "Using locale codec as backup..."; 0226 m_codec = QTextCodec::codecForLocale(); 0227 m_textDecoder.reset(m_codec->makeDecoder()); 0228 } 0229 } 0230 } 0231 0232 void KompareProcess::start() 0233 { 0234 #ifndef NDEBUG 0235 QString cmdLine; 0236 const QStringList program = KProcess::program(); 0237 for (const QString &arg : program) 0238 cmdLine += QLatin1Char('\"') + arg + QLatin1String("\" "); 0239 qCDebug(KOMPAREDIFF2_LOG) << cmdLine; 0240 #endif 0241 setOutputChannelMode(SeparateChannels); 0242 setNextOpenMode(QIODevice::ReadWrite); 0243 KProcess::start(); 0244 0245 // If we have a string to compare against input it now 0246 if ((m_mode == KompareDiff2::ComparingStringFile) || (m_mode == KompareDiff2::ComparingFileString)) 0247 write(m_codec->fromUnicode(m_customString)); 0248 closeWriteChannel(); 0249 } 0250 0251 void KompareProcess::slotFinished(int exitCode, QProcess::ExitStatus exitStatus) 0252 { 0253 // add all output to m_stdout/m_stderr 0254 if (m_textDecoder) { 0255 m_stdout = m_textDecoder->toUnicode(readAllStandardOutput()); 0256 m_stderr = m_textDecoder->toUnicode(readAllStandardError()); 0257 } else 0258 qCDebug(KOMPAREDIFF2_LOG) << "KompareProcess::slotFinished : No decoder !!!"; 0259 0260 // exit code of 0: no differences 0261 // 1: some differences 0262 // 2: error but there may be differences ! 0263 qCDebug(KOMPAREDIFF2_LOG) << "Exited with exit code : " << exitCode; 0264 Q_EMIT diffHasFinished(exitStatus == NormalExit && exitCode != 0); 0265 } 0266 0267 #include "moc_kompareprocess.cpp"