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