1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
-
-
- #include "qcommandlineparser.h"
-
- #include <qcoreapplication.h>
- #include <qhash.h>
- #include <qvector.h>
- #include <qdebug.h>
- #if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
- # include <qt_windows.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
-
- QT_BEGIN_NAMESPACE
-
- typedef QHash<QString, int> NameHash_t;
-
- class QCommandLineParserPrivate
- {
- public:
- inline QCommandLineParserPrivate()
- : singleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions),
- builtinVersionOption(false),
- builtinHelpOption(false),
- needsParsing(true)
- { }
-
- bool parse(const QStringList &args);
- void checkParsed(const char *method);
- QStringList aliases(const QString &name) const;
- QString helpText() const;
- bool registerFoundOption(const QString &optionName);
- bool parseOptionValue(const QString &optionName, const QString &argument,
- QStringList::const_iterator *argumentIterator,
- QStringList::const_iterator argsEnd);
-
-
- QString errorText;
-
-
- QList<QCommandLineOption> commandLineOptionList;
-
-
- NameHash_t nameHash;
-
-
- QHash<int, QStringList> optionValuesHash;
-
-
- QStringList optionNames;
-
-
- QStringList positionalArgumentList;
-
-
- QStringList unknownOptionNames;
-
-
- QString description;
-
-
- struct PositionalArgumentDefinition
- {
- QString name;
- QString description;
- QString syntax;
- };
- QVector<PositionalArgumentDefinition> positionalArgumentDefinitions;
-
-
- QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode;
-
-
- bool builtinVersionOption;
-
-
- bool builtinHelpOption;
-
-
- bool needsParsing;
- };
-
- QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
- {
- const NameHash_t::const_iterator it = nameHash.constFind(optionName);
- if (it == nameHash.constEnd()) {
- qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName));
- return QStringList();
- }
- return commandLineOptionList.at(*it).names();
- }
-
-
-
-
- QCommandLineParser::QCommandLineParser()
- : d(new QCommandLineParserPrivate)
- {
- }
-
-
- QCommandLineParser::~QCommandLineParser()
- {
- delete d;
- }
-
-
-
-
- void QCommandLineParser::setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode)
- {
- d->singleDashWordOptionMode = singleDashWordOptionMode;
- }
-
-
- bool QCommandLineParser::addOption(const QCommandLineOption &option)
- {
- QStringList optionNames = option.names();
-
- if (!optionNames.isEmpty()) {
- foreach (const QString &name, optionNames) {
- if (d->nameHash.contains(name))
- return false;
- }
-
- d->commandLineOptionList.append(option);
-
- const int offset = d->commandLineOptionList.size() - 1;
- foreach (const QString &name, optionNames)
- d->nameHash.insert(name, offset);
-
- return true;
- }
-
- return false;
- }
-
-
- bool QCommandLineParser::addOptions(const QList<QCommandLineOption> &options)
- {
-
- bool result = true;
- for (QList<QCommandLineOption>::const_iterator it = options.begin(), end = options.end(); it != end; ++it)
- result &= addOption(*it);
- return result;
- }
-
-
- QCommandLineOption QCommandLineParser::addVersionOption()
- {
- QCommandLineOption opt(QStringList() << QString("v") << QString("version"), tr("Displays version information."));
- addOption(opt);
- d->builtinVersionOption = true;
- return opt;
- }
-
-
- QCommandLineOption QCommandLineParser::addHelpOption()
- {
- QCommandLineOption opt(QStringList()
- #ifdef Q_OS_WIN
- << QString("?")
- #endif
- << QString("h")
- << QString("help"), tr("Displays this help."));
- addOption(opt);
- d->builtinHelpOption = true;
- return opt;
- }
-
-
- void QCommandLineParser::setApplicationDescription(const QString &description)
- {
- d->description = description;
- }
-
-
- QString QCommandLineParser::applicationDescription() const
- {
- return d->description;
- }
-
-
- void QCommandLineParser::addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
- {
- QCommandLineParserPrivate::PositionalArgumentDefinition arg;
- arg.name = name;
- arg.description = description;
- arg.syntax = syntax.isEmpty() ? name : syntax;
- d->positionalArgumentDefinitions.append(arg);
- }
-
-
- void QCommandLineParser::clearPositionalArguments()
- {
- d->positionalArgumentDefinitions.clear();
- }
-
-
- bool QCommandLineParser::parse(const QStringList &arguments)
- {
- return d->parse(arguments);
- }
-
-
- QString QCommandLineParser::errorText() const
- {
- if (!d->errorText.isEmpty())
- return d->errorText;
- if (d->unknownOptionNames.count() == 1)
- return tr("Unknown option '%1'.").arg(d->unknownOptionNames.first());
- if (d->unknownOptionNames.count() > 1)
- return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(QString(", ")));
- return QString();
- }
-
- enum MessageType { UsageMessage, ErrorMessage };
-
- #if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
-
-
- static inline bool displayMessageBox()
- {
- if (GetConsoleWindow())
- return false;
- STARTUPINFO startupInfo;
- startupInfo.cb = sizeof(STARTUPINFO);
- GetStartupInfo(&startupInfo);
- return !(startupInfo.dwFlags & STARTF_USESTDHANDLES);
- }
- #endif
-
- static void showParserMessage(const QString &message, MessageType type)
- {
- #if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
- if (displayMessageBox()) {
- const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
- | (type == UsageMessage ? MB_ICONINFORMATION : MB_ICONERROR);
- QString title;
- if (QCoreApplication::instance())
- title = QCoreApplication::instance()->property("applicationDisplayName").toString();
- if (title.isEmpty())
- title = QCoreApplication::applicationName();
- MessageBoxW(0, reinterpret_cast<const wchar_t *>(message.utf16()),
- reinterpret_cast<const wchar_t *>(title.utf16()), flags);
- return;
- }
- #endif
- fputs(qPrintable(message), type == UsageMessage ? stdout : stderr);
- }
-
-
- void QCommandLineParser::process(const QStringList &arguments)
- {
- if (!d->parse(arguments)) {
- showParserMessage(errorText() + QLatin1Char('\n'), ErrorMessage);
- ::exit(EXIT_FAILURE);
- }
-
- if (d->builtinVersionOption && isSet(QString("version")))
- showVersion();
-
- if (d->builtinHelpOption && isSet(QString("help")))
- showHelp(EXIT_SUCCESS);
- }
-
-
- void QCommandLineParser::process(const QCoreApplication &app)
- {
-
- Q_UNUSED(app);
- process(QCoreApplication::arguments());
- }
-
- void QCommandLineParserPrivate::checkParsed(const char *method)
- {
- if (needsParsing)
- qWarning("QCommandLineParser: call process() or parse() before %s", method);
- }
-
-
- bool QCommandLineParserPrivate::registerFoundOption(const QString &optionName)
- {
- if (nameHash.contains(optionName)) {
- optionNames.append(optionName);
- return true;
- } else {
- unknownOptionNames.append(optionName);
- return false;
- }
- }
-
-
- bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, const QString &argument,
- QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
- {
- const QLatin1Char assignChar('=');
- const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
- if (nameHashIt != nameHash.constEnd()) {
- const int assignPos = argument.indexOf(assignChar);
- const NameHash_t::mapped_type optionOffset = *nameHashIt;
- const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
- if (withValue) {
- if (assignPos == -1) {
- ++(*argumentIterator);
- if (*argumentIterator == argsEnd) {
- errorText = QCommandLineParser::tr("Missing value after '%1'.").arg(argument);
- return false;
- }
- optionValuesHash[optionOffset].append(*(*argumentIterator));
- } else {
- optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
- }
- } else {
- if (assignPos != -1) {
- errorText = QCommandLineParser::tr("Unexpected value after '%1'.").arg(argument.left(assignPos));
- return false;
- }
- }
- }
- return true;
- }
-
-
- bool QCommandLineParserPrivate::parse(const QStringList &args)
- {
- needsParsing = false;
- bool error = false;
-
- const QString doubleDashString(QString("--"));
- const QLatin1Char dashChar('-');
- const QLatin1Char assignChar('=');
-
- bool doubleDashFound = false;
- errorText.clear();
- positionalArgumentList.clear();
- optionNames.clear();
- unknownOptionNames.clear();
- optionValuesHash.clear();
-
- if (args.isEmpty()) {
- qWarning("QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
- return false;
- }
-
- QStringList::const_iterator argumentIterator = args.begin();
- ++argumentIterator;
-
- for (; argumentIterator != args.end() ; ++argumentIterator) {
- QString argument = *argumentIterator;
-
- if (doubleDashFound) {
- positionalArgumentList.append(argument);
- } else if (argument.startsWith(doubleDashString)) {
- if (argument.length() > 2) {
- QString optionName = argument.mid(2).section(assignChar, 0, 0);
- if (registerFoundOption(optionName)) {
- if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
- error = true;
- } else {
- error = true;
- }
- } else {
- doubleDashFound = true;
- }
- } else if (argument.startsWith(dashChar)) {
- if (argument.size() == 1) {
- positionalArgumentList.append(argument);
- continue;
- }
- switch (singleDashWordOptionMode) {
- case QCommandLineParser::ParseAsCompactedShortOptions:
- {
- QString optionName;
- bool valueFound = false;
- for (int pos = 1 ; pos < argument.size(); ++pos) {
- optionName = argument.mid(pos, 1);
- if (!registerFoundOption(optionName)) {
- error = true;
- } else {
- const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
- Q_ASSERT(nameHashIt != nameHash.constEnd());
- const NameHash_t::mapped_type optionOffset = *nameHashIt;
- const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
- if (withValue) {
- if (pos + 1 < argument.size()) {
- if (argument.at(pos + 1) == assignChar)
- ++pos;
- optionValuesHash[optionOffset].append(argument.mid(pos + 1));
- valueFound = true;
- }
- break;
- }
- if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
- break;
- }
- }
- if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
- error = true;
- break;
- }
- case QCommandLineParser::ParseAsLongOptions:
- {
- const QString optionName = argument.mid(1).section(assignChar, 0, 0);
- if (registerFoundOption(optionName)) {
- if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
- error = true;
- } else {
- error = true;
- }
- break;
- }
- }
- } else {
- positionalArgumentList.append(argument);
- }
- if (argumentIterator == args.end())
- break;
- }
- return !error;
- }
-
-
-
- bool QCommandLineParser::isSet(const QString &name) const
- {
- d->checkParsed("isSet");
- if (d->optionNames.contains(name))
- return true;
- const QStringList aliases = d->aliases(name);
- foreach (const QString &optionName, d->optionNames) {
- if (aliases.contains(optionName))
- return true;
- }
- return false;
- }
-
-
-
- QString QCommandLineParser::value(const QString &optionName) const
- {
- d->checkParsed("value");
- const QStringList valueList = values(optionName);
-
- if (!valueList.isEmpty())
- return valueList.last();
-
- return QString();
- }
-
-
-
- QStringList QCommandLineParser::values(const QString &optionName) const
- {
- d->checkParsed("values");
- const NameHash_t::const_iterator it = d->nameHash.constFind(optionName);
- if (it != d->nameHash.constEnd()) {
- const int optionOffset = *it;
- QStringList values = d->optionValuesHash.value(optionOffset);
- if (values.isEmpty())
- values = d->commandLineOptionList.at(optionOffset).defaultValues();
- return values;
- }
-
- qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName));
- return QStringList();
- }
-
-
- bool QCommandLineParser::isSet(const QCommandLineOption &option) const
- {
-
- return !option.names().isEmpty() && isSet(option.names().first());
- }
-
-
- QString QCommandLineParser::value(const QCommandLineOption &option) const
- {
- return value(option.names().first());
- }
-
-
- QStringList QCommandLineParser::values(const QCommandLineOption &option) const
- {
- return values(option.names().first());
- }
-
-
-
- QStringList QCommandLineParser::positionalArguments() const
- {
- d->checkParsed("positionalArguments");
- return d->positionalArgumentList;
- }
-
-
-
- QStringList QCommandLineParser::optionNames() const
- {
- d->checkParsed("optionNames");
- return d->optionNames;
- }
-
-
-
- QStringList QCommandLineParser::unknownOptionNames() const
- {
- d->checkParsed("unknownOptionNames");
- return d->unknownOptionNames;
- }
-
-
- void QCommandLineParser::showVersion()
- {
- showParserMessage(QCoreApplication::applicationName() + QLatin1Char(' ')
- + QCoreApplication::applicationVersion() + QLatin1Char('\n'),
- UsageMessage);
- ::exit(EXIT_SUCCESS);
- }
-
-
- void QCommandLineParser::showHelp(int exitCode)
- {
- showParserMessage(d->helpText(), UsageMessage);
- ::exit(exitCode);
- }
-
-
- QString QCommandLineParser::helpText() const
- {
- return d->helpText();
- }
-
- static QString wrapText(const QString &names, int longestOptionNameString, const QString &description)
- {
- const QLatin1Char nl('\n');
- QString text = QString(" ") + names.leftJustified(longestOptionNameString) + QLatin1Char(' ');
- const int indent = text.length();
- int lineStart = 0;
- int lastBreakable = -1;
- const int max = 79 - indent;
- int x = 0;
- const int len = description.length();
-
- for (int i = 0; i < len; ++i) {
- ++x;
- const QChar c = description.at(i);
- if (c.isSpace())
- lastBreakable = i;
-
- int breakAt = -1;
- int nextLineStart = -1;
- if (x > max && lastBreakable != -1) {
-
- breakAt = lastBreakable;
- nextLineStart = lastBreakable + 1;
- } else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
-
- breakAt = i + 1;
- nextLineStart = breakAt;
- } else if (c == nl) {
-
- breakAt = i;
- nextLineStart = i + 1;
- }
-
- if (breakAt != -1) {
- const int numChars = breakAt - lineStart;
-
- if (lineStart > 0)
- text += QString(indent, QLatin1Char(' '));
- text += description.midRef(lineStart, numChars).toString() + nl;
- x = 0;
- lastBreakable = -1;
- lineStart = nextLineStart;
- if (lineStart < len && description.at(lineStart).isSpace())
- ++lineStart;
- i = lineStart;
- }
- }
-
- return text;
- }
-
- QString QCommandLineParserPrivate::helpText() const
- {
- const QLatin1Char nl('\n');
- QString text;
- const QString exeName = QCoreApplication::instance()->arguments().first();
- QString usage = exeName;
- if (!commandLineOptionList.isEmpty()) {
- usage += QLatin1Char(' ');
- usage += QCommandLineParser::tr("[options]");
- }
- foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) {
- usage += QLatin1Char(' ');
- usage += arg.syntax;
- }
- text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
- if (!description.isEmpty())
- text += description + nl;
- text += nl;
- if (!commandLineOptionList.isEmpty())
- text += QCommandLineParser::tr("Options:") + nl;
- QStringList optionNameList;
- int longestOptionNameString = 0;
- foreach (const QCommandLineOption &option, commandLineOptionList) {
- QStringList optionNames;
- foreach (const QString &optionName, option.names()) {
- if (optionName.length() == 1)
- optionNames.append(QLatin1Char('-') + optionName);
- else
- optionNames.append(QString("--") + optionName);
- }
- QString optionNamesString = optionNames.join(QString(", "));
- if (!option.valueName().isEmpty())
- optionNamesString += QString(" <") + option.valueName() + QLatin1Char('>');
- optionNameList.append(optionNamesString);
- longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length());
- }
- ++longestOptionNameString;
- for (int i = 0; i < commandLineOptionList.count(); ++i) {
- const QCommandLineOption &option = commandLineOptionList.at(i);
- text += wrapText(optionNameList.at(i), longestOptionNameString, option.description());
- }
- if (!positionalArgumentDefinitions.isEmpty()) {
- if (!commandLineOptionList.isEmpty())
- text += nl;
- text += QCommandLineParser::tr("Arguments:") + nl;
- foreach (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) {
- text += wrapText(arg.name, longestOptionNameString, arg.description);
- }
- }
- return text;
- }
-
- QT_END_NAMESPACE
|