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 <qvector.h>
47#include <qdebug.h>
48#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINRT)
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 QVector<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) && !defined(Q_OS_WINRT)
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 && !Q_OS_WIN && !Q_OS_WINRT
558
559static void showParserMessage(const QString &message, MessageType type)
560{
561#if defined(Q_OS_WINRT)
562 if (type == UsageMessage)
563 qInfo("%ls", qUtf16Printable(message));
564 else
565 qCritical("%ls", qUtf16Printable(message));
566 return;
567#elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
568 if (displayMessageBox()) {
569 const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
570 | (type == UsageMessage ? 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 return;
579 }
580#endif // Q_OS_WIN && !QT_BOOTSTRAPPED
581 fputs(qPrintable(message), type == UsageMessage ? stdout : stderr);
582}
583
584/*!
585 Processes the command line \a arguments.
586
587 In addition to parsing the options (like parse()), this function also handles the builtin
588 options and handles errors.
589
590 The builtin options are \c{--version} if addVersionOption was called and
591 \c{--help} / \c{--help-all} if addHelpOption was called.
592
593 When invoking one of these options, or when an error happens (for instance an unknown option was
594 passed), the current process will then stop, using the exit() function.
595
596 \sa QCoreApplication::arguments(), parse()
597 */
598void QCommandLineParser::process(const QStringList &arguments)
599{
600 if (!d->parse(arguments)) {
601 showParserMessage(QCoreApplication::applicationName() + QLatin1String(": ") + errorText() + QLatin1Char('\n'), ErrorMessage);
602 qt_call_post_routines();
603 ::exit(EXIT_FAILURE);
604 }
605
606 if (d->builtinVersionOption && isSet(QStringLiteral("version")))
607 showVersion();
608
609 if (d->builtinHelpOption && isSet(QStringLiteral("help")))
610 d->showHelp(EXIT_SUCCESS, false);
611
612 if (d->builtinHelpOption && isSet(QStringLiteral("help-all")))
613 d->showHelp(EXIT_SUCCESS, true);
614}
615
616/*!
617 \overload
618
619 The command line is obtained from the QCoreApplication instance \a app.
620 */
621void QCommandLineParser::process(const QCoreApplication &app)
622{
623 // QCoreApplication::arguments() is static, but the app instance must exist so we require it as parameter
624 Q_UNUSED(app);
625 process(QCoreApplication::arguments());
626}
627
628void QCommandLineParserPrivate::checkParsed(const char *method)
629{
630 if (needsParsing)
631 qWarning("QCommandLineParser: call process() or parse() before %s", method);
632}
633
634/*!
635 \internal
636 Looks up the option \a optionName (found on the command line) and register it as found.
637 Returns \c true on success.
638 */
639bool QCommandLineParserPrivate::registerFoundOption(const QString &optionName)
640{
641 if (nameHash.contains(optionName)) {
642 optionNames.append(optionName);
643 return true;
644 } else {
645 unknownOptionNames.append(optionName);
646 return false;
647 }
648}
649
650/*!
651 \internal
652 \brief Parse the value for a given option, if it was defined to expect one.
653
654 The value is taken from the next argument, or after the equal sign in \a argument.
655
656 \param optionName the short option name
657 \param argument the argument from the command line currently parsed. Only used for -k=value parsing.
658 \param argumentIterator iterator to the currently parsed argument. Incremented if the next argument contains the value.
659 \param argsEnd args.end(), to check if ++argumentIterator goes out of bounds
660 Returns \c true on success.
661 */
662bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, const QString &argument,
663 QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
664{
665 const QLatin1Char assignChar('=');
666 const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
667 if (nameHashIt != nameHash.constEnd()) {
668 const int assignPos = argument.indexOf(assignChar);
669 const NameHash_t::mapped_type optionOffset = *nameHashIt;
670 const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
671 if (withValue) {
672 if (assignPos == -1) {
673 ++(*argumentIterator);
674 if (*argumentIterator == argsEnd) {
675 errorText = QCommandLineParser::tr("Missing value after '%1'.").arg(argument);
676 return false;
677 }
678 optionValuesHash[optionOffset].append(*(*argumentIterator));
679 } else {
680 optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
681 }
682 } else {
683 if (assignPos != -1) {
684 errorText = QCommandLineParser::tr("Unexpected value after '%1'.").arg(argument.left(assignPos));
685 return false;
686 }
687 }
688 }
689 return true;
690}
691
692/*!
693 \internal
694
695 Parse the list of arguments \a args, and fills in
696 optionNames, optionValuesHash, unknownOptionNames, positionalArguments, and errorText.
697
698 Any results from a previous parse operation are removed.
699
700 The parser will not look for further options once it encounters the option
701 \c{--}; this does not include when \c{--} follows an option that requires a value.
702 */
703bool QCommandLineParserPrivate::parse(const QStringList &args)
704{
705 needsParsing = false;
706 bool error = false;
707
708 const QString doubleDashString(QStringLiteral("--"));
709 const QLatin1Char dashChar('-');
710 const QLatin1Char assignChar('=');
711
712 bool forcePositional = false;
713 errorText.clear();
714 positionalArgumentList.clear();
715 optionNames.clear();
716 unknownOptionNames.clear();
717 optionValuesHash.clear();
718
719 if (args.isEmpty()) {
720 qWarning("QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
721 return false;
722 }
723
724 QStringList::const_iterator argumentIterator = args.begin();
725 ++argumentIterator; // skip executable name
726
727 for (; argumentIterator != args.end() ; ++argumentIterator) {
728 QString argument = *argumentIterator;
729
730 if (forcePositional) {
731 positionalArgumentList.append(argument);
732 } else if (argument.startsWith(doubleDashString)) {
733 if (argument.length() > 2) {
734 QString optionName = argument.mid(2).section(assignChar, 0, 0);
735 if (registerFoundOption(optionName)) {
736 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
737 error = true;
738 } else {
739 error = true;
740 }
741 } else {
742 forcePositional = true;
743 }
744 } else if (argument.startsWith(dashChar)) {
745 if (argument.size() == 1) { // single dash ("stdin")
746 positionalArgumentList.append(argument);
747 continue;
748 }
749 switch (singleDashWordOptionMode) {
750 case QCommandLineParser::ParseAsCompactedShortOptions:
751 {
752 QString optionName;
753 bool valueFound = false;
754 for (int pos = 1 ; pos < argument.size(); ++pos) {
755 optionName = argument.mid(pos, 1);
756 if (!registerFoundOption(optionName)) {
757 error = true;
758 } else {
759 const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
760 Q_ASSERT(nameHashIt != nameHash.constEnd()); // checked by registerFoundOption
761 const NameHash_t::mapped_type optionOffset = *nameHashIt;
762 const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
763 if (withValue) {
764 if (pos + 1 < argument.size()) {
765 if (argument.at(pos + 1) == assignChar)
766 ++pos;
767 optionValuesHash[optionOffset].append(argument.mid(pos + 1));
768 valueFound = true;
769 }
770 break;
771 }
772 if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
773 break;
774 }
775 }
776 if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
777 error = true;
778 break;
779 }
780 case QCommandLineParser::ParseAsLongOptions:
781 {
782 if (argument.size() > 2) {
783 const QString possibleShortOptionStyleName = argument.mid(1, 1);
784 const auto shortOptionIt = nameHash.constFind(possibleShortOptionStyleName);
785 if (shortOptionIt != nameHash.constEnd()) {
786 const auto &arg = commandLineOptionList.at(*shortOptionIt);
787 if (arg.flags() & QCommandLineOption::ShortOptionStyle) {
788 registerFoundOption(possibleShortOptionStyleName);
789 optionValuesHash[*shortOptionIt].append(argument.mid(2));
790 break;
791 }
792 }
793 }
794 const QString optionName = argument.mid(1).section(assignChar, 0, 0);
795 if (registerFoundOption(optionName)) {
796 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
797 error = true;
798 } else {
799 error = true;
800 }
801 break;
802 }
803 }
804 } else {
805 positionalArgumentList.append(argument);
806 if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments)
807 forcePositional = true;
808 }
809 if (argumentIterator == args.end())
810 break;
811 }
812 return !error;
813}
814
815/*!
816 Checks whether the option \a name was passed to the application.
817
818 Returns \c true if the option \a name was set, false otherwise.
819
820 The name provided can be any long or short name of any option that was
821 added with \c addOption(). All the options names are treated as being
822 equivalent. If the name is not recognized or that option was not present,
823 false is returned.
824
825 Example:
826 \snippet code/src_corelib_tools_qcommandlineparser.cpp 0
827 */
828
829bool QCommandLineParser::isSet(const QString &name) const
830{
831 d->checkParsed("isSet");
832 if (d->optionNames.contains(name))
833 return true;
834 const QStringList aliases = d->aliases(name);
835 for (const QString &optionName : qAsConst(d->optionNames)) {
836 if (aliases.contains(optionName))
837 return true;
838 }
839 return false;
840}
841
842/*!
843 Returns the option value found for the given option name \a optionName, or
844 an empty string if not found.
845
846 The name provided can be any long or short name of any option that was
847 added with \c addOption(). All the option names are treated as being
848 equivalent. If the name is not recognized or that option was not present, an
849 empty string is returned.
850
851 For options found by the parser, the last value found for
852 that option is returned. If the option wasn't specified on the command line,
853 the default value is returned.
854
855 An empty string is returned if the option does not take a value.
856
857 \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
858 */
859
860QString QCommandLineParser::value(const QString &optionName) const
861{
862 d->checkParsed("value");
863 const QStringList valueList = values(optionName);
864
865 if (!valueList.isEmpty())
866 return valueList.last();
867
868 return QString();
869}
870
871/*!
872 Returns a list of option values found for the given option name \a
873 optionName, or an empty list if not found.
874
875 The name provided can be any long or short name of any option that was
876 added with \c addOption(). All the options names are treated as being
877 equivalent. If the name is not recognized or that option was not present, an
878 empty list is returned.
879
880 For options found by the parser, the list will contain an entry for
881 each time the option was encountered by the parser. If the option wasn't
882 specified on the command line, the default values are returned.
883
884 An empty list is returned if the option does not take a value.
885
886 \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
887 */
888
889QStringList QCommandLineParser::values(const QString &optionName) const
890{
891 d->checkParsed("values");
892 const NameHash_t::const_iterator it = d->nameHash.constFind(optionName);
893 if (it != d->nameHash.cend()) {
894 const int optionOffset = *it;
895 QStringList values = d->optionValuesHash.value(optionOffset);
896 if (values.isEmpty())
897 values = d->commandLineOptionList.at(optionOffset).defaultValues();
898 return values;
899 }
900
901 qWarning("QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName));
902 return QStringList();
903}
904
905/*!
906 \overload
907 Checks whether the \a option was passed to the application.
908
909 Returns \c true if the \a option was set, false otherwise.
910
911 This is the recommended way to check for options with no values.
912
913 Example:
914 \snippet code/src_corelib_tools_qcommandlineparser.cpp 1
915*/
916bool QCommandLineParser::isSet(const QCommandLineOption &option) const
917{
918 // option.names() might be empty if the constructor failed
919 const auto names = option.names();
920 return !names.isEmpty() && isSet(names.first());
921}
922
923/*!
924 \overload
925 Returns the option value found for the given \a option, or
926 an empty string if not found.
927
928 For options found by the parser, the last value found for
929 that option is returned. If the option wasn't specified on the command line,
930 the default value is returned.
931
932 An empty string is returned if the option does not take a value.
933
934 \sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
935*/
936QString QCommandLineParser::value(const QCommandLineOption &option) const
937{
938 return value(option.names().constFirst());
939}
940
941/*!
942 \overload
943 Returns a list of option values found for the given \a option,
944 or an empty list if not found.
945
946 For options found by the parser, the list will contain an entry for
947 each time the option was encountered by the parser. If the option wasn't
948 specified on the command line, the default values are returned.
949
950 An empty list is returned if the option does not take a value.
951
952 \sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
953*/
954QStringList QCommandLineParser::values(const QCommandLineOption &option) const
955{
956 return values(option.names().constFirst());
957}
958
959/*!
960 Returns a list of positional arguments.
961
962 These are all of the arguments that were not recognized as part of an
963 option.
964 */
965
966QStringList QCommandLineParser::positionalArguments() const
967{
968 d->checkParsed("positionalArguments");
969 return d->positionalArgumentList;
970}
971
972/*!
973 Returns a list of option names that were found.
974
975 This returns a list of all the recognized option names found by the
976 parser, in the order in which they were found. For any long options
977 that were in the form {--option=value}, the value part will have been
978 dropped.
979
980 The names in this list do not include the preceding dash characters.
981 Names may appear more than once in this list if they were encountered
982 more than once by the parser.
983
984 Any entry in the list can be used with \c value() or with
985 \c values() to get any relevant option values.
986 */
987
988QStringList QCommandLineParser::optionNames() const
989{
990 d->checkParsed("optionNames");
991 return d->optionNames;
992}
993
994/*!
995 Returns a list of unknown option names.
996
997 This list will include both long an short name options that were not
998 recognized. For any long options that were in the form {--option=value},
999 the value part will have been dropped and only the long name is added.
1000
1001 The names in this list do not include the preceding dash characters.
1002 Names may appear more than once in this list if they were encountered
1003 more than once by the parser.
1004
1005 \sa optionNames()
1006 */
1007
1008QStringList QCommandLineParser::unknownOptionNames() const
1009{
1010 d->checkParsed("unknownOptionNames");
1011 return d->unknownOptionNames;
1012}
1013
1014/*!
1015 Displays the version information from QCoreApplication::applicationVersion(),
1016 and exits the application.
1017 This is automatically triggered by the --version option, but can also
1018 be used to display the version when not using process().
1019 The exit code is set to EXIT_SUCCESS (0).
1020
1021 \sa addVersionOption()
1022 \since 5.4
1023*/
1024Q_NORETURN void QCommandLineParser::showVersion()
1025{
1026 showParserMessage(QCoreApplication::applicationName() + QLatin1Char(' ')
1027 + QCoreApplication::applicationVersion() + QLatin1Char('\n'),
1028 UsageMessage);
1029 qt_call_post_routines();
1030 ::exit(EXIT_SUCCESS);
1031}
1032
1033/*!
1034 Displays the help information, and exits the application.
1035 This is automatically triggered by the --help option, but can also
1036 be used to display the help when the user is not invoking the
1037 application correctly.
1038 The exit code is set to \a exitCode. It should be set to 0 if the
1039 user requested to see the help, and to any other value in case of
1040 an error.
1041
1042 \sa helpText()
1043*/
1044Q_NORETURN void QCommandLineParser::showHelp(int exitCode)
1045{
1046 d->showHelp(exitCode, false);
1047}
1048
1049Q_NORETURN void QCommandLineParserPrivate::showHelp(int exitCode, bool includeQtOptions)
1050{
1051 showParserMessage(helpText(includeQtOptions), UsageMessage);
1052 qt_call_post_routines();
1053 ::exit(exitCode);
1054}
1055
1056/*!
1057 Returns a string containing the complete help information.
1058
1059 \sa showHelp()
1060*/
1061QString QCommandLineParser::helpText() const
1062{
1063 return d->helpText(false);
1064}
1065
1066static QString wrapText(const QString &names, int longestOptionNameString, const QString &description)
1067{
1068 const QLatin1Char nl('\n');
1069 const QLatin1String indentation(" ");
1070 if (description.isEmpty())
1071 return indentation + names + nl;
1072
1073 QString text = indentation + names.leftJustified(longestOptionNameString) + QLatin1Char(' ');
1074 const int indent = text.length();
1075 int lineStart = 0;
1076 int lastBreakable = -1;
1077 const int max = 79 - indent;
1078 int x = 0;
1079 const int len = description.length();
1080
1081 for (int i = 0; i < len; ++i) {
1082 ++x;
1083 const QChar c = description.at(i);
1084 if (c.isSpace())
1085 lastBreakable = i;
1086
1087 int breakAt = -1;
1088 int nextLineStart = -1;
1089 if (x > max && lastBreakable != -1) {
1090 // time to break and we know where
1091 breakAt = lastBreakable;
1092 nextLineStart = lastBreakable + 1;
1093 } else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
1094 // time to break but found nowhere [-> break here], or end of last line
1095 breakAt = i + 1;
1096 nextLineStart = breakAt;
1097 } else if (c == nl) {
1098 // forced break
1099 breakAt = i;
1100 nextLineStart = i + 1;
1101 }
1102
1103 if (breakAt != -1) {
1104 const int numChars = breakAt - lineStart;
1105 //qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
1106 if (lineStart > 0)
1107 text += QString(indent, QLatin1Char(' '));
1108 text += description.midRef(lineStart, numChars) + nl;
1109 x = 0;
1110 lastBreakable = -1;
1111 lineStart = nextLineStart;
1112 if (lineStart < len && description.at(lineStart).isSpace())
1113 ++lineStart; // don't start a line with a space
1114 i = lineStart;
1115 }
1116 }
1117
1118 return text;
1119}
1120
1121QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
1122{
1123 const QLatin1Char nl('\n');
1124 QString text;
1125 QString usage;
1126 usage += QCoreApplication::instance()->arguments().constFirst(); // executable name
1127 QList<QCommandLineOption> options = commandLineOptionList;
1128 if (includeQtOptions)
1129 QCoreApplication::instance()->d_func()->addQtOptions(&options);
1130 if (!options.isEmpty())
1131 usage += QLatin1Char(' ') + QCommandLineParser::tr("[options]");
1132 for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1133 usage += QLatin1Char(' ') + arg.syntax;
1134 text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
1135 if (!description.isEmpty())
1136 text += description + nl;
1137 text += nl;
1138 if (!options.isEmpty())
1139 text += QCommandLineParser::tr("Options:") + nl;
1140 QStringList optionNameList;
1141 optionNameList.reserve(options.size());
1142 int longestOptionNameString = 0;
1143 for (const QCommandLineOption &option : qAsConst(options)) {
1144 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1145 continue;
1146 const QStringList optionNames = option.names();
1147 QString optionNamesString;
1148 for (const QString &optionName : optionNames) {
1149 const int numDashes = optionName.length() == 1 ? 1 : 2;
1150 optionNamesString += QLatin1String("--", numDashes) + optionName + QLatin1String(", ");
1151 }
1152 if (!optionNames.isEmpty())
1153 optionNamesString.chop(2); // remove trailing ", "
1154 const auto valueName = option.valueName();
1155 if (!valueName.isEmpty())
1156 optionNamesString += QLatin1String(" <") + valueName + QLatin1Char('>');
1157 optionNameList.append(optionNamesString);
1158 longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length());
1159 }
1160 ++longestOptionNameString;
1161 auto optionNameIterator = optionNameList.cbegin();
1162 for (const QCommandLineOption &option : qAsConst(options)) {
1163 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1164 continue;
1165 text += wrapText(*optionNameIterator, longestOptionNameString, option.description());
1166 ++optionNameIterator;
1167 }
1168 if (!positionalArgumentDefinitions.isEmpty()) {
1169 if (!options.isEmpty())
1170 text += nl;
1171 text += QCommandLineParser::tr("Arguments:") + nl;
1172 for (const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1173 text += wrapText(arg.name, longestOptionNameString, arg.description);
1174 }
1175 return text;
1176}
1177
1178QT_END_NAMESPACE
1179