diff --git a/examples/network/dnslookup/dnslookup.cpp b/examples/network/dnslookup/dnslookup.cpp index 202a5f9580..003a3e3028 100644 --- a/examples/network/dnslookup/dnslookup.cpp +++ b/examples/network/dnslookup/dnslookup.cpp @@ -45,14 +45,101 @@ #include #include #include +#include +#include #include -static void usage() { - printf("Qt DNS example - performs DNS lookups\n" - "Usage: dnslookup [-t ] [-s nameserver] name\n\n"); +static int typeFromParameter(const QString &type) +{ + if (type == "a") + return QDnsLookup::A; + if (type == "aaaa") + return QDnsLookup::AAAA; + if (type == "any") + return QDnsLookup::ANY; + if (type == "cname") + return QDnsLookup::CNAME; + if (type == "mx") + return QDnsLookup::MX; + if (type == "ns") + return QDnsLookup::NS; + if (type == "ptr") + return QDnsLookup::PTR; + if (type == "srv") + return QDnsLookup::SRV; + if (type == "txt") + return QDnsLookup::TXT; + return -1; } +//! [0] + +enum CommandLineParseResult +{ + CommandLineOk, + CommandLineError, + CommandLineVersionRequested, + CommandLineHelpRequested +}; + +CommandLineParseResult parseCommandLine(QCommandLineParser &parser, DnsQuery *query, QString *errorMessage) +{ + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + const QCommandLineOption nameServerOption("n", "The name server to use.", "nameserver"); + parser.addOption(nameServerOption); + const QCommandLineOption typeOption("t", "The lookup type.", "type"); + parser.addOption(typeOption); + parser.addPositionalArgument("name", "The name to look up."); + const QCommandLineOption helpOption = parser.addHelpOption(); + const QCommandLineOption versionOption = parser.addVersionOption(); + + if (!parser.parse(QCoreApplication::arguments())) { + *errorMessage = parser.errorText(); + return CommandLineError; + } + + if (parser.isSet(versionOption)) + return CommandLineVersionRequested; + + if (parser.isSet(helpOption)) + return CommandLineHelpRequested; + + if (parser.isSet(nameServerOption)) { + const QString nameserver = parser.value(nameServerOption); + query->nameServer = QHostAddress(nameserver); + if (query->nameServer.isNull() || query->nameServer.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { + *errorMessage = "Bad nameserver address: " + nameserver; + return CommandLineError; + } + } + + if (parser.isSet(typeOption)) { + const QString typeParameter = parser.value(typeOption); + const int type = typeFromParameter(typeParameter.toLower()); + if (type < 0) { + *errorMessage = "Bad record type: " + typeParameter; + return CommandLineError; + } + query->type = static_cast(type); + } + + const QStringList positionalArguments = parser.positionalArguments(); + if (positionalArguments.isEmpty()) { + *errorMessage = "Argument 'name' missing."; + return CommandLineError; + } + if (positionalArguments.size() > 1) { + *errorMessage = "Several 'name' arguments specified."; + return CommandLineError; + } + query->name = positionalArguments.first(); + + return CommandLineOk; +} + +//! [0] + DnsManager::DnsManager() { dns = new QDnsLookup(this); @@ -61,55 +148,11 @@ DnsManager::DnsManager() void DnsManager::execute() { - QStringList args = QCoreApplication::instance()->arguments(); - args.takeFirst(); - // lookup type - dns->setType(QDnsLookup::A); - if (args.size() > 1 && args.first() == "-t") { - args.takeFirst(); - const QString type = args.takeFirst().toLower(); - if (type == "a") - dns->setType(QDnsLookup::A); - else if (type == "aaaa") - dns->setType(QDnsLookup::AAAA); - else if (type == "any") - dns->setType(QDnsLookup::ANY); - else if (type == "cname") - dns->setType(QDnsLookup::CNAME); - else if (type == "mx") - dns->setType(QDnsLookup::MX); - else if (type == "ns") - dns->setType(QDnsLookup::NS); - else if (type == "ptr") - dns->setType(QDnsLookup::PTR); - else if (type == "srv") - dns->setType(QDnsLookup::SRV); - else if (type == "txt") - dns->setType(QDnsLookup::TXT); - else { - printf("Bad record type: %s\n", qPrintable(type)); - QCoreApplication::instance()->quit(); - return; - } - } - if (args.size() > 1 && args.first() == "-s") { - args.takeFirst(); - const QString ns = args.takeFirst(); - QHostAddress nameserver(ns); - if (nameserver.isNull() || nameserver.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { - printf("Bad nameserver address: %s\n", qPrintable(ns)); - QCoreApplication::instance()->quit(); - return; - } - dns->setNameserver(nameserver); - } - if (args.isEmpty()) { - usage(); - QCoreApplication::instance()->quit(); - return; - } - dns->setName(args.takeFirst()); + dns->setType(query.type); + if (!query.nameServer.isNull()) + dns->setNameserver(query.nameServer); + dns->setName(query.name); dns->lookup(); } @@ -159,7 +202,33 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); +//! [1] + QCoreApplication::setApplicationVersion(QT_VERSION_STR); + QCoreApplication::setApplicationName(QCoreApplication::translate("QDnsLookupExample", "DNS Lookup Example")); + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("QDnsLookupExample", "An example demonstrating the class QDnsLookup.")); + DnsQuery query; + QString errorMessage; + switch (parseCommandLine(parser, &query, &errorMessage)) { + case CommandLineOk: + break; + case CommandLineError: + fputs(qPrintable(errorMessage), stderr); + fputs("\n\n", stderr); + fputs(qPrintable(parser.helpText()), stderr); + return 1; + case CommandLineVersionRequested: + printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), + qPrintable(QCoreApplication::applicationVersion())); + return 0; + case CommandLineHelpRequested: + parser.showHelp(); + Q_UNREACHABLE(); + } +//! [1] + DnsManager manager; + manager.setQuery(query); QTimer::singleShot(0, &manager, SLOT(execute())); return app.exec(); diff --git a/examples/network/dnslookup/dnslookup.h b/examples/network/dnslookup/dnslookup.h index d76756bad0..4d0232be8a 100644 --- a/examples/network/dnslookup/dnslookup.h +++ b/examples/network/dnslookup/dnslookup.h @@ -38,11 +38,21 @@ ** ****************************************************************************/ -#include +#include +#include -QT_BEGIN_NAMESPACE -class QDnsLookup; -QT_END_NAMESPACE +//! [0] + +struct DnsQuery +{ + DnsQuery() : type(QDnsLookup::A) {} + + QDnsLookup::Type type; + QHostAddress nameServer; + QString name; +}; + +//! [0] class DnsManager : public QObject { @@ -50,6 +60,7 @@ class DnsManager : public QObject public: DnsManager(); + void setQuery(const DnsQuery &q) { query = q; } public slots: void execute(); @@ -57,5 +68,6 @@ public slots: private: QDnsLookup *dns; + DnsQuery query; }; diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 18fdfb18f3..2ad24d33b1 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -37,7 +37,8 @@ exampledirs += \ snippets \ ../../../examples/threads/ \ ../../../examples/tools/ \ - ../../../examples/json/ + ../../../examples/json/ \ + ../../../examples/network/dnslookup imagedirs += images diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp index c860b4d155..505ab5f46d 100644 --- a/src/corelib/tools/qcommandlineparser.cpp +++ b/src/corelib/tools/qcommandlineparser.cpp @@ -187,6 +187,78 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const QCoreApplication::arguments() before QCommandLineParser defines the \c{profile} option and parses the command line. + \section2 How to Use QCommandLineParser in Complex Applications + + In practice, additional error checking needs to be performed on the positional + arguments and option values. For example, ranges of numbers should be checked. + + It is then advisable to introduce a function to do the command line parsing + which takes a struct or class receiving the option values returning an + enumeration representing the result. The dnslookup example of the QtNetwork + module illustrates this: + + \snippet dnslookup.h 0 + + \snippet dnslookup.cpp 0 + + In the main function, help should be printed to the standard output if the help option + was passed and the application should return the exit code 0. + + If an error was detected, the error message should be printed to the standard + error output and the application should return an exit code other than 0. + + \snippet dnslookup.cpp 1 + + A special case to consider here are GUI applications on Windows and mobile + platforms. These applications may not use the standard output or error channels + since the output is either discarded or not accessible. + + For such GUI applications, it is recommended to display help texts and error messages + using a QMessageBox. To preserve the formatting of the help text, rich text + with \c
 elements should be used:
+
+    \code
+
+    switch (parseCommandLine(parser, &query, &errorMessage)) {
+    case CommandLineOk:
+        break;
+    case CommandLineError:
+#ifdef Q_OS_WIN
+        QMessageBox::warning(0, QGuiApplication::applicationDisplayName(),
+                             "

" + errorMessage + "

"
+                             + parser.helpText() + "
"); +#else + fputs(qPrintable(errorMessage), stderr); + fputs("\n\n", stderr); + fputs(qPrintable(parser.helpText()), stderr); +#endif + return 1; + case CommandLineVersionRequested: +#ifdef Q_OS_WIN + QMessageBox::information(0, QGuiApplication::applicationDisplayName(), + QGuiApplication::applicationDisplayName() + ' ' + + QCoreApplication::applicationVersion()); +#else + printf("%s %s\n", QGuiApplication::applicationDisplayName(), + qPrintable(QCoreApplication::applicationVersion())); +#endif + return 0; + case CommandLineHelpRequested: +#ifdef Q_OS_WIN + QMessageBox::warning(0, QGuiApplication::applicationDisplayName(), + "
"
+                             + parser.helpText() + "
"); + return 0; +#else + parser.showHelp(); + Q_UNREACHABLE(); +#endif + } + \endcode + + However, this does not apply to the dnslookup example, because it is a + console application. + \sa QCommandLineOption, QCoreApplication */