source: branches/vendor/trolltech/qt/current/tools/xmlpatterns/qapplicationargumentparser.cpp @ 2

Last change on this file since 2 was 2, checked in by Dmitry A. Kuminov, 13 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 33.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file.  Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
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.