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