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