source: trunk/tools/xmlpatterns/qapplicationargumentparser.cpp@ 932

Last change on this file since 932 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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