tools/xmlpatterns/qapplicationargumentparser.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    55 QT_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 */
       
   122 class QApplicationArgumentParserPrivate
       
   123 {
       
   124     Q_DECLARE_TR_FUNCTIONS(QApplicationArgumentParserPrivate)
       
   125 public:
       
   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 
       
   172 private:
       
   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 
       
   182 QApplicationArgument 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 
       
   212 int 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  */
       
   229 bool 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  */
       
   245 bool 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  */
       
   255 bool 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  */
       
   266 bool QApplicationArgumentParserPrivate::isSwitch(const QApplicationArgument &arg)
       
   267 {
       
   268     return arg.type() == QVariant::Invalid;
       
   269 }
       
   270 
       
   271 QVariant 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 
       
   278 bool 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 */
       
   286 QStringList 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 
       
   298 void 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  */
       
   312 template<>
       
   313 class qLess <QApplicationArgument>
       
   314 {
       
   315 public:
       
   316     inline bool operator()(const QApplicationArgument &o1,
       
   317                            const QApplicationArgument &o2) const
       
   318     {
       
   319         return o1.name().compare(o2.name()) < 0;
       
   320     }
       
   321 };
       
   322 
       
   323 void 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  */
       
   451 QString 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  */
       
   498 QList<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.
       
   516 These arguments should be passed directly from the \c main() function, and the decoding
       
   517 of 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  */
       
   521 QApplicationArgumentParser::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  */
       
   537 QApplicationArgumentParser::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  */
       
   549 QStringList 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 */
       
   564 void 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 */
       
   576 QList<QPair<QApplicationArgument, QVariant> > QApplicationArgumentParser::usedArguments() const
       
   577 {
       
   578     return d->usedArguments;
       
   579 }
       
   580 
       
   581 /*!
       
   582   Destructs this QApplicationArgumentParser instance.
       
   583  */
       
   584 QApplicationArgumentParser::~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  */
       
   597 void 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  */
       
   612 void 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  */
       
   626 QList<QApplicationArgument> QApplicationArgumentParser::declaredArguments() const
       
   627 {
       
   628     return d->declaredArguments.values();
       
   629 }
       
   630 
       
   631 bool 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  */
       
   659 bool 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  */
       
   809 QVariant 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  */
       
   867 QString 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  */
       
   898 QVariant 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  */
       
   908 int 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  */
       
   922 bool 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  */
       
   935 QVariant 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  */
       
   956 QVariantList 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  */
       
   981 QApplicationArgumentParser::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  */
       
   991 void 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  */
       
  1004 void 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 */
       
  1015 void QApplicationArgumentParser::setApplicationVersion(const QString &version)
       
  1016 {
       
  1017     d->applicationVersion = version;
       
  1018 }
       
  1019 
       
  1020 /*!
       
  1021  Writes out \a message to \c stderr.
       
  1022  */
       
  1023 void QApplicationArgumentParser::message(const QString &message) const
       
  1024 {
       
  1025     d->errorMessage(message);
       
  1026 }
       
  1027 
       
  1028 QT_END_NAMESPACE