6.7.1.  Derivation and ArgumentList

[ fromfile: argumentlist.xml id: argumentlist ]

ArgumentList provides an example of a reusable class with a specific purpose derived from a more general purpose Qt class. It reuses QString and QStringList to simplify the processing of command-line arguments.

Operationally, ArgumentList is a class that is initialized with the main() function's int and char** parameters, which capture the command-line arguments. Conceptually, ArgumentList is a list of QStrings. Structurally, it is derived from QStringList, with some added functionality. A Java programmer would say that ArgumentList is extended from QStringList. Example 6.26 contains the class definition for ArgumentList.

Example 6.26. src/derivation/argumentlist/argumentlist.h

#ifndef ARGUMENTLIST_H
#define ARGUMENTLIST_H

#include <QStringList>

class 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.27 shows the implementation code for these functions.

Example 6.27. src/derivation/argumentlist/argumentlist.cpp

#include <QCoreApplication>
#include <QDebug>
#include "argumentlist.h"
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.28 all argument processing code has been removed from main(). No loops, char*, or strcmp are to be found.

Example 6.28. src/derivation/argumentlist/main.cpp

#include <QString>
#include <QDebug>
#include "argumentlist.h" 

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 (const QString &current, listOfFiles) { 
      processFile(current, verbose);
   }
}

int main( int argc, char * argv[] ) {
   ArgumentList al(argc, argv);       1
   QString appname = al.takeFirst();  2
   qDebug() << "Running " << appname;
   bool verbose = al.getSwitch("-v");
   bool testing = al.getSwitch("-t"); 3
   if (testing) {
      runTestOnly(al, verbose);       4
      return 0;
   } else {
      qDebug() << "This Is Not A Test";
   }
}

1

Instantiate the ArgumentList with command line args.

2

Inherited from QStringList - first item in the list is the name of the executable.

3

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

4

ArgumentList can be used in place of QStringList.


Following are some sample outputs from running the program in Example 6.28:

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