summaryrefslogtreecommitdiff
path: root/tools/xmlpatterns/qapplicationargumentparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/xmlpatterns/qapplicationargumentparser.cpp')
-rw-r--r--tools/xmlpatterns/qapplicationargumentparser.cpp1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/tools/xmlpatterns/qapplicationargumentparser.cpp b/tools/xmlpatterns/qapplicationargumentparser.cpp
new file mode 100644
index 0000000..2f4f424
--- /dev/null
+++ b/tools/xmlpatterns/qapplicationargumentparser.cpp
@@ -0,0 +1,1028 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDebug>
+#include <QTextBoundaryFinder>
+#include <QCoreApplication>
+#include <QHash>
+#include <QPair>
+#include <QStringList>
+#include <QTextStream>
+#include <QUrl>
+
+#include "qapplicationargument_p.h"
+
+#include "qapplicationargumentparser_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QApplicationArgumentParser
+ \brief The QApplicationArgumentParser class parses the command
+ line arguments for an application.
+ \reentrant
+ \internal
+ \since 4.4
+
+ QApplicationArgumentParser simplifies writing command line applications by taking care of:
+
+ \list
+ \o Generating help and version arguments
+ \o Taking care of converting arguments to QVariant types, since each argument
+ has a type: QApplicationArgument::type()
+ \o Validates the command line such that the user operates on well-defined input. For instance,
+ that the argument is a valid integer if that is the case, that an argument does not
+ occur more times than allowed, and so on.
+ \o Allows customization through sub-classing.
+ \endlist
+
+ The user declares what arguments that can be given to the application with QApplicationArgument. Provided
+ with that information, QApplicationArgumentParser takes care of parsing the actual
+ command line, appropriately flag errors, generate help messages, and provide
+ convenient access to the values of the arguments.
+
+ The way to use it is to create a set of QApplicationArgument by ones choosing, call
+ addArgument() for each, and subsequently call parse(). If parse() returns \c false,
+ the caller should exit and return exitCode().
+
+ If parse() returns \c true the command line was successfully parsed, its
+ values are well-defined, and they can be spectated with count(),
+ has(), value() and values().
+
+ \snippet doc/src/snippets/code/tools_patternist_qapplicationargumentparser.cpp 0
+
+ For arguments without a name(such as filename passed to the \c ls utility on Linux) add a
+ QApplicationArgument that does not have a name. The minimum and maximum occurrences will be
+ respected as usual and the type applies too.
+
+ QApplicationArgumentParser always has two options builtin: \c version and \c help.
+
+ \section1 Changing Parsing Convention
+
+ QApplicationArgumentParser by default parses the command line in the style
+ of Qt's utilities, where arguments are preceded by a single dash, and identified
+ by a single name. However, in some cases it might be of interest to parse
+ another style, such as the well-established UNIX \c getopt convention(\c -l
+ and \c --long).
+
+ This can be achieved by sub-classing QApplicationArgumentParser and reimplementing
+ parse(). It would do the following:
+
+ \list
+ \o Call input() to retrieve the strings the user specified on the command line.
+ \o Call declaredArguments() to retrieve the arguments that the implementor has
+ decided can be specified.
+ \o Parse and validate the input. Salt and pepper as per taste.
+ \o If an error occurred, call setExitCode() and return \c false.
+ \o Otherwise, call setExitCode(Success), provide access to the
+ arguments by calling setUsedArguments(), and return \c true. If a
+ help message was requested, call setExitCode(Success) and return \c false.
+ \endlist
+
+ \sa QApplicationArgument, QCoreApplication
+*/
+class QApplicationArgumentParserPrivate
+{
+ Q_DECLARE_TR_FUNCTIONS(QApplicationArgumentParserPrivate)
+public:
+ // TODO Isn't it like ten times better with QHash<QApplicationArgument, QList<QVariant> >?
+ // TODO test QApplicationArgument::nameless()
+ typedef QList<QPair<QApplicationArgument, QVariant> > UsedList;
+
+ /*!
+ We initialize exitCode to ParseError such that we consciously flag success.
+ */
+ inline QApplicationArgumentParserPrivate(QApplicationArgumentParser *const master,
+ const QStringList &aInput) : exitCode(QApplicationArgumentParser::ParseError)
+ , input(aInput)
+ , q_ptr(master)
+ {
+ Q_ASSERT(!aInput.isEmpty());
+ }
+
+ QApplicationArgument nextNamelessArgument() const;
+ static QStringList argumentsFromLocal(const int argc, const char *const *const argv);
+
+ bool error(const QString &message);
+ static bool errorMessage(const QString &message);
+ static inline bool isSwitch(const QApplicationArgument &arg);
+ static inline QVariant conversionError(const QString &typeName,
+ const QString &input);
+ int count(const QApplicationArgument &arg) const;
+ bool contains(const QApplicationArgument &arg) const;
+ static inline bool isBuiltinVariant(const int type);
+ void displayVersion() const;
+ void displayHelp() const;
+ void parseNameless();
+ bool parseNamelessArguments(const QString &in);
+
+ QApplicationArgumentParser::ExitCode exitCode;
+ const QStringList input;
+
+ /*!
+ Since the QString is QApplicationArgument::name() anyway, why
+ not use a QSet?
+ */
+ QHash<QString, QApplicationArgument> declaredArguments;
+
+ QList<QApplicationArgument> declaredNamelessArguments;
+
+ UsedList usedArguments;
+ QString applicationDescription;
+ QString applicationVersion;
+
+private:
+ QApplicationArgumentParser *const q_ptr;
+ Q_DECLARE_PUBLIC(QApplicationArgumentParser)
+
+ static QString lineWrap(const QString &input,
+ const int leftIndent,
+ const int width);
+ static QList<QApplicationArgument> builtinArguments();
+};
+
+QApplicationArgument QApplicationArgumentParserPrivate::nextNamelessArgument() const
+{
+ /* Count how many nameless arguments we have so far. */
+ int count = 0;
+
+ for(int i = 0; i < usedArguments.count(); ++i)
+ {
+ if(usedArguments.at(i).first.isNameless())
+ ++count;
+ }
+
+ /* TODO this doesn't work for arguments that have more than one
+ * mandatory value(e.g nameless ones), since several values should
+ * then only count for one argument. */
+ for(int i = 0; i < declaredNamelessArguments.count(); ++i)
+ {
+ if(count)
+ {
+ /* Skip the ones we already have processed. */
+ --count;
+ continue;
+ }
+
+ if(declaredNamelessArguments.at(i).isNameless())
+ return declaredNamelessArguments.at(i);
+ }
+
+ return QApplicationArgument();
+}
+
+int QApplicationArgumentParserPrivate::count(const QApplicationArgument &arg) const
+{
+ const int len = usedArguments.count();
+ int count = 0;
+
+ for(int i = 0; i < len; ++i)
+ {
+ if(usedArguments.at(i).first == arg)
+ ++count;
+ }
+
+ return count;
+}
+
+/*!
+ Returns \c true if \a arg has appeared on the command line, not whether it has been declared.
+ */
+bool QApplicationArgumentParserPrivate::contains(const QApplicationArgument &arg) const
+{
+ const int len = usedArguments.count();
+
+ for(int i = 0; i < len; ++i)
+ {
+ if(usedArguments.at(i).first == arg)
+ return true;
+ }
+
+ return false;
+}
+
+/*!
+ Returns always \c false.
+ */
+bool QApplicationArgumentParserPrivate::error(const QString &message)
+{
+ exitCode = QApplicationArgumentParser::ParseError;
+ errorMessage(message);
+ return errorMessage(tr("Pass -help for information about the command line."));
+}
+
+/*!
+ Returns always \c false.
+ */
+bool QApplicationArgumentParserPrivate::errorMessage(const QString &message)
+{
+ QTextStream out(stderr, QIODevice::WriteOnly);
+ out << message << endl;
+ return false;
+}
+
+/*!
+ \internal
+ Determines whether \a arg carries a value or is on/off.
+ */
+bool QApplicationArgumentParserPrivate::isSwitch(const QApplicationArgument &arg)
+{
+ return arg.type() == QVariant::Invalid;
+}
+
+QVariant QApplicationArgumentParserPrivate::conversionError(const QString &typeName,
+ const QString &input)
+{
+ errorMessage(tr("Cannot convert %1 to type %2.").arg(input, typeName));
+ return QVariant();
+}
+
+bool QApplicationArgumentParserPrivate::isBuiltinVariant(const int type)
+{
+ return type < int(QVariant::UserType);
+}
+
+/*!
+ TODO Temporary, replace with a function in QCoreApplication.
+*/
+QStringList QApplicationArgumentParserPrivate::argumentsFromLocal(const int argc, const char *const *const argv)
+{
+ Q_ASSERT(argc >= 1);
+ Q_ASSERT(argv);
+ QStringList result;
+
+ for(int i = 0; i < argc; ++i)
+ result.append(QString::fromLocal8Bit(argv[i]));
+
+ return result;
+}
+
+void QApplicationArgumentParserPrivate::displayVersion() const
+{
+ QTextStream out(stderr);
+
+ out << tr("%1 version %2 using Qt %3").arg(QCoreApplication::applicationName(), applicationVersion, QString::fromAscii(qVersion()))
+ << endl;
+}
+
+/*!
+ \internal
+ \relates QApplicationArgument
+
+ qLess() functor for QApplicationArgument that considers the name.
+ */
+template<>
+class qLess <QApplicationArgument>
+{
+public:
+ inline bool operator()(const QApplicationArgument &o1,
+ const QApplicationArgument &o2) const
+ {
+ return o1.name().compare(o2.name()) < 0;
+ }
+};
+
+void QApplicationArgumentParserPrivate::displayHelp() const
+{
+ enum Constants
+ {
+ /**
+ * When we want to line wrap, 80 minus a couple of characters. This should
+ * be suitable for vt100 compatible terminals.
+ */
+ LineWrapAt = 78,
+
+ /**
+ * The initial " -" for each option.
+ */
+ IndentPadding = 3,
+
+ /**
+ * Pad for the brackets and space we use when we have a type.
+ */
+ ValueArgumentPadding = 4
+ };
+
+ QList<QApplicationArgument> args(declaredArguments.values());
+ args += builtinArguments();
+
+ /* Sort them, such that we get the nameless options at the end, and it
+ * generally looks tidy. */
+ qSort(args);
+
+ /* This is the basic approach:
+ * Switches:
+ * -name description
+ * Value arguments:
+ * -name <name-of-value-type> description
+ *
+ * Nameless arguments
+ * name <type> description
+ *
+ * It all line-wraps at OutputWidth and the description is indented,
+ * where the highest indent is the length of the name plus length of the name
+ * of the type. */
+
+ /* First we find the name with the largest width. */
+ int maxWidth = 0;
+
+ QList<QApplicationArgument> nameless(declaredNamelessArguments);
+ qSort(nameless);
+
+ /* Note, here the nameless arguments appear last, but are sorted
+ * with themselves. */
+ QList<QApplicationArgument> allArgs(args + nameless);
+ const int allArgsCount = allArgs.count();
+
+ for(int i = 0; i < allArgsCount; ++i)
+ {
+ const QApplicationArgument &at = allArgs.at(i);
+ const int nameLength = at.name().length();
+ const QString typeName(q_ptr->typeToName(at));
+ const int typeNameLength = typeName.length();
+ const int padding = at.type() == QVariant::Invalid ? 0 : ValueArgumentPadding;
+ maxWidth = qMax(maxWidth, nameLength + typeNameLength + padding);
+ }
+
+ QTextStream out(stderr);
+ out << endl
+ << QString(IndentPadding, QLatin1Char(' '))
+ << QCoreApplication::applicationName()
+ << QLatin1String(" -- ")
+ << applicationDescription
+ << endl;
+ // TODO synopsis
+
+ /* One extra so we get some space between the overview and the options. */
+ out << endl;
+
+ const int indentWidth = maxWidth + 3;
+
+ /* Ok, print them out. */
+ for(int i = 0; i < allArgsCount; ++i)
+ {
+ const QApplicationArgument &at = allArgs.at(i);
+ /* " -name ". Indent a bit first, inspired by Qt's moc. */
+ const QString &name = at.name();
+ QString prolog(QLatin1String(" "));
+
+ /* We have a special case for the single dash. */
+ if(name == QChar::fromLatin1('-'))
+ prolog.append(name);
+ else
+ {
+ if(!at.isNameless())
+ prolog.append(QLatin1Char('-'));
+
+ prolog.append(name + QLatin1Char(' '));
+ }
+
+ if(at.type() != QVariant::Invalid)
+ {
+ /* It's not a switch, it has a value. */
+
+ /* Do we have a default value? If so, the argument is optional. */
+ const QString typeName(q_ptr->typeToName(at));
+
+ if(at.defaultValue().isValid())
+ prolog.append(QLatin1Char('[') + typeName + QLatin1Char(']'));
+ else
+ prolog.append(QLatin1Char('<') + typeName + QLatin1Char('>'));
+ // TODO Don't we want to display the default value?
+
+ prolog.append(QLatin1Char(' '));
+ }
+
+ prolog = prolog.leftJustified(indentWidth);
+
+ out << prolog
+ << lineWrap(at.description(), indentWidth, LineWrapAt)
+ << endl;
+ }
+}
+
+/*!
+ Line wraps \a input and indents each line with \a leftIndent spaces, such that
+ the width does not go beyond \a maxWidth.
+
+ The addition of line endings is accounted for by the caller.
+
+ With QTextBoundaryFinder our line wrapping is relatively fancy, since it
+ does it the Unicode-way.
+ */
+QString QApplicationArgumentParserPrivate::lineWrap(const QString &input,
+ const int leftIndent,
+ const int maxWidth)
+{
+ const QString indent(QString(leftIndent, QLatin1Char(' ')));
+ const int len = input.length();
+ const int textWidth = maxWidth - leftIndent;
+
+ QString output;
+ QTextBoundaryFinder wrapFinder(QTextBoundaryFinder::Line, input);
+ wrapFinder.setPosition(textWidth);
+
+ if(input.length() + leftIndent <= maxWidth)
+ return input;
+
+ int from = wrapFinder.toPreviousBoundary();
+ output.append(input.left(from));
+
+ while(true)
+ {
+ if((len - from) + leftIndent > maxWidth)
+ {
+ /* We need to line wrap. */
+ wrapFinder.setPosition(from + textWidth);
+ const int currentWidthPos = wrapFinder.toPreviousBoundary();
+
+ output.append(QLatin1Char('\n'));
+ output.append(indent);
+ output.append(input.mid(from, currentWidthPos - from).trimmed());
+ from += (currentWidthPos - from);
+ }
+ else
+ {
+ /* Append the remains. */
+ output.append(QLatin1Char('\n'));
+ output.append(indent);
+ output.append(input.mid(from).trimmed());
+ break;
+ }
+ }
+
+ return output;
+}
+
+/*!
+ Returns a list with the builtin options that the parser has
+ */
+QList<QApplicationArgument> QApplicationArgumentParserPrivate::builtinArguments()
+{
+ QList<QApplicationArgument> result;
+
+ result.append(QApplicationArgument(QLatin1String("help"),
+ QLatin1String("Displays this help.")));
+ result.append(QApplicationArgument(QLatin1String("version"),
+ QLatin1String("Displays version information.")));
+
+ result.append(QApplicationArgument(QLatin1String("-"),
+ QLatin1String("When appearing, any following options are not interpreted as switches.")));
+ return result;
+}
+
+/* TODO, I don't think we want this function in a public API. Add it first when there is a demand. */
+
+/*!
+ Creates a QApplicationArgumentParser that will parse the input in \a argc and \a argv.
+These arguments should be passed directly from the \c main() function, and the decoding
+of the input will be taken care of appropriately, depending on platform.
+
+ It is preferred to use the QStringList overload, in case the input is in the form of QStrings.
+ */
+QApplicationArgumentParser::QApplicationArgumentParser(int argc, char **argv) : d(new QApplicationArgumentParserPrivate(this, QApplicationArgumentParserPrivate::argumentsFromLocal(argc, argv)))
+{
+ Q_ASSERT_X(argv, Q_FUNC_INFO, "Argv cannot be null.");
+ Q_ASSERT_X(argc >= 1, Q_FUNC_INFO,
+ "argc must at least contain the application name. "
+ "Use the QStringList overload instead.");
+}
+
+/*!
+ \overload
+
+ Creates a QApplicationArgumentParser that will parse \a input. That is, instead of passing in \c argc
+ and \c argv, one can pass in a QStringList.
+
+ The caller guarantees that the first string in \a input is the name of the application.
+ */
+QApplicationArgumentParser::QApplicationArgumentParser(const QStringList &input) : d(new QApplicationArgumentParserPrivate(this, input))
+{
+ Q_ASSERT_X(input.count() >= 1, Q_FUNC_INFO,
+ "The input must at least contain the application name.");
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ Returns the strings that the user specified when starting the application. The first string
+ in the list is always the application name.
+ */
+QStringList QApplicationArgumentParser::input() const
+{
+ Q_ASSERT_X(d->input.count() >= 1, Q_FUNC_INFO, "Internal error, this should always hold true");
+ return d->input;
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ Sets the arguments that the user actually used on the command line to \a arguments.
+ The parse() function should call this, such that the result afterwards can be inspected
+ with for instance has() or count().
+
+\sa usedArguments()
+*/
+void QApplicationArgumentParser::setUsedArguments(const QList<QPair<QApplicationArgument, QVariant> > &arguments)
+{
+ d->usedArguments = arguments;
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ Returns the arguments that the user used on the command line.
+
+\sa setUsedArguments()
+*/
+QList<QPair<QApplicationArgument, QVariant> > QApplicationArgumentParser::usedArguments() const
+{
+ return d->usedArguments;
+}
+
+/*!
+ Destructs this QApplicationArgumentParser instance.
+ */
+QApplicationArgumentParser::~QApplicationArgumentParser()
+{
+ delete d;
+}
+
+/*!
+ Adds \a argument to this parser.
+
+ This function is provided for convenience. It is equivalent to creating a QList
+ containing \a argument, append the existing arguments, and then call setDeclaredArguments() with the list.
+
+ \sa setDeclaredArguments()
+ */
+void QApplicationArgumentParser::addArgument(const QApplicationArgument &argument)
+{
+ if(argument.isNameless())
+ d->declaredNamelessArguments.append(argument);
+ else
+ d->declaredArguments.insert(argument.name(), argument);
+}
+
+/*!
+ Makes the parser recognize all arguments in \a arguments.
+
+ Any arguments previously set, are discarded.
+
+ \sa addArgument(), declaredArguments()
+ */
+void QApplicationArgumentParser::setDeclaredArguments(const QList<QApplicationArgument> &arguments)
+{
+ // TODO If we have a QHash internally, why not use it in the public API too?
+ const int len = arguments.count();
+
+ for(int i = 0; i < len; ++i)
+ d->declaredArguments.insert(arguments.at(i).name(), arguments.at(i));
+}
+
+/*!
+ Returns the arguments that this parser recognizes.
+
+ \sa addArgument(), setDeclaredArguments()
+ */
+QList<QApplicationArgument> QApplicationArgumentParser::declaredArguments() const
+{
+ return d->declaredArguments.values();
+}
+
+bool QApplicationArgumentParserPrivate::parseNamelessArguments(const QString &in)
+{
+ /* It's a nameless options, such as simply "value". */
+ const QApplicationArgument nameless(nextNamelessArgument());
+
+ const QVariant val(q_ptr->convertToValue(nameless, in));
+ if(val.isValid())
+ {
+ usedArguments.append(qMakePair(nameless, val));
+ return true;
+ }
+ else
+ return false; // TODO error msg?
+}
+
+/*!
+ Parses input() together with declaredArguments() and returns \c false if the caller
+ should exit immediately, which is the case of which an error was encountered or
+ help or the version was requested.
+
+ In the case of \c true was returned, valid arguments were supplied, and they can
+ be requested with functions like value(), values(), count() and has().
+
+ parse() must only be called once per QApplicationArgumentParser instance. The
+ second time it's called, the effects and return value are undefined.
+
+ \sa convertToValue(), typeToName()
+ */
+bool QApplicationArgumentParser::parse()
+{
+ const QChar sep(QLatin1Char('-'));
+ const int inputCount = d->input.count();
+
+ /* We skip the first entry, which is the application name. */
+ int i = 1;
+
+ for(; i < inputCount; ++i)
+ {
+ const QString &in = d->input.at(i);
+
+ /* We have a single '-', signalling that the succeeding are not options. */
+ if(in == sep)
+ {
+ ++i;
+
+ for(; i < inputCount; ++i)
+ {
+ if(!d->parseNamelessArguments(d->input.at(i)))
+ return false;
+ /* Process nameless options. Have code for this elsewhere, factor it out. */
+ }
+
+ break;
+ }
+
+ if(in.startsWith(sep)) /* It is "-name". */
+ {
+ const QString name(in.mid(1));
+
+ if(name == QLatin1String("help"))
+ {
+ setExitCode(Success);
+ d->displayHelp();
+ return false;
+ }
+ else if(name == QLatin1String("version"))
+ {
+ setExitCode(Success);
+ d->displayVersion();
+ return false;
+ }
+
+ if(!d->declaredArguments.contains(name))
+ return d->error(QApplicationArgumentParserPrivate::tr("\"%1\" is an unknown argument.").arg(name));
+
+ const QApplicationArgument &arg = d->declaredArguments.value(name);
+ const int argCount = d->count(arg) + 1;
+ const int max = arg.maximumOccurrence();
+
+ if(argCount > max && max != -1)
+ {
+ /* Let's tailor the message for a common case. */
+ if(max == 1)
+ return d->error(QApplicationArgumentParserPrivate::tr("\"%1\" can only be used once.").arg(name));
+ else
+ return d->error(QApplicationArgumentParserPrivate::tr("\"%1\" can only be used %2 times.").arg(name, QString::number(max)));
+ }
+
+ if(QApplicationArgumentParserPrivate::isSwitch(arg))
+ {
+ d->usedArguments.append(qMakePair(arg, QVariant()));
+ continue;
+ }
+ else
+ {
+ ++i;
+
+ if(i == inputCount)
+ return d->error(QApplicationArgumentParserPrivate::tr("\"%1\" must be followed by a value.").arg(name));
+
+ /* Okidoki, got a value, always something. Let's
+ * see if it validates. */
+ const QString &value = d->input.at(i);
+
+ const QVariant val(convertToValue(arg, value));
+ if(val.isValid())
+ {
+ d->usedArguments.append(qMakePair(arg, val));
+ continue;
+ }
+ else
+ return false; // TODO error msg?
+ }
+ }
+ else
+ {
+ if(!d->parseNamelessArguments(in))
+ return false;
+ }
+ }
+
+ /* Check that all arguments that have been declared as mandatory, are actually
+ * specified. */
+ const QList<QApplicationArgument> declaredArguments(d->declaredArguments.values() + d->declaredNamelessArguments);
+ const int len = declaredArguments.count();
+ for(int i = 0; i < len; ++i)
+ {
+ const QApplicationArgument &at = declaredArguments.at(i);
+ const int min = at.minimumOccurrence();
+ const int max = at.maximumOccurrence(); // TODO What about infinite? -1
+ if(min == 0)
+ continue;
+ else
+ {
+ const int usedLen = d->usedArguments.count();
+ int useCount = 0;
+
+ for(int u = 0; u < usedLen; ++u)
+ {
+ const QPair<QApplicationArgument, QVariant> &used = d->usedArguments.at(u);
+ if(used.first == at)
+ ++useCount;
+ }
+
+ const QString originalName(at.name());
+ const QString effectiveName(originalName.isEmpty() ? QLatin1Char('<') + typeToName(at) + QLatin1Char('>') : originalName);
+
+ if(useCount < min)
+ {
+ /* For nameless options, we use the type as the name. Looks better. */
+ return d->error(QApplicationArgumentParserPrivate::tr("%1 must occur at least %2 times, therefore %3 times is insufficient.", "The number is for %2.", min)
+ .arg(effectiveName, QString::number(min), QString::number(useCount)));
+ }
+ else if(useCount > max)
+ return d->error(QApplicationArgumentParserPrivate::tr("%1 can occur at most %2 times", "", max).arg(effectiveName, QString::number(max)));
+ }
+ }
+
+ d->exitCode = Success;
+ return true;
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ parse() calls this function each time a value, that is \a input, on the command line needs to be
+ validated and subsequently converted to the type of \a argument. A descriptive error message will
+ be outputted if \a input cannot be converted to the required type.
+
+ The default implementation uses QVariant::canConvert() and QVariant::convert() for doing conversions.
+
+ QApplicationArgumentParser can be subclassed and this function subsequently overridden, to handle custom types.
+
+ If \a input isn't valid input for \a argument, this function returns a default constructed
+ QVariant.
+
+ \sa typeToName(), parse()
+ */
+QVariant QApplicationArgumentParser::convertToValue(const QApplicationArgument &argument,
+ const QString &input) const
+{
+ const int type = argument.type();
+
+ switch(type)
+ {
+ case QVariant::Bool:
+ {
+ if(input == QLatin1String("true") || input == QChar::fromLatin1('1'))
+ return QVariant(true);
+ else if(input == QLatin1String("false") || input == QChar::fromLatin1('0'))
+ return QVariant(false);
+ else
+ return QApplicationArgumentParserPrivate::conversionError(typeToName(argument), input);
+ }
+ case QVariant::RegExp:
+ {
+ const QRegExp exp(input);
+
+ if(exp.isValid())
+ return QVariant(exp);
+ else
+ return QApplicationArgumentParserPrivate::conversionError(typeToName(argument), input);
+ }
+ case QVariant::Url:
+ {
+ const QUrl result(QUrl::fromEncoded(input.toLatin1()));
+
+ if(result.isValid())
+ return QVariant(result);
+ else
+ return QApplicationArgumentParserPrivate::conversionError(typeToName(argument), input);
+ }
+ default:
+ {
+ QVariant result(input);
+
+ if(QApplicationArgumentParserPrivate::isBuiltinVariant(type) &&
+ result.convert(QVariant::Type(type)))
+ return result;
+ else
+ return QApplicationArgumentParserPrivate::conversionError(typeToName(argument), input);
+ }
+ }
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ convertToValue() calls this function when requiring a string for referring to \a type,
+ when generating user messages.
+
+ The implementation uses QVariant::typeToName() for most types, but special handles
+ some types, in order to let the message be better tailored for humans.
+
+ \sa convertToValue()
+ */
+QString QApplicationArgumentParser::typeToName(const QApplicationArgument &argument) const
+{
+ /* Personally I think nameForType() would be a better name but this is consistent
+ * with QVariant's function of the same name. */
+ const int type = argument.type();
+
+ switch(type)
+ {
+ case QVariant::RegExp:
+ return QApplicationArgumentParserPrivate::tr("regular expression");
+ case QVariant::Url:
+ return QLatin1String("URI");
+ case QVariant::String:
+ return QLatin1String("string");
+ default:
+ {
+ if(QApplicationArgumentParserPrivate::isBuiltinVariant(type))
+ return QString::fromLatin1(QVariant::typeToName(QVariant::Type(type)));
+ else
+ return QLatin1String(QVariant(type, static_cast<void *>(0)).typeName());
+ }
+ }
+}
+
+/*!
+ Returns the default value for \a argument. The default implementation returns
+ QApplicationArgument::defaultValue(), if \a argument has been added to this parser.
+
+ Overriding this function can be useful if creating the default value is resource
+ consuming, such as opening a file.
+ */
+QVariant QApplicationArgumentParser::defaultValue(const QApplicationArgument &argument) const
+{
+ return d->declaredArguments.value(argument.name()).defaultValue();
+}
+
+/*!
+ Returns the count of how many times \a argument was used on the command line.
+
+ \sa has()
+ */
+int QApplicationArgumentParser::count(const QApplicationArgument &argument) const
+{
+ Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
+ d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
+ "The argument isn't known to the parser. Has addArgument() been called?");
+ return d->count(argument);
+}
+
+/*!
+ Returns \c true if \a argument has been
+ specified one or more times on the command line, otherwise \a false.
+
+ \sa count()
+ */
+bool QApplicationArgumentParser::has(const QApplicationArgument &argument) const
+{
+ Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
+ d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
+ "The argument isn't known to the parser. Has addArgument() been called?");
+ return d->contains(argument);
+}
+
+/*!
+ // TODO docs
+
+ \sa values()
+ */
+QVariant QApplicationArgumentParser::value(const QApplicationArgument &argument) const
+{
+ Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
+ d->declaredNamelessArguments.contains(argument), Q_FUNC_INFO,
+ "The argument isn't known to the parser. Has addArgument() been called?");
+
+ const int len = d->usedArguments.count();
+
+ for(int i = 0; i < len; ++i)
+ {
+ if(d->usedArguments.at(i).first == argument)
+ return d->usedArguments.at(i).second;
+ }
+
+ return defaultValue(argument);
+}
+
+/*!
+ // TODO docs
+ \sa value()
+ */
+QVariantList QApplicationArgumentParser::values(const QApplicationArgument &argument) const
+{
+ Q_ASSERT_X(d->declaredArguments.contains(argument.name()) ||
+ d->declaredNamelessArguments.contains(argument),
+ Q_FUNC_INFO,
+ "The argument isn't known to the parser. Has addArgument() been called?");
+
+ const int len = d->usedArguments.count();
+
+ QVariantList result;
+ for(int i = 0; i < len; ++i)
+ {
+ if(d->usedArguments.at(i).first == argument)
+ result.append(d->usedArguments.at(i).second);
+ }
+
+ // TODO how do we handle default values?
+ return result;
+}
+
+/*!
+ After parse() has been called, this function returns a code that can be used to
+ exit \c main() with. It returns zero upon success or if help was requested, and
+ otherwise a value signalling failure.
+ */
+QApplicationArgumentParser::ExitCode QApplicationArgumentParser::exitCode() const
+{
+ return d->exitCode;
+}
+
+/*!
+ This function is only of interest when subclassing.
+
+ Makes exitCode() return \a code.
+ */
+void QApplicationArgumentParser::setExitCode(ExitCode code)
+{
+ d->exitCode = code;
+}
+
+/*!
+ Sets the application description to \a description.
+
+ The application description is a sentence or two used for help and version
+ messages, that briefly describes the application.
+
+ The default is the empty string.
+ */
+void QApplicationArgumentParser::setApplicationDescription(const QString &description)
+{
+ d->applicationDescription = description;
+}
+
+/*!
+ Sets the application version to \a version.
+
+ This string, which is arbitrary but typically is "1.0" or so, is used when
+ generating a version statement.
+*/
+void QApplicationArgumentParser::setApplicationVersion(const QString &version)
+{
+ d->applicationVersion = version;
+}
+
+/*!
+ Writes out \a message to \c stderr.
+ */
+void QApplicationArgumentParser::message(const QString &message) const
+{
+ d->errorMessage(message);
+}
+
+QT_END_NAMESPACE