Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcommandlineparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
2// Copyright (C) 2013 David Faure <faure@kde.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
6
7#include <qcoreapplication.h>
8#include <private/qcoreapplication_p.h>
9#include <qhash.h>
10#include <qvarlengtharray.h>
11#include <qlist.h>
12#include <qdebug.h>
13#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
14# include <qt_windows.h>
15#endif
16#include <stdio.h>
17#include <stdlib.h>
18
20
21using namespace Qt::StringLiterals;
22
23extern void Q_CORE_EXPORT qt_call_post_routines();
24
26
28{
29public:
37
38 bool parse(const QStringList &args);
39 void checkParsed(const char *method);
40 QStringList aliases(const QString &name) const;
41 QString helpText(bool includeQtOptions) const;
42 bool registerFoundOption(const QString &optionName);
43 bool parseOptionValue(const QString &optionName, const QString &argument,
44 QStringList::const_iterator *argumentIterator,
45 QStringList::const_iterator argsEnd);
46 Q_NORETURN void showHelp(int exitCode, bool includeQtOptions);
47
48 //! Error text set when parse() returns false
50
51 //! The command line options used for parsing
53
54 //! Hash mapping option names to their offsets in commandLineOptionList and optionArgumentList.
56
57 //! Option values found (only for options with a value)
59
60 //! Names of options found on the command line.
62
63 //! Arguments which did not belong to any option.
65
66 //! Names of options which were unknown.
68
69 //! Application description
71
72 //! Documentation for positional arguments
80
81 //! The parsing mode for "-abc"
83
84 //! How to parse "arg -option"
86
87 //! Whether addVersionOption was called
89
90 //! Whether addHelpOption was called
92
93 //! True if parse() needs to be called
95};
97
98QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
99{
100 const NameHash_t::const_iterator it = nameHash.constFind(optionName);
101 if (it == nameHash.cend()) {
102 qWarning("QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName));
103 return QStringList();
104 }
105 return commandLineOptionList.at(*it).names();
106}
107
108/*!
109 \since 5.2
110 \class QCommandLineParser
111 \inmodule QtCore
112 \ingroup tools
113
114 \brief The QCommandLineParser class provides a means for handling the
115 command line options.
116
117 QCoreApplication provides the command-line arguments as a simple list of strings.
118 QCommandLineParser provides the ability to define a set of options, parse the
119 command-line arguments, and store which options have actually been used, as
120 well as option values.
121
122 Any argument that isn't an option (i.e. doesn't start with a \c{-}) is stored
123 as a "positional argument".
124
125 The parser handles short names, long names, more than one name for the same
126 option, and option values.
127
128 Options on the command line are recognized as starting with one or two
129 \c{-} characters, followed by the option name.
130 The option \c{-} (single dash alone) is a special case, often meaning standard
131 input, and is not treated as an option. The parser will treat everything after the
132 option \c{--} (double dash) as positional arguments.
133
134 Short options are single letters. The option \c{v} would be specified by
135 passing \c{-v} on the command line. In the default parsing mode, short options
136 can be written in a compact form, for instance \c{-abc} is equivalent to \c{-a -b -c}.
137 The parsing mode can be changed to ParseAsLongOptions, in which case \c{-abc}
138 will be parsed as the long option \c{abc}.
139
140 Long options are more than one letter long and cannot be compacted together.
141 The long option \c{verbose} would be passed as \c{--verbose} or \c{-verbose}.
142
143 Passing values to options can be done by using the assignment operator (\c{-v=value},
144 \c{--verbose=value}), or with a space (\c{-v value}, \c{--verbose value}). This
145 works even if the the value starts with a \c{-}.
146
147 The parser does not support optional values - if an option is set to
148 require a value, one must be present. If such an option is placed last
149 and has no value, the option will be treated as if it had not been
150 specified.
151
152 The parser does not automatically support negating or disabling long options
153 by using the format \c{--disable-option} or \c{--no-option}. However, it is
154 possible to handle this case explicitly by making an option with \c{no-option}
155 as one of its names, and handling the option explicitly.
156
157 Example:
158 \snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
159
160 The three addOption() calls in the above example can be made more compact
161 by using addOptions():
162 \snippet code/src_corelib_tools_qcommandlineparser_main.cpp cxx11
163
164 Known limitation: the parsing of Qt options inside QCoreApplication and subclasses
165 happens before QCommandLineParser exists, so it can't take it into account. This
166 means any option value that looks like a builtin Qt option will be treated by
167 QCoreApplication as a builtin Qt option. Example: \c{--profile -reverse} will
168 lead to QGuiApplication seeing the -reverse option set, and removing it from
169 QCoreApplication::arguments() before QCommandLineParser defines the \c{profile}
170 option and parses the command line.
171
172 \section2 How to Use QCommandLineParser in Complex Applications
173
174 In practice, additional error checking needs to be performed on the positional
175 arguments and option values. For example, ranges of numbers should be checked.
176
177 It is then advisable to introduce a function to do the command line parsing
178 which takes a struct or class receiving the option values returning an
179 object representing the result. The dnslookup example of the QtNetwork
180 module illustrates this:
181
182 \snippet dnslookup.h 0
183
184 \snippet dnslookup.cpp 0
185
186 In the main function, help should be printed to the standard output if the help option
187 was passed and the application should return the exit code 0.
188
189 If an error was detected, the error message should be printed to the standard
190 error output and the application should return an exit code other than 0.
191
192 \snippet dnslookup.cpp 1
193
194 A special case to consider here are GUI applications on Windows and mobile
195 platforms. These applications may not use the standard output or error channels
196 since the output is either discarded or not accessible.
197
198 On Windows, QCommandLineParser uses message boxes to display usage information
199 and errors if no console window can be obtained. These message boxes can be omitted by setting
200 the \c QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES environment variable.
201
202 For other platforms, it is recommended to display help texts and error messages
203 using a QMessageBox. To preserve the formatting of the help text, rich text
204 with \c <pre> elements should be used:
205
206 \code
207
208 switch (parseResult.statusCode) {
209 case Status::Ok:
210 break;
211 case Status::Error: {
212 QString errorMessage = parseResult.errorString.value_or(u"Unknown error occurred"_qs);
213 QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
214 "<html><head/><body><h2>" + errorMessage + "</h2><pre>"
215 + parser.helpText() + "</pre></body></html>");
216 return 1;
217 }
218 case Status::VersionRequested:
219 QMessageBox::information(0, QGuiApplication::applicationDisplayName(),
220 QGuiApplication::applicationDisplayName() + ' '
221 + QCoreApplication::applicationVersion());
222 return 0;
223 case Status::HelpRequested:
224 QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
225 "<html><head/><body><pre>"
226 + parser.helpText() + "</pre></body></html>");
227 return 0;
228 }
229 \endcode
230
231 However, this does not apply to the dnslookup example, because it is a
232 console application.
233
234 \sa QCommandLineOption, QCoreApplication
235*/
236
237/*!
238 Constructs a command line parser object.
239*/
240QCommandLineParser::QCommandLineParser()
241 : d(new QCommandLineParserPrivate)
242{
243}
244
245/*!
246 Destroys the command line parser object.
247*/
248QCommandLineParser::~QCommandLineParser()
249{
250 delete d;
251}
252
253/*!
254 \enum QCommandLineParser::SingleDashWordOptionMode
255
256 This enum describes the way the parser interprets command-line
257 options that use a single dash followed by multiple letters, as \c{-abc}.
258
259 \value ParseAsCompactedShortOptions \c{-abc} is interpreted as \c{-a -b -c},
260 i.e. as three short options that have been compacted on the command-line,
261 if none of the options take a value. If \c{a} takes a value, then it
262 is interpreted as \c{-a bc}, i.e. the short option \c{a} followed by the value \c{bc}.
263 This is typically used in tools that behave like compilers, in order
264 to handle options such as \c{-DDEFINE=VALUE} or \c{-I/include/path}.
265 This is the default parsing mode. New applications are recommended to
266 use this mode.
267
268 \value ParseAsLongOptions \c{-abc} is interpreted as \c{--abc},
269 i.e. as the long option named \c{abc}. This is how Qt's own tools
270 (uic, rcc...) have always been parsing arguments. This mode should be
271 used for preserving compatibility in applications that were parsing
272 arguments in such a way. There is an exception if the \c{a} option has the
273 QCommandLineOption::ShortOptionStyle flag set, in which case it is still
274 interpreted as \c{-a bc}.
275
276 \sa setSingleDashWordOptionMode()
277*/
278
279/*!
280 Sets the parsing mode to \a singleDashWordOptionMode.
281 This must be called before process() or parse().
282*/
283void QCommandLineParser::setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode)
284{
285 d->singleDashWordOptionMode = singleDashWordOptionMode;
286}
287
288/*!
289 \enum QCommandLineParser::OptionsAfterPositionalArgumentsMode
290
291 This enum describes the way the parser interprets options that
292 occur after positional arguments.
293
294 \value ParseAsOptions \c{application argument --opt -t} is interpreted as setting
295 the options \c{opt} and \c{t}, just like \c{application --opt -t argument} would do.
296 This is the default parsing mode. In order to specify that \c{--opt} and \c{-t}
297 are positional arguments instead, the user can use \c{--}, as in
298 \c{application argument -- --opt -t}.
299
300 \value ParseAsPositionalArguments \c{application argument --opt} is interpreted as
301 having two positional arguments, \c{argument} and \c{--opt}.
302 This mode is useful for executables that aim to launch other executables
303 (e.g. wrappers, debugging tools, etc.) or that support internal commands
304 followed by options for the command. \c{argument} is the name of the command,
305 and all options occurring after it can be collected and parsed by another
306 command line parser, possibly in another executable.
307
308 \sa setOptionsAfterPositionalArgumentsMode()
309
310 \since 5.6
311*/
312
313/*!
314 Sets the parsing mode to \a parsingMode.
315 This must be called before process() or parse().
316 \since 5.6
317*/
318void QCommandLineParser::setOptionsAfterPositionalArgumentsMode(QCommandLineParser::OptionsAfterPositionalArgumentsMode parsingMode)
319{
320 d->optionsAfterPositionalArgumentsMode = parsingMode;
321}
322
323/*!
324 Adds the option \a option to look for while parsing.
325
326 Returns \c true if adding the option was successful; otherwise returns \c false.
327
328 Adding the option fails if there is no name attached to the option, or
329 the option has a name that clashes with an option name added before.
330 */
331bool QCommandLineParser::addOption(const QCommandLineOption &option)
332{
333 const QStringList optionNames = option.names();
334
335 if (!optionNames.isEmpty()) {
336 for (const QString &name : optionNames) {
337 if (d->nameHash.contains(name)) {
338 qWarning("QCommandLineParser: option already added: \"%ls\"", qUtf16Printable(name));
339 return false;
340 }
341 }
342
343 d->commandLineOptionList.append(option);
344
345 const qsizetype offset = d->commandLineOptionList.size() - 1;
346 for (const QString &name : optionNames)
347 d->nameHash.insert(name, offset);
348
349 return true;
350 }
351
352 return false;
353}
354
355/*!
356 \since 5.4
357
358 Adds the options to look for while parsing. The options are specified by
359 the parameter \a options.
360
361 Returns \c true if adding all of the options was successful; otherwise
362 returns \c false.
363
364 See the documentation for addOption() for when this function may fail.
365*/
366bool QCommandLineParser::addOptions(const QList<QCommandLineOption> &options)
367{
368 // should be optimized (but it's no worse than what was possible before)
369 bool result = true;
370 for (QList<QCommandLineOption>::const_iterator it = options.begin(), end = options.end(); it != end; ++it)
371 result &= addOption(*it);
372 return result;
373}
374
375/*!
376 Adds the \c{-v} / \c{--version} option, which displays the version string of the application.
377
378 This option is handled automatically by QCommandLineParser.
379
380 You can set the actual version string by using QCoreApplication::setApplicationVersion().
381
382 Returns the option instance, which can be used to call isSet().
383*/
384QCommandLineOption QCommandLineParser::addVersionOption()
385{
386 QCommandLineOption opt(QStringList() << QStringLiteral("v") << QStringLiteral("version"), tr("Displays version information."));
387 addOption(opt);
388 d->builtinVersionOption = true;
389 return opt;
390}
391
392/*!
393 Adds help options to the command-line parser.
394
395 The options specified for this command-line are described by \c{-h} or
396 \c{--help}. On Windows, the alternative \c{-?} is also supported. The option
397 \c{--help-all} extends that to include generic Qt options, not defined by
398 this command, in the output.
399
400 These options are handled automatically by QCommandLineParser.
401
402 Remember to use setApplicationDescription() to set the application
403 description, which will be displayed when this option is used.
404
405 Example:
406 \snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
407
408 Returns the option instance, which can be used to call isSet().
409*/
410QCommandLineOption QCommandLineParser::addHelpOption()
411{
412 QCommandLineOption opt(QStringList()
413#ifdef Q_OS_WIN
414 << QStringLiteral("?")
415#endif
416 << QStringLiteral("h")
417 << QStringLiteral("help"), tr("Displays help on commandline options."));
418 addOption(opt);
419 QCommandLineOption optHelpAll(QStringLiteral("help-all"),
420 tr("Displays help, including generic Qt options."));
421 addOption(optHelpAll);
422 d->builtinHelpOption = true;
423 return opt;
424}
425
426/*!
427 Sets the application \a description shown by helpText().
428*/
429void QCommandLineParser::setApplicationDescription(const QString &description)
430{
431 d->description = description;
432}
433
434/*!
435 Returns the application description set in setApplicationDescription().
436*/
437QString QCommandLineParser::applicationDescription() const
438{
439 return d->description;
440}
441
442/*!
443 Defines an additional argument to the application, for the benefit of the help text.
444
445 The argument \a name and \a description will appear under the \c{Arguments:} section
446 of the help. If \a syntax is specified, it will be appended to the Usage line, otherwise
447 the \a name will be appended.
448
449 Example:
450 \snippet code/src_corelib_tools_qcommandlineparser.cpp 2
451
452 \sa addHelpOption(), helpText()
453*/
454void QCommandLineParser::addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
455{
456 QCommandLineParserPrivate::PositionalArgumentDefinition arg;
457 arg.name = name;
458 arg.description = description;
459 arg.syntax = syntax.isEmpty() ? name : syntax;
460 d->positionalArgumentDefinitions.append(arg);
461}
462
463/*!
464 Clears the definitions of additional arguments from the help text.
465
466 This is only needed for the special case of tools which support multiple commands
467 with different options. Once the actual command has been identified, the options
468 for this command can be defined, and the help text for the command can be adjusted
469 accordingly.
470
471 Example:
472 \snippet code/src_corelib_tools_qcommandlineparser.cpp 3
473*/
474void QCommandLineParser::clearPositionalArguments()
475{
476 d->positionalArgumentDefinitions.clear();
477}
478
479/*!
480 Parses the command line \a arguments.
481
482 Most programs don't need to call this, a simple call to process() is enough.
483
484 parse() is more low-level, and only does the parsing. The application will have to
485 take care of the error handling, using errorText() if parse() returns \c false.
486 This can be useful for instance to show a graphical error message in graphical programs.
487
488 Calling parse() instead of process() can also be useful in order to ignore unknown
489 options temporarily, because more option definitions will be provided later on
490 (depending on one of the arguments), before calling process().
491
492 Don't forget that \a arguments must start with the name of the executable (ignored, though).
493
494 Returns \c false in case of a parse error (unknown option or missing value); returns \c true otherwise.
495
496 \sa process()
497*/
498bool QCommandLineParser::parse(const QStringList &arguments)
499{
500 return d->parse(arguments);
501}
502
503/*!
504 Returns a translated error text for the user.
505 This should only be called when parse() returns \c false.
506*/
507QString QCommandLineParser::errorText() const
508{
509 if (!d->errorText.isEmpty())
510 return d->errorText;
511 if (d->unknownOptionNames.size() == 1)
512 return tr("Unknown option '%1'.").arg(d->unknownOptionNames.constFirst());
513 if (d->unknownOptionNames.size() > 1)
514 return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(", ")));
515 return QString();
516}
517
518#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
519// Return whether to use a message box. Use handles if a console can be obtained
520// or we are run with redirected handles (for example, by QProcess).
521static inline bool displayMessageBox()
522{
523 if (GetConsoleWindow()
524 || qEnvironmentVariableIsSet("QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES"))
525 return false;
526 STARTUPINFO startupInfo;
527 startupInfo.cb = sizeof(STARTUPINFO);
528 GetStartupInfo(&startupInfo);
529 return !(startupInfo.dwFlags & STARTF_USESTDHANDLES);
530}
531#endif // Q_OS_WIN && !QT_BOOTSTRAPPED
532
533/*!
534 \enum QCommandLineParser::MessageType
535 \since 6.9
536
537 The enum is used to specify the type of the message and how it will be shown
538 to the users.
539
540 \value Information Used to show information messages. The message
541 will be printed to \c {stdout}.
542 \value Error Used to show error messages. The message will be printed
543 to \c {stderr}.
544
545 \sa showMessageAndExit()
546*/
547
548/*!
549 \since 6.9
550
551 Displays a \a message, and exits the application with the given \a exitCode.
552
553 The \a message will usually be printed directly to \c{stdout} or \c{stderr} according
554 to the given \a type, or the message may be shown in a message box under Windows when
555 necessary, with an information icon or error icon according to the given \a type
556 (set the \c{QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES} environment variable if
557 you don't want the message box).
558
559 It's the same message display method used by showHelp, showVersion and the builtin
560 options (\c{--version} if addVersionOption was called and \c{--help} / \c{--help-all}
561 if addHelpOption was called).
562
563 \sa addVersionOption(), showHelp(), showVersion(), QCommandLineParser::MessageType
564*/
565[[noreturn]] void QCommandLineParser::showMessageAndExit(MessageType type, const QString &message, int exitCode)
566{
567#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
568 if (displayMessageBox()) {
569 const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
570 | (type == MessageType::Information ? MB_ICONINFORMATION : MB_ICONERROR);
571 QString title;
572 if (QCoreApplication::instance())
573 title = QCoreApplication::instance()->property("applicationDisplayName").toString();
574 if (title.isEmpty())
575 title = QCoreApplication::applicationName();
576 MessageBoxW(0, reinterpret_cast<const wchar_t *>(message.utf16()),
577 reinterpret_cast<const wchar_t *>(title.utf16()), flags);
578 qt_call_post_routines();
579 ::exit(exitCode);
580 }
581#endif // Q_OS_WIN && !QT_BOOTSTRAPPED
582 fputs(qPrintable(message), type == MessageType::Information ? stdout : stderr);
583 qt_call_post_routines();
584 ::exit(exitCode);
585}
586
587/*!
588 Processes the command line \a arguments.
589
590 In addition to parsing the options (like parse()), this function also handles the builtin
591 options and handles errors.
592
593 The builtin options are \c{--version} if addVersionOption was called and
594 \c{--help} / \c{--help-all} if addHelpOption was called.
595
596 When invoking one of these options, or when an error happens (for instance an unknown option was
597 passed), the current process will then stop, using the exit() function.
598
599 \sa QCoreApplication::arguments(), parse()
600 */
601void QCommandLineParser::process(const QStringList &arguments)
602{
603 if (!d->parse(arguments)) {
604 showMessageAndExit(MessageType::Error,
605 QCoreApplication::applicationName() + ": "_L1 + errorText() + u'\n',
606 EXIT_FAILURE);
607 }
608
609 if (d->builtinVersionOption && isSet(QStringLiteral("version")))
610 showVersion();
611
612 if (d->builtinHelpOption && isSet(QStringLiteral("help")))
613 d->showHelp(EXIT_SUCCESS, false);
614
615 if (d->builtinHelpOption && isSet(QStringLiteral("help-all")))
616 d->showHelp(EXIT_SUCCESS, true);
617}
618
619/*!
620 \overload
621
622 The command line is obtained from the QCoreApplication instance \a app.
623 */
624void QCommandLineParser::process(const QCoreApplication &app)
625{
626 // QCoreApplication::arguments() is static, but the app instance must exist so we require it as parameter
627 Q_UNUSED(app);
628 process(QCoreApplication::arguments());
629}
630
631void QCommandLineParserPrivate::checkParsed(const char *method)
632{
633 if (needsParsing)
634 qWarning("QCommandLineParser: call process() or parse() before %s", method);
635}
636
637/*!
638 \internal
639 Looks up the option \a optionName (found on the command line) and register it as found.
640 Returns \c true on success.
641 */
642bool QCommandLineParserPrivate::registerFoundOption(const QString &optionName)
643{
644 if (nameHash.contains(optionName)) {
645 optionNames.append(optionName);
646 return true;
647 } else {
648 unknownOptionNames.append(optionName);
649 return false;
650 }
651}
652
653/*!
654 \internal
655 \brief Parse the value for a given option, if it was defined to expect one.
656
657 The value is taken from the next argument, or after the equal sign in \a argument.
658
659 \param optionName the short option name
660 \param argument the argument from the command line currently parsed. Only used for -k=value parsing.
661 \param argumentIterator iterator to the currently parsed argument. Incremented if the next argument contains the value.
662 \param argsEnd args.end(), to check if ++argumentIterator goes out of bounds
663 Returns \c true on success.
664 */
665bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, const QString &argument,
666 QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
667{
668 const QLatin1Char assignChar('=');
669 const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
670 if (nameHashIt != nameHash.constEnd()) {
671 const qsizetype assignPos = argument.indexOf(assignChar);
672 const NameHash_t::mapped_type optionOffset = *nameHashIt;
673 const QCommandLineOption &option = commandLineOptionList.at(optionOffset);
674 if (option.flags() & QCommandLineOption::IgnoreOptionsAfter) {
675 *argumentIterator = argsEnd;
676 return true;
677 }
678 const bool withValue = !option.valueName().isEmpty();
679 if (withValue) {
680 if (assignPos == -1) {
681 ++(*argumentIterator);
682 if (*argumentIterator == argsEnd) {
683 errorText = QCommandLineParser::tr("Missing value after '%1'.").arg(argument);
684 return false;
685 }
686 optionValuesHash[optionOffset].append(*(*argumentIterator));
687 } else {
688 optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
689 }
690 } else {
691 if (assignPos != -1) {
692 errorText = QCommandLineParser::tr("Unexpected value after '%1'.").arg(argument.left(assignPos));
693 return false;
694 }
695 }
696 }
697 return true;
698}
699
700/*!
701 \internal
702
703 Parse the list of arguments \a args, and fills in
704 optionNames, optionValuesHash, unknownOptionNames, positionalArguments, and errorText.
705
706 Any results from a previous parse operation are removed.
707
708 The parser will not look for further options once it encounters the option
709 \c{--}; this does not include when \c{--} follows an option that requires a value.
710 */
711bool QCommandLineParserPrivate::parse(const QStringList &args)
712{
713 needsParsing = false;
714 bool error = false;
715
716 const QLatin1Char dashChar('-');
717 const QLatin1Char assignChar('=');
718
719 bool forcePositional = false;
720 errorText.clear();
721 positionalArgumentList.clear();
722 optionNames.clear();
723 unknownOptionNames.clear();
724 optionValuesHash.clear();
725
726 if (args.isEmpty()) {
727 qWarning("QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
728 return false;
729 }
730
731 QStringList::const_iterator argumentIterator = args.begin();
732 ++argumentIterator; // skip executable name
733
734 for (; argumentIterator != args.end() ; ++argumentIterator) {
735 QString argument = *argumentIterator;
736
737 if (forcePositional) {
738 positionalArgumentList.append(argument);
739 } else if (argument.startsWith("--"_L1)) {
740 if (argument.size() > 2) {
741 QString optionName = argument.mid(2).section(assignChar, 0, 0);
742 if (registerFoundOption(optionName)) {
743 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
744 error = true;
745 } else {
746 error = true;
747 }
748 } else {
749 forcePositional = true;
750 }
751 } else if (argument.startsWith(dashChar)) {
752 if (argument.size() == 1) { // single dash ("stdin")
753 positionalArgumentList.append(argument);
754 continue;
755 }
756 switch (singleDashWordOptionMode) {
757 case QCommandLineParser::ParseAsCompactedShortOptions:
758 {
759 QString optionName;
760 bool valueFound = false;
761 for (int pos = 1 ; pos < argument.size(); ++pos) {
762 optionName = argument.mid(pos, 1);
763 if (!registerFoundOption(optionName)) {
764 error = true;
765 } else {
766 const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
767 Q_ASSERT(nameHashIt != nameHash.constEnd()); // checked by registerFoundOption
768 const NameHash_t::mapped_type optionOffset = *nameHashIt;
769 const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
770 if (withValue) {
771 if (pos + 1 < argument.size()) {
772 if (argument.at(pos + 1) == assignChar)
773 ++pos;
774 optionValuesHash[optionOffset].append(argument.mid(pos + 1));
775 valueFound = true;
776 }
777 break;
778 }
779 if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
780 break;
781 }
782 }
783 if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
784 error = true;
785 break;
786 }
787 case QCommandLineParser::ParseAsLongOptions:
788 {
789 if (argument.size() > 2) {
790 const QString possibleShortOptionStyleName = argument.mid(1, 1);
791 const auto shortOptionIt = nameHash.constFind(possibleShortOptionStyleName);
792 if (shortOptionIt != nameHash.constEnd()) {
793 const auto &arg = commandLineOptionList.at(*shortOptionIt);
794 if (arg.flags() & QCommandLineOption::ShortOptionStyle) {
795 registerFoundOption(possibleShortOptionStyleName);
796 optionValuesHash[*shortOptionIt].append(argument.mid(2));
797 break;
798 }
799 }
800 }
801 const QString optionName = argument.mid(1).section(assignChar, 0, 0);
802 if (registerFoundOption(optionName)) {
803 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
804 error = true;
805 } else {
806 error = true;
807 }
808 break;
809 }
810 }
811 } else {
812 positionalArgumentList.append(argument);
813 if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments)
814 forcePositional = true;
815 }
816 if (argumentIterator == args.end())
817 break;
818 }
819 return !error;
820}
821
822/*!
823 Checks whether the option \a name was passed to the application.
824
825 Returns \c true if the option \a name was set, false otherwise.
826
827 The name provided can be any long or short name of any option that was
828 added with addOption(). All the options names are treated as being
829 equivalent. If the name is not recognized or that option was not present,
830 false is returned.
831
832 Example:
833 \snippet code/src_corelib_tools_qcommandlineparser.cpp 0
834 */
835
836bool QCommandLineParser::isSet(const QString &name) const
837{
838 d->checkParsed("isSet");
839 if (d->optionNames.contains(name))
840 return true;
841 const QStringList aliases = d->aliases(name);
842 for (const QString &optionName : std::as_const(d->optionNames)) {
843 if (aliases.contains(optionName))
844 return true;
845 }
846 return false;
847}
848
849/*!
850 Returns the option value found for the given option name \a optionName, or
851 an empty string if not found.
852
853 The name provided can be any long or short name of any option that was
854 added with addOption(). All the option names are treated as being
855 equivalent. If the name is not recognized or that option was not present, an
856 empty string is returned.
857
858 For options found by the parser, the last value found for
859 that option is returned. If the option wasn't specified on the command line,
860 the default value is returned.
861
862 If the option does not take a value, a warning is printed, and an empty string is returned.
863
864 \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
865 */
866
867QString QCommandLineParser::value(const QString &optionName) const
868{
869 d->checkParsed("value");
870 const QStringList valueList = values(optionName);
871
872 if (!valueList.isEmpty())
873 return valueList.last();
874
875 return QString();
876}
877
878/*!
879 Returns a list of option values found for the given option name \a
880 optionName, or an empty list if not found.
881
882 The name provided can be any long or short name of any option that was
883 added with addOption(). All the options names are treated as being
884 equivalent. If the name is not recognized or that option was not present, an
885 empty list is returned.
886
887 For options found by the parser, the list will contain an entry for
888 each time the option was encountered by the parser. If the option wasn't
889 specified on the command line, the default values are returned.
890
891 An empty list is returned if the option does not take a value.
892
893 \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
894 */
895
896QStringList QCommandLineParser::values(const QString &optionName) const
897{
898 d->checkParsed("values");
899 auto it = d->nameHash.constFind(optionName);
900 if (it != d->nameHash.cend()) {
901 const qsizetype optionOffset = *it;
902 QStringList values = d->optionValuesHash.value(optionOffset);
903 if (values.isEmpty()) {
904 const auto &option = d->commandLineOptionList.at(optionOffset);
905 if (option.valueName().isEmpty()) {
906 qWarning("QCommandLineParser: option not expecting values: \"%ls\"",
907 qUtf16Printable(optionName));
908 }
909 values = option.defaultValues();
910 }
911 return values;
912 }
913
914 qWarning("QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName));
915 return QStringList();
916}
917
918/*!
919 \overload
920 Checks whether the \a option was passed to the application.
921
922 Returns \c true if the \a option was set, false otherwise.
923
924 This is the recommended way to check for options with no values.
925
926 Example:
927 \snippet code/src_corelib_tools_qcommandlineparser.cpp 1
928*/
929bool QCommandLineParser::isSet(const QCommandLineOption &option) const
930{
931 // option.names() might be empty if the constructor failed
932 const auto names = option.names();
933 return !names.isEmpty() && isSet(names.first());
934}
935
936/*!
937 \overload
938 Returns the option value found for the given \a option, or
939 an empty string if not found.
940
941 For options found by the parser, the last value found for
942 that option is returned. If the option wasn't specified on the command line,
943 the default value is returned.
944
945 An empty string is returned if the option does not take a value.
946
947 \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
948*/
949QString QCommandLineParser::value(const QCommandLineOption &option) const
950{
951 return value(option.names().constFirst());
952}
953
954/*!
955 \overload
956 Returns a list of option values found for the given \a option,
957 or an empty list if not found.
958
959 For options found by the parser, the list will contain an entry for
960 each time the option was encountered by the parser. If the option wasn't
961 specified on the command line, the default values are returned.
962
963 An empty list is returned if the option does not take a value.
964
965 \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
966*/
967QStringList QCommandLineParser::values(const QCommandLineOption &option) const
968{
969 return values(option.names().constFirst());
970}
971
972/*!
973 Returns a list of positional arguments.
974
975 These are all of the arguments that were not recognized as part of an
976 option.
977 */
978
979QStringList QCommandLineParser::positionalArguments() const
980{
981 d->checkParsed("positionalArguments");
982 return d->positionalArgumentList;
983}
984
985/*!
986 Returns a list of option names that were found.
987
988 This returns a list of all the recognized option names found by the
989 parser, in the order in which they were found. For any long options
990 that were in the form {--option=value}, the value part will have been
991 dropped.
992
993 The names in this list do not include the preceding dash characters.
994 Names may appear more than once in this list if they were encountered
995 more than once by the parser.
996
997 Any entry in the list can be used with value() or with
998 values() to get any relevant option values.
999 */
1000
1001QStringList QCommandLineParser::optionNames() const
1002{
1003 d->checkParsed("optionNames");
1004 return d->optionNames;
1005}
1006
1007/*!
1008 Returns a list of unknown option names.
1009
1010 This list will include both long an short name options that were not
1011 recognized. For any long options that were in the form {--option=value},
1012 the value part will have been dropped and only the long name is added.
1013
1014 The names in this list do not include the preceding dash characters.
1015 Names may appear more than once in this list if they were encountered
1016 more than once by the parser.
1017
1018 \sa optionNames()
1019 */
1020
1021QStringList QCommandLineParser::unknownOptionNames() const
1022{
1023 d->checkParsed("unknownOptionNames");
1024 return d->unknownOptionNames;
1025}
1026
1027/*!
1028 Displays the version information from QCoreApplication::applicationVersion(),
1029 and exits the application.
1030 This is automatically triggered by the --version option, but can also
1031 be used to display the version when not using process().
1032 The exit code is set to EXIT_SUCCESS (0).
1033
1034 \sa addVersionOption()
1035 \since 5.4
1036*/
1037Q_NORETURN void QCommandLineParser::showVersion()
1038{
1039 showMessageAndExit(MessageType::Information,
1040 QCoreApplication::applicationName() + u' '
1041 + QCoreApplication::applicationVersion() + u'\n',
1042 EXIT_SUCCESS);
1043}
1044
1045/*!
1046 Displays the help information, and exits the application.
1047 This is automatically triggered by the --help option, but can also
1048 be used to display the help when the user is not invoking the
1049 application correctly.
1050 The exit code is set to \a exitCode. It should be set to 0 if the
1051 user requested to see the help, and to any other value in case of
1052 an error.
1053
1054 \sa helpText(), showMessageAndExit()
1055*/
1056Q_NORETURN void QCommandLineParser::showHelp(int exitCode)
1057{
1058 d->showHelp(exitCode, false);
1059}
1060
1061Q_NORETURN void QCommandLineParserPrivate::showHelp(int exitCode, bool includeQtOptions)
1062{
1063 QCommandLineParser::showMessageAndExit(QCommandLineParser::MessageType::Information,
1064 helpText(includeQtOptions),
1065 exitCode);
1066}
1067
1068/*!
1069 Returns a string containing the complete help information.
1070
1071 \sa showHelp()
1072*/
1073QString QCommandLineParser::helpText() const
1074{
1075 return d->helpText(false);
1076}
1077
1078static QString wrapText(const QString &names, int optionNameMaxWidth, const QString &description)
1079{
1080 const auto nl = u'\n';
1081 const auto indentation = " "_L1;
1082
1083 // In case the list of option names is very long, wrap it as well
1084 int nameIndex = 0;
1085 auto nextNameSection = [&]() {
1086 QString section = names.mid(nameIndex, optionNameMaxWidth);
1087 nameIndex += section.size();
1088 return section;
1089 };
1090
1091 QString text;
1092 qsizetype lineStart = 0;
1093 qsizetype lastBreakable = -1;
1094 const int max = 79 - (indentation.size() + optionNameMaxWidth + 1);
1095 int x = 0;
1096 const qsizetype len = description.size();
1097
1098 for (qsizetype i = 0; i < len; ++i) {
1099 ++x;
1100 const QChar c = description.at(i);
1101 if (c.isSpace())
1102 lastBreakable = i;
1103
1104 qsizetype breakAt = -1;
1105 qsizetype nextLineStart = -1;
1106 if (x > max && lastBreakable != -1) {
1107 // time to break and we know where
1108 breakAt = lastBreakable;
1109 nextLineStart = lastBreakable + 1;
1110 } else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
1111 // time to break but found nowhere [-> break here], or end of last line
1112 breakAt = i + 1;
1113 nextLineStart = breakAt;
1114 } else if (c == nl) {
1115 // forced break
1116 breakAt = i;
1117 nextLineStart = i + 1;
1118 }
1119
1120 if (breakAt != -1) {
1121 const qsizetype numChars = breakAt - lineStart;
1122 //qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
1123 text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
1124 text += QStringView{description}.mid(lineStart, numChars) + nl;
1125 x = 0;
1126 lastBreakable = -1;
1127 lineStart = nextLineStart;
1128 if (lineStart < len && description.at(lineStart).isSpace())
1129 ++lineStart; // don't start a line with a space
1130 i = lineStart;
1131 }
1132 }
1133
1134 while (nameIndex < names.size()) {
1135 text += indentation + nextNameSection() + nl;
1136 }
1137
1138 return text;
1139}
1140
1141QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
1142{
1143 const QLatin1Char nl('\n');
1144 QString text;
1145 QString usage;
1146 // executable name
1147 usage += qApp ? QStringView(QCoreApplication::arguments().constFirst())
1148 : QStringView(u"<executable_name>");
1149 QList<QCommandLineOption> options = commandLineOptionList;
1150 if (includeQtOptions && qApp)
1151 qApp->d_func()->addQtOptions(&options);
1152 if (!options.isEmpty())
1153 usage += u' ' + QCommandLineParser::tr("[options]");
1154 for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1155 usage += u' ' + arg.syntax;
1156 text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
1157 if (!description.isEmpty())
1158 text += description + nl;
1159 text += nl;
1160 if (!options.isEmpty())
1161 text += QCommandLineParser::tr("Options:") + nl;
1162
1163 QStringList optionNameList;
1164 optionNameList.reserve(options.size());
1165 qsizetype longestOptionNameString = 0;
1166 for (const QCommandLineOption &option : std::as_const(options)) {
1167 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1168 continue;
1169 const QStringList optionNames = option.names();
1170 QString optionNamesString;
1171 for (const QString &optionName : optionNames) {
1172 const int numDashes = optionName.size() == 1 ? 1 : 2;
1173 optionNamesString += QLatin1StringView("--", numDashes) + optionName + ", "_L1;
1174 }
1175 if (!optionNames.isEmpty())
1176 optionNamesString.chop(2); // remove trailing ", "
1177 const auto valueName = option.valueName();
1178 if (!valueName.isEmpty())
1179 optionNamesString += " <"_L1 + valueName + u'>';
1180 optionNameList.append(optionNamesString);
1181 longestOptionNameString = qMax(longestOptionNameString, optionNamesString.size());
1182 }
1183
1184 for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1185 longestOptionNameString = qMax(longestOptionNameString, arg.name.size());
1186
1187 ++longestOptionNameString;
1188 const int optionNameMaxWidth = qMin(50, int(longestOptionNameString));
1189 auto optionNameIterator = optionNameList.cbegin();
1190 for (const QCommandLineOption &option : std::as_const(options)) {
1191 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1192 continue;
1193 text += wrapText(*optionNameIterator, optionNameMaxWidth, option.description());
1194 ++optionNameIterator;
1195 }
1196 if (!positionalArgumentDefinitions.isEmpty()) {
1197 if (!options.isEmpty())
1198 text += nl;
1199 text += QCommandLineParser::tr("Arguments:") + nl;
1200 for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1201 text += wrapText(arg.name, optionNameMaxWidth, arg.description);
1202 }
1203 return text;
1204}
1205
1206QT_END_NAMESPACE
QStringList aliases(const QString &name) const
bool parseOptionValue(const QString &optionName, const QString &argument, QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
Parse the value for a given option, if it was defined to expect one.
QList< QCommandLineOption > commandLineOptionList
The command line options used for parsing.
QList< PositionalArgumentDefinition > positionalArgumentDefinitions
bool registerFoundOption(const QString &optionName)
NameHash_t nameHash
Hash mapping option names to their offsets in commandLineOptionList and optionArgumentList.
bool builtinVersionOption
Whether addVersionOption was called.
QStringList optionNames
Names of options found on the command line.
QString helpText(bool includeQtOptions) const
QString description
Application description.
bool needsParsing
True if parse() needs to be called.
void checkParsed(const char *method)
bool parse(const QStringList &args)
bool builtinHelpOption
Whether addHelpOption was called.
QStringList unknownOptionNames
Names of options which were unknown.
QStringList positionalArgumentList
Arguments which did not belong to any option.
Q_NORETURN void showHelp(int exitCode, bool includeQtOptions)
QHash< qsizetype, QStringList > optionValuesHash
Option values found (only for options with a value)
QString errorText
Error text set when parse() returns false.
Definition qlist.h:80
Combined button and popup list for selecting options.
Q_DECLARE_TYPEINFO(QCommandLineParserPrivate::PositionalArgumentDefinition, Q_RELOCATABLE_TYPE)
static QString wrapText(const QString &names, int optionNameMaxWidth, const QString &description)
QHash< QString, qsizetype > NameHash_t
#define qApp