6.7.1.  Derivation and ArgumentList

[ fromfile: argumentlist.xml id: argumentlist ]

In this section, we present the ArgumentList class, an example from libutils (Section 7.3). It reuses QString and QStringList to simplify the processing of command-line arguments.

Operationally, ArgumentList is a class that we initialize with the main() function's int, and char** parameters that capture the command line arguments. Conceptually, ArgumentList is a list of QStrings. Structurally, it is derived from QStringList, with some added functionality. We could also say that ArgumentList is extended from QStringList (as they do in Java-land). Example 6.24 contains the class definition for ArgumentList.

Example 6.24. src/libs/utils/argumentlist.h

#ifndef ARGUMENTLIST_H
#define ARGUMENTLIST_H
#include "utils_export.h"

#include <QStringList>

class UTILS_EXPORT ArgumentList : public QStringList {
  public:
    ArgumentList();
     
    ArgumentList(int argc, char* argv[]) {
        argsToStringlist(argc, argv);
    }

    ArgumentList(const QStringList& argumentList): 
       QStringList(argumentList) {}
    bool getSwitch(QString option);
    QString getSwitchArg(QString option, 
                         QString defaultRetVal=QString());
  private:
    void argsToStringlist(int argc,  char* argv[]);
};
#endif


Because it is publicly derived from QStringList, ArgumentList supports the full interface of QStringList and can be used wherever a QStringList is expected. In addition to its constructors, ArgumentList defines a few additional functions:

Example 6.25 shows the implementation code for these functions.

Example 6.25. src/libs/utils/argumentlist.cpp

#include <QCoreApplication>
#include <QApplication>
#include "argumentlist.h"
#include <QDebug>

ArgumentList::ArgumentList() {
    if (qApp != NULL)  1
        *this = qApp->arguments();
}


void ArgumentList::argsToStringlist(int argc, char * argv []) {
    for (int i=0; i < argc; ++i) {
        *this += argv[i];
    }
}

bool ArgumentList::getSwitch (QString option) {
    QMutableStringListIterator itr(*this);
    while (itr.hasNext()) {
        if (option == itr.next()) {
            itr.remove();
            return true;
        }
    }
    return false;
}

QString ArgumentList::getSwitchArg(QString option, QString defaultValue) {
    if (isEmpty())
        return defaultValue;
    QMutableStringListIterator itr(*this);
    while (itr.hasNext()) {
        if (option == itr.next()) {
            itr.remove();
            if (itr.hasNext()) {
                QString retval = itr.next();
                itr.remove();
                return retval;
            }
            else {
                qDebug() << "Missing Argument for " << option;
                return QString();
            }
        }
    }
    return defaultValue;
}

1

a global pointer to the current qApplication

In the client code shown in Example 6.26 all argument processing code has been removed from main(). No loops, char*, or strcmp are to be found.

Example 6.26. src/reuse/main.cpp

#include <QString>
#include <QDebug>
#include <argumentlist.h>  // in our utils lib

void processFile(QString filename, bool verbose) {
    if (verbose)
        qDebug() << QString("Do something chatty with %1.").arg(filename);
    else
        qDebug() << filename;
}

void runTestOnly(QStringList & listOfFiles, bool verbose) {
    foreach (QString current, listOfFiles) { 1
        processFile(current, verbose);
    }
}


int main( int argc, char * argv[] ) {
    
    ArgumentList al(argc, argv); 2
    QString appname = al.takeFirst(); 3
    qDebug() << "Running " << appname;

    bool verbose = al.getSwitch("-v");
    bool testing = al.getSwitch("-t"); 4
    if (testing) {
        runTestOnly(al, verbose); 5
        return 0;
    } else {
        qDebug() << "This Is Not A Test";
    }
}

1

Qt improved foreach loop

2

Instantiate the ArgumentList with command line args.

3

The first item in the list is the name of the executable

4

Now all switches have been removed from the list. Only filenames remain.

5

ArgumentList can be used in place of QStringList.

Here are some sample outputs from running the program in Example 6.26:

src/reuse> ./reuse item1 "item2 item3" item4 item5
"Running ./reuse"
This Is Not A Test
src/reuse> ./reuse -t item1 item2 item3 item4 item5
"Running ./reuse"
"item1"
"item2 item3"
"item4"
"item5"
src/reuse> ./reuse -v -t "foo bar" 123 space1 "1 1"
"Running ./reuse"
"Do something chatty with foo bar."
"Do something chatty with 123."
"Do something chatty with space1."
"Do something chatty with 1 1."
src/reuse>

We include the project file in Example 6.27 to show how to reuse the classes in our utils library.

Example 6.27. src/reuse/reuse.pro

CONFIG += console
TEMPLATE = app
INCLUDEPATH += $$(CPPLIBS)/utils
LIBS += -L$$(CPPLIBS) -lutils
# Input
SOURCES += main.cpp