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