QCommandLineParser: Support ignoring input past a certain option

This change adds a new flag to QCommandLineOption to indicate
that any command line options that follow are to be ignored by
QCommandLineParser. When an option with that flag is parsed,
any subsequent options are immediately skipped, and the parser
will return true, indicating success.

This is motivated by Qt WebEngine's need for being able to pass
through command line options from the host application to
the underlying Chromium. This is done by
using the --webEngineArgs option, which separates the Qt application
options (on the left), and the Chromium ones (on the right).
With this change, this mechanism will no longer clash with
QCommandLineParser's behavior of shutting the app down when
encountering an unknown option.

Change-Id: I31aedb7a18e551def742891623604513a329d7ca
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Kaloyan Chehlarski 2024-08-23 14:24:24 +02:00 committed by David Faure
parent 8a0c86651f
commit 61e91cb281
4 changed files with 29 additions and 3 deletions

View File

@ -389,6 +389,10 @@ void QCommandLineOption::setFlags(Flags flags)
interpreted as short flags even when the parser is in
QCommandLineParser::ParseAsLongOptions mode.
\value IgnoreOptionsAfter [since 6.9] No options beyond this one will be parsed. Useful
for cases where you need to send extra command line arguments to a secondary
application. If a value is provided for this option, it will be ignored.
\sa QCommandLineOption::setFlags(), QCommandLineOption::flags()
*/

View File

@ -19,7 +19,8 @@ class Q_CORE_EXPORT QCommandLineOption
public:
enum Flag {
HiddenFromHelp = 0x1,
ShortOptionStyle = 0x2
ShortOptionStyle = 0x2,
IgnoreOptionsAfter = 0x4,
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@ -653,7 +653,12 @@ bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, cons
if (nameHashIt != nameHash.constEnd()) {
const qsizetype assignPos = argument.indexOf(assignChar);
const NameHash_t::mapped_type optionOffset = *nameHashIt;
const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
const QCommandLineOption &option = commandLineOptionList.at(optionOffset);
if (option.flags() & QCommandLineOption::IgnoreOptionsAfter) {
*argumentIterator = argsEnd;
return true;
}
const bool withValue = !option.valueName().isEmpty();
if (withValue) {
if (assignPos == -1) {
++(*argumentIterator);

View File

@ -59,6 +59,7 @@ private slots:
void testHelpAll_data();
void testHelpAll();
void testVeryLongOptionNames();
void testIgnoringOptions();
};
static char *empty_argv[] = { 0 };
@ -784,6 +785,21 @@ void tst_QCommandLineParser::testVeryLongOptionNames()
#endif // QT_CONFIG(process)
}
void tst_QCommandLineParser::testIgnoringOptions()
{
QCommandLineParser parser;
QCommandLineOption ignoreAfterOption(QStringLiteral("ignoreAfterOption"));
ignoreAfterOption.setFlags(QCommandLineOption::IgnoreOptionsAfter);
ignoreAfterOption.setValueName(QStringLiteral("ignoreAfterValue"));
parser.addOption(ignoreAfterOption);
QCommandLineOption normalOption(QStringLiteral("normalOption"));
parser.addOption(QCommandLineOption(QStringLiteral("normalOption")));
QVERIFY(parser.parse({"executableName", "--normalOption", "--ignoreAfterOption=value", "--badOption", "notAnOption"}));
QVERIFY(parser.isSet(normalOption));
QVERIFY(parser.isSet(ignoreAfterOption)); // The ignore option is not ignored itself
QVERIFY(parser.value(ignoreAfterOption).isEmpty()); // Values passed to the ignore option should be ignored
QVERIFY(!parser.isSet("badOption"));
}
QTEST_APPLESS_MAIN(tst_QCommandLineParser)
#include "tst_qcommandlineparser.moc"