File indexing completed on 2024-12-01 11:19:44
0001 // clang-format off 0002 /* 0003 * This file is part of KDiff3. 0004 * 0005 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 0006 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 // clang-format on 0010 0011 #include "kdiff3_shell.h" 0012 #include "TypeUtils.h" 0013 #include "version.h" 0014 0015 #include <stdio.h> // for fileno, stderr 0016 #include <stdlib.h> // for exit 0017 0018 #ifndef Q_OS_WIN 0019 #include <unistd.h> 0020 #endif 0021 0022 #include <KAboutData> 0023 #include <KCrash> 0024 #include <KLocalizedString> 0025 #include <KMessageBox> 0026 0027 #include <QApplication> 0028 #include <QCommandLineOption> 0029 #include <QCommandLineParser> 0030 #include <QFile> 0031 #include <QStandardPaths> 0032 #include <QStringList> 0033 #include <QTextStream> 0034 0035 void initialiseCmdLineArgs(QCommandLineParser* cmdLineParser) 0036 { 0037 const QString configFileName = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "kdiff3rc"); 0038 QFile configFile(configFileName); 0039 QString ignorableOptionsLine = "-u;-query;-html;-abort"; 0040 if(configFile.open(QIODevice::ReadOnly)) 0041 { 0042 QTextStream ts(&configFile); 0043 while(!ts.atEnd()) 0044 { 0045 const QString line = ts.readLine(); 0046 if(line.startsWith(u8"IgnorableCmdLineOptions=")) 0047 { 0048 const QtSizeType pos = line.indexOf('='); 0049 if(pos >= 0) 0050 { 0051 ignorableOptionsLine = line.mid(pos + 1); 0052 } 0053 break; 0054 } 0055 } 0056 } 0057 0058 const QStringList ignorableOptions = ignorableOptionsLine.split(';'); 0059 0060 for(QString ignorableOption: ignorableOptions) 0061 { 0062 ignorableOption.remove('-'); 0063 if(!ignorableOption.isEmpty()) 0064 { 0065 if(ignorableOption.length() == 1) 0066 { 0067 cmdLineParser->addOption(QCommandLineOption({ignorableOption, u8"ignore"}, i18n("Ignored. (User defined.)"))); 0068 } 0069 else 0070 { 0071 cmdLineParser->addOption(QCommandLineOption(ignorableOption, i18n("Ignored. (User defined.)"))); 0072 } 0073 } 0074 } 0075 } 0076 0077 qint32 main(qint32 argc, char* argv[]) 0078 { 0079 constexpr QLatin1String appName("kdiff3", sizeof("kdiff3") - 1); 0080 //Syncronize qt HDPI behavoir on all versions/platforms 0081 #if(QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 0082 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 0083 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0084 #endif 0085 QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); 0086 0087 QApplication app(argc, argv); // KAboutData and QCommandLineParser depend on this being setup. 0088 KLocalizedString::setApplicationDomain(appName.data()); 0089 0090 KCrash::initialize(); 0091 0092 const QString i18nName = i18n("KDiff3"); 0093 QString appVersion(KDIFF3_VERSION_STRING); 0094 0095 appVersion += i18nc("Program version info.", " (64 bit)"); 0096 0097 const QString description = i18n("Tool for Comparison and Merge of Files and Folders"); 0098 const QString copyright = i18n("(c) 2002-2014 Joachim Eibl, (c) 2017 Michael Reeves KF5/Qt5 port"); 0099 const QString homePage = QStringLiteral("https://kde.org/applications/development/kdiff3"); 0100 0101 KAboutData aboutData(appName, i18nName, 0102 appVersion, description, KAboutLicense::GPL_V2, copyright, QString(), 0103 homePage); 0104 0105 KAboutData::setApplicationData(aboutData); 0106 0107 /* 0108 The QCommandLineParser is a static scoped unique ptr. This is safe given that. 0109 As the distuctor will not be fired until main exits. 0110 */ 0111 QCommandLineParser* cmdLineParser = KDiff3Shell::getParser().get(); 0112 cmdLineParser->setApplicationDescription(aboutData.shortDescription()); 0113 0114 aboutData.setupCommandLine(cmdLineParser); 0115 0116 initialiseCmdLineArgs(cmdLineParser); 0117 // ignorable command options 0118 cmdLineParser->addOption(QCommandLineOption({u8"m", u8"merge"}, i18n("Merge the input."))); 0119 cmdLineParser->addOption(QCommandLineOption({u8"b", u8"base"}, i18n("Explicit base file. For compatibility with certain tools."), u8"file")); 0120 cmdLineParser->addOption(QCommandLineOption({u8"o", u8"output"}, i18n("Output file. Implies -m. E.g.: -o newfile.txt"), u8"file")); 0121 cmdLineParser->addOption(QCommandLineOption(u8"out", i18n("Output file, again. (For compatibility with certain tools.)"), u8"file")); 0122 #ifdef ENABLE_AUTO 0123 cmdLineParser->addOption(QCommandLineOption(u8"auto", i18n("No GUI if all conflicts are auto-solvable. (Needs -o file)"))); 0124 cmdLineParser->addOption(QCommandLineOption(u8"noauto", i18n("Ignore --auto and always show GUI."))); 0125 #else 0126 cmdLineParser->addOption(QCommandLineOption(u8"noauto", i18n("Ignored."))); 0127 cmdLineParser->addOption(QCommandLineOption(u8"auto", i18n("Ignored."))); 0128 #endif 0129 cmdLineParser->addOption(QCommandLineOption(u8"L1", i18n("Visible name replacement for input file 1 (base)."), u8"alias1")); 0130 cmdLineParser->addOption(QCommandLineOption(u8"L2", i18n("Visible name replacement for input file 2."), u8"alias2")); 0131 cmdLineParser->addOption(QCommandLineOption(u8"L3", i18n("Visible name replacement for input file 3."), u8"alias3")); 0132 cmdLineParser->addOption(QCommandLineOption({u8"L", u8"fname"}, i18n("Alternative visible name replacement. Supply this once for every input."), u8"alias")); 0133 cmdLineParser->addOption(QCommandLineOption(u8"cs", i18n("Override a config setting. Use once for every setting. E.g.: --cs \"AutoAdvance=1\""), u8"string")); 0134 cmdLineParser->addOption(QCommandLineOption(u8"confighelp", i18n("Show list of config settings and current values."))); 0135 cmdLineParser->addOption(QCommandLineOption(u8"config", i18n("Use a different config file."), u8"file")); 0136 0137 // other command options 0138 cmdLineParser->addPositionalArgument(u8"[File1]", i18n("file1 to open (base, if not specified via --base)")); 0139 cmdLineParser->addPositionalArgument(u8"[File2]", i18n("file2 to open")); 0140 cmdLineParser->addPositionalArgument(u8"[File3]", i18n("file3 to open")); 0141 0142 bool isAtty = true; 0143 0144 #ifndef Q_OS_WIN 0145 isAtty = isatty(fileno(stderr)) == 1;//will be true for redirected output as well 0146 #endif 0147 /* 0148 QCommandLineParser::process does what is expected on windows or when running from a commandline. 0149 However, it only accounts for a lack of terminal output on windows. 0150 */ 0151 if(isAtty) 0152 { 0153 cmdLineParser->process(QCoreApplication::arguments()); 0154 } 0155 else 0156 { 0157 /* 0158 There is no terminal connected so don't just exit mysteriously on error. 0159 */ 0160 if(!cmdLineParser->parse(QCoreApplication::arguments())) 0161 { 0162 const QString errorMessage = cmdLineParser->errorText(); 0163 0164 KMessageBox::error(nullptr, "<html><head/><body><h2>" + errorMessage + "</h2><pre>" + i18n("See kdiff3 --help for supported options.") + "</pre></body></html>", aboutData.displayName()); 0165 exit(1); 0166 } 0167 0168 if(cmdLineParser->isSet(QStringLiteral("version"))) 0169 { 0170 KMessageBox::information(nullptr, 0171 aboutData.displayName() + ' ' + aboutData.version(), aboutData.displayName()); 0172 exit(0); 0173 } 0174 if(cmdLineParser->isSet(QStringLiteral("help"))) 0175 { 0176 KMessageBox::information(nullptr, "<html><head/><body><pre>" + cmdLineParser->helpText() + "</pre></body></html>", aboutData.displayName()); 0177 0178 exit(0); 0179 } 0180 } 0181 0182 aboutData.processCommandLine(cmdLineParser); 0183 0184 /* 0185 This short segment is wrapped in a lambda to delay KDiff3Shell construction until 0186 after the main event loop starts. Thus allowing us to avoid std::exit as much as 0187 possiable. Makes for a cleaner exit. 0188 */ 0189 QPointer<KDiff3Shell> p; 0190 QMetaObject::invokeMethod( 0191 qApp, [&p] { 0192 /* 0193 Do not attempt to call show here that will be done later. 0194 This variable exists solely to insure the KDiff3Shell is deleted on exit. 0195 */ 0196 p = new KDiff3Shell(); 0197 }, 0198 Qt::QueuedConnection); 0199 qint32 retVal = QApplication::exec(); 0200 delete p; 0201 return retVal; 0202 }