1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtDebug>
30#include <QTextBoundaryFinder>
31#include <QCoreApplication>
32#include <QHash>
33#include <QPair>
34#include <QStringList>
35#include <QTextStream>
36#include <QUrl>
37#include <QRegExp>
38
39#include "qapplicationargument_p.h"
40
41#include "qapplicationargumentparser_p.h"
42
43#include <algorithm>
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 \class QApplicationArgumentParser
49 \brief The QApplicationArgumentParser class parses the command
50 line arguments for an application.
51 \reentrant
52 \internal
53 \since 4.4
54
55 QApplicationArgumentParser simplifies writing command line applications by taking care of:
56
57 \list
58 \li Generating help and version arguments
59 \li Taking care of converting arguments to QVariant types, since each argument
60 has a type: QApplicationArgument::type()
61 \li Validates the command line such that the user operates on well-defined input. For instance,
62 that the argument is a valid integer if that is the case, that an argument does not
63 occur more times than allowed, and so on.
64 \li Allows customization through sub-classing.
65 \endlist
66
67 The user declares what arguments that can be given to the application with QApplicationArgument. Provided
68 with that information, QApplicationArgumentParser takes care of parsing the actual
69 command line, appropriately flag errors, generate help messages, and provide
70 convenient access to the values of the arguments.
71
72 The way to use it is to create a set of QApplicationArgument by ones choosing, call
73 addArgument() for each, and subsequently call parse(). If parse() returns \c false,
74 the caller should exit and return exitCode().
75
76 If parse() returns \c true the command line was successfully parsed, its
77 values are well-defined, and they can be spectated with count(),
78 has(), value() and values().
79
80 \snippet doc/src/snippets/code/tools_patternist_qapplicationargumentparser.cpp 0
81
82 For arguments without a name(such as filename passed to the \c ls utility on Linux) add a
83 QApplicationArgument that does not have a name. The minimum and maximum occurrences will be
84 respected as usual and the type applies too.
85
86 QApplicationArgumentParser always has two options builtin: \c version and \c help.
87
88 \section1 Changing Parsing Convention
89
90 QApplicationArgumentParser by default parses the command line in the style
91 of Qt's utilities, where arguments are preceded by a single dash, and identified
92 by a single name. However, in some cases it might be of interest to parse
93 another style, such as the well-established UNIX \c getopt convention(\c -l
94 and \c --long).
95
96 This can be achieved by sub-classing QApplicationArgumentParser and reimplementing
97 parse(). It would do the following:
98
99 \list
100 \li Call input() to retrieve the strings the user specified on the command line.
101 \li Call declaredArguments() to retrieve the arguments that the implementor has
102 decided can be specified.
103 \li Parse and validate the input. Salt and pepper as per taste.
104 \li If an error occurred, call setExitCode() and return \c false.
105 \li Otherwise, call setExitCode(Success), provide access to the
106 arguments by calling setUsedArguments(), and return \c true. If a
107 help message was requested, call setExitCode(Success) and return \c false.
108 \endlist
109
110 \sa QApplicationArgument, QCoreApplication
111*/
112class QApplicationArgumentParserPrivate
113{
114 Q_DECLARE_TR_FUNCTIONS(QApplicationArgumentParserPrivate)
115public:
116 // TODO Isn't it like ten times better with QHash<QApplicationArgument, QList<QVariant> >?
117 // TODO test QApplicationArgument::nameless()
118 typedef QList<QPair<QApplicationArgument, QVariant> > UsedList;
119
120 /*!
121 We initialize exitCode to ParseError such that we consciously flag success.
122 */
123 inline QApplicationArgumentParserPrivate(QApplicationArgumentParser *const master,
124 const QStringList &aInput) : exitCode(QApplicationArgumentParser::ParseError)
125 , input(aInput)
126 , q_ptr(master)
127 {
128 Q_ASSERT(!aInput.isEmpty());
129 }
130
131 QApplicationArgument nextNamelessArgument() const;
132 static QStringList argumentsFromLocal(const int argc, const char *const *const argv);
133
134 bool error(const QString &message);
135 static bool errorMessage(const QString &message);
136 static inline bool isSwitch(const QApplicationArgument &arg);
137 static inline QVariant conversionError(const QString &typeName,
138 const QString &input);
139 int count(const QApplicationArgument &arg) const;
140 bool contains(const QApplicationArgument &arg) const;
141 static inline bool isBuiltinVariant(const int type);
142 void displayVersion() const;
143 void displayHelp() const;
144 void parseNameless();
145 bool parseNamelessArguments(const QString &in);
146
147 QApplicationArgumentParser::ExitCode exitCode;
148 const QStringList input;
149
150 /*!
151 Since the QString is QApplicationArgument::name() anyway, why
152 not use a QSet?
153 */
154 QHash<QString, QApplicationArgument> declaredArguments;
155
156 QList<QApplicationArgument> declaredNamelessArguments;
157
158 UsedList usedArguments;
159 QString applicationDescription;
160 QString applicationVersion;
161
162private:
163 QApplicationArgumentParser *const q_ptr;
164 Q_DECLARE_PUBLIC(QApplicationArgumentParser)
165
166 static QString lineWrap(const QString &input,
167 const int leftIndent,
168 const int width);
169 static QList<QApplicationArgument> builtinArguments();
170};
171
172QApplicationArgument QApplicationArgumentParserPrivate::nextNamelessArgument() const
173{
174 /* Count how many nameless arguments we have so far. */
175 int count = 0;
176
177 for(int i = 0; i < usedArguments.count(); ++i)
178 {
179 if(usedArguments.at(i).first.isNameless())
180 ++count;
181 }
182
183 /* TODO this doesn't work for arguments that have more than one
184 * mandatory value(e.g nameless ones), since several values should
185 * then only count for one argument. */
186 for(int i = 0; i < declaredNamelessArguments.count(); ++i)
187 {
188 if(count)
189 {
190 /* Skip the ones we already have processed. */
191 --count;
192 continue;
193 }
194
195 if(declaredNamelessArguments.at(i).isNameless())
196 return declaredNamelessArguments.at(i);
197 }
198
199 return QApplicationArgument();
200}
201
202int QApplicationArgumentParserPrivate::count(const QApplicationArgument &arg) const
203{
204 const int len = usedArguments.count();
205 int count = 0;
206
207 for(int i = 0; i < len; ++i)
208 {
209 if(usedArguments.at(i).first == arg)
210 ++count;
211 }
212
213 return count;
214}
215
216/*!
217 Returns \c true if \a arg has appeared on the command line, not whether it has been declared.
218 */
219bool QApplicationArgumentParserPrivate::contains(const QApplicationArgument &arg) const
220{
221 const int len = usedArguments.count();
222
223 for(int i = 0; i < len; ++i)
224 {
225 if(usedArguments.at(i).first == arg)
226 return true;
227 }
228
229 return false;
230}
231
232/*!
233 Returns always \c false.
234 */
235bool QApplicationArgumentParserPrivate::error(const QString &message)
236{
237 exitCode = QApplicationArgumentParser::ParseError;
238 errorMessage(message);
239 return errorMessage(message: tr(sourceText: "Pass -help for information about the command line."));
240}
241
242/*!
243 Returns always \c false.
244 */
245bool QApplicationArgumentParserPrivate::errorMessage(const QString &message)
246{
247 QTextStream out(stderr, QIODevice::WriteOnly);
248 out << message << Qt::endl;
249 return false;
250}
251
252/*!
253 \internal
254 Determines whether \a arg carries a value or is on/off.
255 */
256bool QApplicationArgumentParserPrivate::isSwitch(const QApplicationArgument &arg)
257{
258 return arg.type() == QVariant::Invalid;
259}
260
261QVariant QApplicationArgumentParserPrivate::conversionError(const QString &typeName,
262 const QString &input)
263{
264 errorMessage(message: tr(sourceText: "Cannot convert %1 to type %2.").arg(a1: input, a2: typeName));
265 return QVariant();
266}
267
268bool QApplicationArgumentParserPrivate::isBuiltinVariant(const int type)
269{
270 return type < int(QVariant::UserType);
271}
272
273/*!
274 TODO Temporary, replace with a function in QCoreApplication.
275*/
276QStringList QApplicationArgumentParserPrivate::argumentsFromLocal(const int argc, const char *const *const argv)
277{
278 Q_ASSERT(argc >= 1);
279 Q_ASSERT(argv);
280 QStringList result;
281
282 for(int i = 0; i < argc; ++i)
283 result.append(t: QString::fromLocal8Bit(str: argv[i]));
284
285 return result;
286}
287
288void QApplicationArgumentParserPrivate::displayVersion() const
289{
290 QTextStream out(stderr);
291
292 out << tr(sourceText: "%1 version %2 using Qt %3").arg(args: QCoreApplication::applicationName(), args: applicationVersion, args: QString::fromLatin1(str: qVersion()))
293 << Qt::endl;
294}
295
296void QApplicationArgumentParserPrivate::displayHelp() const
297{
298 enum Constants
299 {
300 /**
301 * When we want to line wrap, 80 minus a couple of characters. This should
302 * be suitable for vt100 compatible terminals.
303 */
304 LineWrapAt = 78,
305
306 /**
307 * The initial " -" for each option.
308 */
309 IndentPadding = 3,
310
311 /**
312 * Pad for the brackets and space we use when we have a type.
313 */
314 ValueArgumentPadding = 4
315 };
316
317 QList<QApplicationArgument> args(declaredArguments.values());
318 args += builtinArguments();
319
320 /* Sort them, such that we get the nameless options at the end, and it
321 * generally looks tidy. */
322 std::sort(first: args.begin(), last: args.end());
323
324 /* This is the basic approach:
325 * Switches:
326 * -name description
327 * Value arguments:
328 * -name <name-of-value-type> description
329 *
330 * Nameless arguments
331 * name <type> description
332 *
333 * It all line-wraps at OutputWidth and the description is indented,
334 * where the highest indent is the length of the name plus length of the name
335 * of the type. */
336
337 /* First we find the name with the largest width. */
338 int maxWidth = 0;
339
340 QList<QApplicationArgument> nameless(declaredNamelessArguments);
341 std::sort(first: nameless.begin(), last: nameless.end());
342
343 /* Note, here the nameless arguments appear last, but are sorted
344 * with themselves. */
345 QList<QApplicationArgument> allArgs(args + nameless);
346 const int allArgsCount = allArgs.count();
347
348 for(int i = 0; i < allArgsCount; ++i)
349 {
350 const QApplicationArgument &at = allArgs.at(i);
351 const int nameLength = at.name().length();
352 const QString typeName(q_ptr->typeToName(argument: at));
353 const int typeNameLength = typeName.length();
354 const int padding = at.type() == QVariant::Invalid ? 0 : ValueArgumentPadding;
355 maxWidth = qMax(a: maxWidth, b: nameLength + typeNameLength + padding);
356 }
357
358 QTextStream out(stderr);
359 out << Qt::endl
360 << QString(IndentPadding, QLatin1Char(' '))
361 << QCoreApplication::applicationName()
362 << QLatin1String(" -- ")
363 << applicationDescription
364 << Qt::endl;
365 // TODO synopsis
366
367 /* One extra so we get some space between the overview and the options. */
368 out << Qt::endl;
369
370 const int indentWidth = maxWidth + 3;
371
372 /* Ok, print them out. */
373 for(int i = 0; i < allArgsCount; ++i)
374 {
375 const QApplicationArgument &at = allArgs.at(i);
376 /* " -name ". Indent a bit first, inspired by Qt's moc. */
377 const QString &name = at.name();
378 QString prolog(QLatin1String(" "));
379
380 /* We have a special case for the single dash. */
381 if(name == QChar::fromLatin1(c: '-'))
382 prolog.append(s: name);
383 else
384 {
385 if(!at.isNameless())
386 prolog.append(c: QLatin1Char('-'));
387
388 prolog.append(s: name + QLatin1Char(' '));
389 }
390
391 if(at.type() != QVariant::Invalid)
392 {
393 /* It's not a switch, it has a value. */
394
395 /* Do we have a default value? If so, the argument is optional. */
396 const QString typeName(q_ptr->typeToName(argument: at));
397
398 if(at.defaultValue().isValid())
399 prolog.append(s: QLatin1Char('[') + typeName + QLatin1Char(']'));
400 else
401 prolog.append(s: QLatin1Char('<') + typeName + QLatin1Char('>'));
402 // TODO Don't we want to display the default value?
403
404 prolog.append(c: QLatin1Char(' '));
405 }
406
407 prolog = prolog.leftJustified(width: indentWidth);
408
409 out << prolog
410 << lineWrap(input: at.description(), leftIndent: indentWidth, width: LineWrapAt)
411 << Qt::endl;
412 }
413}
414
415/*!
416 Line wraps \a input and indents each line with \a leftIndent spaces, such that
417 the width does not go beyond \a maxWidth.
418
419 The addition of line endings is accounted for by the caller.
420
421 With QTextBoundaryFinder our line wrapping is relatively fancy, since it
422 does it the Unicode-way.
423 */
424QString QApplicationArgumentParserPrivate::lineWrap(const QString &input,
425 const int leftIndent,
426 const int maxWidth)
427{
428 const QString indent(QString(leftIndent, QLatin1Char(' ')));
429 const int len = input.length();
430 const int textWidth = maxWidth - leftIndent;
431
432 QString output;
433 QTextBoundaryFinder wrapFinder(QTextBoundaryFinder::Line, input);
434 wrapFinder.setPosition(textWidth);
435
436 if(input.length() + leftIndent <= maxWidth)
437 return input;
438
439 int from = wrapFinder.toPreviousBoundary();
440 output.append(s: input.leftRef(n: from));
441
442 while(true)
443 {
444 if((len - from) + leftIndent > maxWidth)
445 {
446 /* We need to line wrap. */
447 wrapFinder.setPosition(from + textWidth);
448 const int currentWidthPos = wrapFinder.toPreviousBoundary();
449
450 output.append(c: QLatin1Char('\n'));
451 output.append(s: indent);
452 output.append(s: input.midRef(position: from, n: currentWidthPos - from).trimmed().toString());
453 from += (currentWidthPos - from);
454 }
455 else
456 {
457 /* Append the remains. */
458 output.append(c: QLatin1Char('\n'));
459 output.append(s: indent);
460 output.append(s: input.midRef(position: from).trimmed().toString());
461 break;
462 }
463 }
464
465 return output;
466}
467
468/*!
469 Returns a list with the builtin options that the parser has
470 */
471QList<QApplicationArgument> QApplicationArgumentParserPrivate::builtinArguments()
472{
473 QList<QApplicationArgument> result;
474
475 result.append(t: QApplicationArgument(QLatin1String("help"),
476 QLatin1String("Displays this help.")));
477 result.append(t: QApplicationArgument(QLatin1String("version"),
478 QLatin1String("Displays version information.")));
479
480 result.append(t: QApplicationArgument(QLatin1String("-"),
481 QLatin1String("When appearing, any following options are not interpreted as switches.")));
482 return result;
483}
484
485/* TODO, I don't think we want this function in a public API. Add it first when there is a demand. */
486
487/*!
488 Creates a QApplicationArgumentParser that will parse the input in \a argc and \a argv.
489These arguments should be passed directly from the \c main() function, and the decoding
490of the input will be taken care of appropriately, depending on platform.
491
492 It is preferred to use the QStringList overload, in case the input is in the form of QStrings.
493 */
494QApplicationArgumentParser::QApplicationArgumentParser(int argc, char **argv) : d(new QApplicationArgumentParserPrivate(this, QApplicationArgumentParserPrivate::argumentsFromLocal(argc, argv)))
495{
496 Q_ASSERT_X(argv, Q_FUNC_INFO, "Argv cannot be null.");
497 Q_ASSERT_X(argc >= 1, Q_FUNC_INFO,
498 "argc must at least contain the application name. "
499 "Use the QStringList overload instead.");
500}
501
502/*!
503 \overload
504
505 Creates a QApplicationArgumentParser that will parse \a input. That is, instead of passing in \c argc
506 and \c argv, one can pass in a QStringList.
507
508 The caller guarantees that the first string in \a input is the name of the application.
509 */
510QApplicationArgumentParser::QApplicationArgumentParser(const QStringList &input) : d(new QApplicationArgumentParserPrivate(this, input))
511{
512 Q_ASSERT_X(input.count() >= 1, Q_FUNC_INFO,
513 "The input must at least contain the application name.");
514}
515
516/*!
517 This function is only of interest when subclassing.
518
519 Returns the strings that the user specified when starting the application. The first string
520 in the list is always the application name.
521 */
522QStringList QApplicationArgumentParser::input() const
523{
524 Q_ASSERT_X(d->input.count() >= 1, Q_FUNC_INFO, "Internal error, this should always hold true");
525 return d->input;
526}
527
528/*!
529 This function is only of interest when subclassing.
530
531 Sets the arguments that the user actually used on the command line to \a arguments.
532 The parse() function should call this, such that the result afterwards can be inspected
533 with for instance has() or count().
534
535\sa usedArguments()
536*/
537void QApplicationArgumentParser::setUsedArguments(const QList<QPair<QApplicationArgument, QVariant> > &arguments)
538{
539 d->usedArguments = arguments;
540}
541
542/*!
543 This function is only of interest when subclassing.
544
545 Returns the arguments that the user used on the command line.
546
547\sa setUsedArguments()
548*/
549QList<QPair<QApplicationArgument, QVariant> > QApplicationArgumentParser::usedArguments() const
550{
551 return d->usedArguments;
552}
553
554/*!
555 Destructs this QApplicationArgumentParser instance.
556 */
557QApplicationArgumentParser::~QApplicationArgumentParser()
558{
559 delete d;
560}
561
562/*!
563 Adds \a argument to this parser.
564
565 This function is provided for convenience. It is equivalent to creating a QList
566 containing \a argument, append the existing arguments, and then call setDeclaredArguments() with the list.
567
568 \sa setDeclaredArguments()
569 */
570void QApplicationArgumentParser::addArgument(const QApplicationArgument &argument)
571{
572 if(argument.isNameless())
573 d->declaredNamelessArguments.append(t: argument);
574 else
575 d->declaredArguments.insert(akey: argument.name(), avalue: argument);
576}
577
578/*!
579 Makes the parser recognize all arguments in \a arguments.
580
581 Any arguments previously set, are discarded.
582
583 \sa addArgument(), declaredArguments()
584 */
585void QApplicationArgumentParser::setDeclaredArguments(const QList<QApplicationArgument> &arguments)
586{
587 // TODO If we have a QHash internally, why not use it in the public API too?
588 const int len = arguments.count();
589
590 for(int i = 0; i < len; ++i)
591 d->declaredArguments.insert(akey: arguments.at(i).name(), avalue: arguments.at(i));
592}
593
594/*!
595 Returns the arguments that this parser recognizes.
596
597 \sa addArgument(), setDeclaredArguments()
598 */
599QList<QApplicationArgument> QApplicationArgumentParser::declaredArguments() const
600{
601 return d->declaredArguments.values();
602}
603
604bool QApplicationArgumentParserPrivate::parseNamelessArguments(const QString &in)
605{
606 /* It's a nameless options, such as simply "value". */
607 const QApplicationArgument nameless(nextNamelessArgument());
608
609 const QVariant val(q_ptr->convertToValue(argument: nameless, value: in));
610 if(val.isValid())
611 {
612 usedArguments.append(t: qMakePair(x: nameless, y: val));
613 return true;
614 }
615 else
616 return false; // TODO error msg?
617}
618
619/*!
620 Parses input() together with declaredArguments() and returns \c false if the caller
621 should exit immediately, which is the case of which an error was encountered or
622 help or the version was requested.
623
624 In the case of \c true was returned, valid arguments were supplied, and they can
625 be requested with functions like value(), values(), count() and has().
626
627 parse() must only be called once per QApplicationArgumentParser instance. The
628 second time it's called, the effects and return value are undefined.
629
630 \sa convertToValue(), typeToName()
631 */
632bool QApplicationArgumentParser::parse()
633{
634 const QChar sep(QLatin1Char('-'));
635 const int inputCount = d->input.count();
636
637 /* We skip the first entry, which is the application name. */
638 int i = 1;
639
640 for(; i < inputCount; ++i)
641 {
642 const QString &in = d->input.at(i);
643
644 /* We have a single '-', signalling that the succeeding are not options. */
645 if(in == sep)
646 {
647 ++i;
648
649 for(; i < inputCount; ++i)
650 {
651 if(!d->parseNamelessArguments(in: d->input.at(i)))
652 return false;
653 /* Process nameless options. Have code for this elsewhere, factor it out. */
654 }
655
656 break;
657 }
658
659 if(in.startsWith(c: sep)) /* It is "-name". */
660 {
661 const QString name(in.mid(position: 1));
662
663 if(name == QLatin1String("help"))
664 {
665 setExitCode(Success);
666 d->displayHelp();
667 return false;
668 }
669 else if(name == QLatin1String("version"))
670 {
671 setExitCode(Success);
672 d->displayVersion();
673 return false;
674 }
675
676 if(!d->declaredArguments.contains(akey: name))
677 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "\"%1\" is an unknown argument.").arg(a: name));
678
679 const QApplicationArgument &arg = d->declaredArguments.value(akey: name);
680 const int argCount = d->count(arg) + 1;
681 const int max = arg.maximumOccurrence();
682
683 if(argCount > max && max != -1)
684 {
685 /* Let's tailor the message for a common case. */
686 if(max == 1)
687 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "\"%1\" can only be used once.").arg(a: name));
688 else
689 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "\"%1\" can only be used %2 times.").arg(args: name, args: QString::number(max)));
690 }
691
692 if(QApplicationArgumentParserPrivate::isSwitch(arg))
693 {
694 d->usedArguments.append(t: qMakePair(x: arg, y: QVariant()));
695 continue;
696 }
697 else
698 {
699 ++i;
700
701 if(i == inputCount)
702 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "\"%1\" must be followed by a value.").arg(a: name));
703
704 /* Okidoki, got a value, always something. Let's
705 * see if it validates. */
706 const QString &value = d->input.at(i);
707
708 const QVariant val(convertToValue(argument: arg, value));
709 if(val.isValid())
710 {
711 d->usedArguments.append(t: qMakePair(x: arg, y: val));
712 continue;
713 }
714 else
715 return false; // TODO error msg?
716 }
717 }
718 else
719 {
720 if(!d->parseNamelessArguments(in))
721 return false;
722 }
723 }
724
725 /* Check that all arguments that have been declared as mandatory, are actually
726 * specified. */
727 const QList<QApplicationArgument> declaredArguments(d->declaredArguments.values() + d->declaredNamelessArguments);
728 const int len = declaredArguments.count();
729 for(int i = 0; i < len; ++i)
730 {
731 const QApplicationArgument &at = declaredArguments.at(i);
732 const int min = at.minimumOccurrence();
733 const int max = at.maximumOccurrence(); // TODO What about infinite? -1
734 if(min == 0)
735 continue;
736 else
737 {
738 const int usedLen = d->usedArguments.count();
739 int useCount = 0;
740
741 for(int u = 0; u < usedLen; ++u)
742 {
743 const QPair<QApplicationArgument, QVariant> &used = d->usedArguments.at(i: u);
744 if(used.first == at)
745 ++useCount;
746 }
747
748 const QString originalName(at.name());
749 const QString effectiveName(originalName.isEmpty() ? QLatin1Char('<') + typeToName(argument: at) + QLatin1Char('>') : originalName);
750
751 if(useCount < min)
752 {
753 /* For nameless options, we use the type as the name. Looks better. */
754 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "%1 must occur at least %2 times, therefore %3 times is insufficient.", disambiguation: "The number is for %2.", n: min)
755 .arg(args: effectiveName, args: QString::number(min), args: QString::number(useCount)));
756 }
757 else if(useCount > max)
758 return d->error(message: QApplicationArgumentParserPrivate::tr(sourceText: "%1 can occur at most %2 times", disambiguation: "", n: max).arg(args: effectiveName, args: QString::number(max)));
759 }
760 }
761
762 d->exitCode = Success;
763 return true;
764}
765
766/*!
767 This function is only of interest when subclassing.
768
769 parse() calls this function each time a value, that is \a input, on the command line needs to be
770 validated and subsequently converted to the type of \a argument. A descriptive error message will
771 be outputted if \a input cannot be converted to the required type.
772
773 The default implementation uses QVariant::canConvert() and QVariant::convert() for doing conversions.
774
775 QApplicationArgumentParser can be subclassed and this function subsequently overridden, to handle custom types.
776
777 If \a input isn't valid input for \a argument, this function returns a default constructed
778 QVariant.
779
780 \sa typeToName(), parse()
781 */
782QVariant QApplicationArgumentParser::convertToValue(const QApplicationArgument &argument,
783 const QString &input) const
784{
785 const int type = argument.type();
786
787 switch(type)
788 {
789 case QVariant::Bool:
790 {
791 if(input == QLatin1String("true") || input == QChar::fromLatin1(c: '1'))
792 return QVariant(true);
793 else if(input == QLatin1String("false") || input == QChar::fromLatin1(c: '0'))
794 return QVariant(false);
795 else
796 return QApplicationArgumentParserPrivate::conversionError(typeName: typeToName(argument), input);
797 }
798 case QVariant::RegExp:
799 {
800 QRegExp exp(input);
801
802 if(exp.isValid())
803 return QVariant(exp);
804 else
805 return QApplicationArgumentParserPrivate::conversionError(typeName: typeToName(argument), input);
806 }
807 case QVariant::Url:
808 {
809 const QUrl result(input);
810
811 if(result.isValid())
812 return QVariant(result);
813 else
814 return QApplicationArgumentParserPrivate::conversionError(typeName: typeToName(argument), input);
815 }
816 default:
817 {
818 QVariant result(input);
819
820 if(QApplicationArgumentParserPrivate::isBuiltinVariant(type) &&
821 result.convert(targetTypeId: type))
822 return result;
823 else
824 return QApplicationArgumentParserPrivate::conversionError(typeName: typeToName(argument), input);
825 }
826 }
827}
828
829/*!
830 This function is only of interest when subclassing.
831
832 convertToValue() calls this function when requiring a string for referring to \a type,
833 when generating user messages.
834
835 The implementation uses QMetaType::typeName() for most types, but special handles
836 some types, in order to let the message be better tailored for humans.
837
838 \sa convertToValue()
839 */
840QString QApplicationArgumentParser::typeToName(const QApplicationArgument &argument) const
841{
842 /* Personally I think nameForType() would be a better name but this is consistent
843 * with QVariant's function of the same name. */
844 const int type = argument.type();
845
846 switch(type)
847 {
848 case QVariant::RegExp:
849 return QApplicationArgumentParserPrivate::tr(sourceText: "regular expression");
850 case QVariant::Url:
851 return QLatin1String("URI");
852 case QVariant::String:
853 return QLatin1String("string");
854 default:
855 {
856 return QString::fromLatin1(str: QMetaType::typeName(type));
857 }
858 }
859}
860
861/*!
862 Returns the default value for \a argument. The default implementation returns
863 QApplicationArgument::defaultValue(), if \a argument has been added to this parser.
864
865 Overriding this function can be useful if creating the default value is resource
866 consuming, such as opening a file.
867 */
868QVariant QApplicationArgumentParser::defaultValue(const QApplicationArgument &argument) const
869{
870 return d->declaredArguments.value(akey: argument.name()).defaultValue();
871}
872
873/*!
874 Returns the count of how many times \a argument was used on the command line.
875
876 \sa has()
877 */
878int QApplicationArgumentParser::count(const QApplicationArgument &argument) const
879{
880 Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
881 d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
882 "The argument isn't known to the parser. Has addArgument() been called?");
883 return d->count(arg: argument);
884}
885
886/*!
887 Returns \c true if \a argument has been
888 specified one or more times on the command line, otherwise \a false.
889
890 \sa count()
891 */
892bool QApplicationArgumentParser::has(const QApplicationArgument &argument) const
893{
894 Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
895 d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
896 "The argument isn't known to the parser. Has addArgument() been called?");
897 return d->contains(arg: argument);
898}
899
900/*!
901 // TODO docs
902
903 \sa values()
904 */
905QVariant QApplicationArgumentParser::value(const QApplicationArgument &argument) const
906{
907 Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
908 d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
909 "The argument isn't known to the parser. Has addArgument() been called?");
910
911 const int len = d->usedArguments.count();
912
913 for(int i = 0; i < len; ++i)
914 {
915 if(d->usedArguments.at(i).first == argument)
916 return d->usedArguments.at(i).second;
917 }
918
919 return defaultValue(argument);
920}
921
922/*!
923 // TODO docs
924 \sa value()
925 */
926QVariantList QApplicationArgumentParser::values(const QApplicationArgument &argument) const
927{
928 Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
929 d->declaredNamelessArguments.contains(argument),
930 Q_FUNC_INFO,
931 "The argument isn't known to the parser. Has addArgument() been called?");
932
933 const int len = d->usedArguments.count();
934
935 QVariantList result;
936 for(int i = 0; i < len; ++i)
937 {
938 if(d->usedArguments.at(i).first == argument)
939 result.append(t: d->usedArguments.at(i).second);
940 }
941
942 // TODO how do we handle default values?
943 return result;
944}
945
946/*!
947 After parse() has been called, this function returns a code that can be used to
948 exit \c main() with. It returns zero upon success or if help was requested, and
949 otherwise a value signalling failure.
950 */
951QApplicationArgumentParser::ExitCode QApplicationArgumentParser::exitCode() const
952{
953 return d->exitCode;
954}
955
956/*!
957 This function is only of interest when subclassing.
958
959 Makes exitCode() return \a code.
960 */
961void QApplicationArgumentParser::setExitCode(ExitCode code)
962{
963 d->exitCode = code;
964}
965
966/*!
967 Sets the application description to \a description.
968
969 The application description is a sentence or two used for help and version
970 messages, that briefly describes the application.
971
972 The default is the empty string.
973 */
974void QApplicationArgumentParser::setApplicationDescription(const QString &description)
975{
976 d->applicationDescription = description;
977}
978
979/*!
980 Sets the application version to \a version.
981
982 This string, which is arbitrary but typically is "1.0" or so, is used when
983 generating a version statement.
984*/
985void QApplicationArgumentParser::setApplicationVersion(const QString &version)
986{
987 d->applicationVersion = version;
988}
989
990/*!
991 Writes out \a message to \c stderr.
992 */
993void QApplicationArgumentParser::message(const QString &message) const
994{
995 d->errorMessage(message);
996}
997
998QT_END_NAMESPACE
999

source code of qtxmlpatterns/tools/xmlpatterns/qapplicationargumentparser.cpp