24

I am looking for a command line parser for Qt4.

I did a small google search, and found this: http://www.froglogic.com/pg?id=PublicationsFreeware&category=getopt however it lacks support for "--enable-foo" and "--disable-foo" switches. Besides that, it looks like a real winner.

EDIT:

It seems Frologic removed this. So the best options I see are using Boost (which is not API nor ABI stable) or forking the support for kdelibs. Yay...

elcuco
  • 8,948
  • 9
  • 47
  • 69
  • For those (like me) still on Qt4, the frologic library can be obtained using the Internet Archive Wayback machine. The license on the frologic code is a 3-clause BSD-style license, so most anyone can use the code. – Michael Kohne Feb 28 '14 at 19:40

11 Answers11

23

QCoreApplication's constructors require (int &argc, char **argv) (and QApplication inherits from QCoreApplication). As the documentation states, it is highly recommended that

Since QApplication also deals with common command line arguments, it is usually a good idea to create it before any interpretation or modification of argv is done in the application itself.

And if you're letting Qt get the first pass at handling arguments anyways, it would also be a good idea to use QStringList QCoreApplication::arguments() instead of walking through argv; QApplication may remove some of the arguments that it has taken for its own use.

This doesn't lend itself to being very compatible with other argument-parsing libraries...

However, kdelibs does come with a nice argument parser, KCmdLineArgs. It is LGPL and can be used without KApplication if you really want (call KCmdLineArgs::init).

KCmdLineOptions options;
options.add("enable-foo", ki18n("enables foo"));
options.add("nodisable-foo", ki18n("disables foo"));
// double negatives are confusing, but this makes disable-foo enabled by default

KCmdLineArgs::addCmdLineOptions(options);
KApplication app;
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

if (args->isSet("enable-foo") && !args->isSet("disable-foo"))
    cout << "foo enabled" << endl;
else
    cout << "foo disabled" << endl;

Untested (who ever tests what they post on S.O.?).

feedc0de
  • 3,646
  • 8
  • 30
  • 55
ephemient
  • 198,619
  • 38
  • 280
  • 391
18

Since Qt 5.2 you can finally find a solution in QtCore itself: I contributed QCommandLineParser there.

David Faure
  • 1,836
  • 15
  • 19
9

This is more or less the same answer as ephemient, but with a simple regexp to help parse the args. (This way could be useful if you only need a handful of args)

Run with this:

./QArgTest --pid=45 --enable-foo

And the code:

int main(int argc, char *argv[]) {
    QApplication app(argc, argv, false);
    qDebug() << "QApp arg test app"; 

    QStringList args = app.arguments();

    int pid = 0;

    QRegExp rxArgPid("--pid=([0-9]{1,})");
    QRegExp rxArgFooEna("--enable-foo");
    QRegExp rxArgFooDis("--disable-foo");

    for (int i = 1; i < args.size(); ++i) {
        if (rxArgPid.indexIn(args.at(i)) != -1 ) {   
            pid =  rxArgPid.cap(1).toInt();
            qDebug() << i << ":" << args.at(i) << rxArgPid.cap(1) << pid;
        }
        else if (rxArgFooEna.indexIn(args.at(i)) != -1 ) {   
            qDebug() << i << ":" << args.at(i) << "Enable Foo";
        } 
        else if (rxArgFooDis.indexIn(args.at(i)) != -1 ) {   
            qDebug() << i << ":" << args.at(i) << "Disable Foo";
        } 
        else {
            qDebug() << "Uknown arg:" << args.at(i);
        }
    }
    return 0;
}
Johan
  • 20,067
  • 28
  • 92
  • 110
7

There is also QxtCommandOptions from http://www.libqxt.org/

KillerWabbit
  • 94
  • 1
  • 1
3

That package does support --disable-foo and --enable-foo via opts.addSwitch("disable-foo", &foo_disabled); and opts.addSwitch("enable-foo", &foo_enabled);. You need handle checking both, and dealing with someone specifying both (oops).

What I don't understand is how this has anything to do with QT4...

jesup
  • 6,765
  • 27
  • 32
  • This means that for every bool I need to add two rules. Not the best practice. Besides, I want to have a "native" Qt4 solution. For example, when adding a switch with multiple values, I want to get a QList, or when saying that I want a point, I want to get a QPoint. opts.addPoint("location", myQPointVariable) – elcuco May 15 '09 at 19:36
  • Yes, that's true, you need two "rules" - but you also have two options; it's --disable-foo not --foo=disabled. And if you have both, you need to detect and at least error on enable and disable together (though that could be done in the getopt parser). ephemient's answer has more QT-specific info, but the library he suggests has the same general restrictions as the froglogic one. The QT arguments() stuff doesn't handle any of the sort of parsing you want. – jesup May 15 '09 at 20:22
2

Look at this: http://code.google.com/p/qtargparser/

Igor
  • 21
  • 1
  • 1
    SO NICE!!! seems like BSD'ish license, pure Qt... however it's kinda verbose. Look for example, the amount of code needed to process the command line agruments: http://code.google.com/p/qtargparser/source/browse/trunk/samples/help/main.cpp I do need to find time and play with it. Thanks! – elcuco Nov 22 '09 at 08:10
  • Looks quite nice but not if you see that the whole API uses Exceptions .. I dont want to use Exceptions in a Framework which doesnt use them. :( – Tobias Jan 24 '11 at 08:16
2

It's 2013 and still no "1st party" arg parser. Anyways..if anyone finds themselves facing the same problem and would like to avoid the learning curves that come with cmd parser libs, here is a "quick & dirty" fix for you:-

QString QArgByKey(QString key, QChar sep = QChar('\0') ) //prototype usually in separate header

QString QArgByKey(QString key, QChar sep )
{
    bool sepd=sep!=QChar('\0');
    int pos=sepd?qApp->arguments().indexOf(QRegExp('^'+key+sep+"\\S*")):qApp->arguments().indexOf(QRegExp(key));
    return pos==-1?QString::null:
    (sepd?qApp->arguments().at(pos).split(sep).at(1):(++pos<qApp->arguments().size()?qApp->arguments().at(pos):QString::null));
}

Example:-

user@box:~$ ./myApp  firstKey=Value1 --secondKey Value2 thirdKey=val3.1,val3.2,val3.3 --enable-foo

Usage:

QString param1   = QArgByKey("firstkey",'='); // Returns `Value1` from first pair
QString param2   = QArgByKey("--secondkey"); // Returns `Value2` from second pair
QString param3-1 = QArgByKey("thirdkey",'=').split(',').at(0); // Returns `val3.1`
bool fooEnabled  = qApp->arguments().contains("--enable-foo"); //To check for `--enable-foo` 

Params can be passed in any order

Edit: Updates to this snippet will be found here

mrmoje
  • 3,714
  • 3
  • 20
  • 18
2

A really simple method is to scan "key=value" args,
put them in a table say zz.map: QString -> QVariant,
and get their values with zz.map.value( key, default ). An example:

#include "ztest.h"
Ztest zz;  
int main( int argc, char* argv[] )
{
    zz.eqargs( ++ argv );  // scan  test=2 x=str ... to zz.map

    QString xx = zz.map.value( "xx", "" );
    if( Zint( Size, 10 ))  // a #def -> zz.map.value( "Size", 10 )
        ...

ztest.h is < 1 page, below; same for Python ~ 10 lines.

(Everybody has his/her favorite options parser; this one's about the simplest.
Worth repeating: however you specify options, echo them to output files --
"every scientist I know has trouble keeping track of what parameters they used last time they ran a script".)

To make QPoints etc work one of course needs a QString -> QPoint parser. Anyone know offhand why this doesn't work (in Qt 4.4.3) ?

QPoint pt(0,0);
QDataStream s( "QPoint(1,2)" );
s >> pt;
qDebug() << "pt:" << pt;  // QPoint(1364225897,1853106225) ??

Added 25nov --

// ztest.h: scan args x=2 s=str ... to a key -> string table
// usage:
// Ztest ztest;
// int main( int argc, char* argv[] )
// {
//     QApplication app( argc, argv );
//     ztest.eqargs( ++ argv );  // scan leading args name=value ...
//     int x = Zint( x, 10 );  // arg x= or default 10
//     qreal ff = Zreal( ff, 3.14 );
//     QString s = Zstr( s, "default" );
// care: int misspelled = Zint( misspellled ) -- you lose
//version: 2009-06-09 jun denis

#ifndef ztest_h
#define ztest_h

#include <QHash>
#include <QString>
#include <QVariant>
#include <QRegExp>

//------------------------------------------------------------------------------
class Ztest {
public:
  QHash< QString, QVariant > map;
  int test;  // arg test=num,  if( ztest.test )

  Ztest() : test( 0 ) {}

  QVariant val( const QString& key, const QVariant& default_ = 0 )
  {
    return map.value( key, default_ );
  }

  void setval( const QString& key, const QVariant& val )
  {
    map[key] = val;
    if( key == "test"  ||  key == "Test" )
        test = val.toInt();
  }

//------------------------------------------------------------------------------
    // ztest.eqargs( ++ argv )  scans test=2 x=3 ... -> ztest table
  void eqargs( char** argv )
  {
    char** argv0 = argv;
    char *arg;
    QRegExp re( "(\\w+)=(.*)" );  // name= anything, but not ./file=name
    for( ; (arg = *argv) && re.exactMatch( arg );  argv ++ ){
        setval( re.cap(1), re.cap(2) );
    }
        // change argv[0..] -> args after all name=values
    while(( *argv0++ = *argv++) != 0 ) {}
  }
};

extern Ztest ztest;

    // macros: int x = Zint( x, 10 ): x= arg or default 10
#define Zstr( key, default )    ztest.val( #key, default ).toString()
#define Zint( key, default )    ztest.val( #key, default ).toInt()
#define Zreal( key, default )   ztest.val( #key, default ).toDouble()

#endif
denis
  • 21,378
  • 10
  • 65
  • 88
1

Does it have to be Qt4 specific? If not, GNU Getopt is really nice, although licensing may be a problem if you are not doing open source software.

Zifre
  • 26,504
  • 11
  • 85
  • 105
0

Also for some fancy options parsing you can try gperf.

IBM has a nice tutorial on it.

Marius Or.
  • 374
  • 4
  • 10
  • GPL, and not LGPL/MIT/X11.... and no integration with Qt4 "primitives" see my comment to jesup – elcuco Nov 11 '09 at 21:30
  • I'm not very sure that the licence applies to code generated by gperf and to the best of my knowledge you are not linking against gperf. It is just an external tool to build a look-up function/object. In all fairness, I have yet to use it for an actual project. – Marius Or. Nov 15 '09 at 16:27
0

Another option I ran across while looking to do this, too:

http://code.google.com/p/qgetopts/

I haven't used it though.

dwj
  • 3,443
  • 5
  • 35
  • 42