/**************************************************************************** | |
** | |
** 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$ | |
** GNU Lesser General Public License Usage | |
** 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. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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 |