Index: src/MainWindow.hxx
===================================================================
--- src/MainWindow.hxx	(revisión: 12719)
+++ src/MainWindow.hxx	(copia de trabajo)
@@ -101,47 +101,17 @@
 		ui.action_Embed_SVG_Diagrams_Option->setChecked(embedSvgDiagramsOption);
 
 		_network.AddFlowControl( new CLAM::NaiveFlowControl );
-		QString backend = "None";
-		QString backendLogo = ":/icons/images/editdelete.png"; // TODO: Change this icon
-		if (_networkPlayer) delete _networkPlayer;
-		_networkPlayer = 0;
 
 #ifdef USE_LADSPA
 		ui.menuFaust->setEnabled(true);
 		ui.action_Compile_Faust_Modules->setEnabled(true);
 #endif
 
-#ifdef USE_JACK
-		CLAM::JACKNetworkPlayer * jackPlayer = new CLAM::JACKNetworkPlayer();
-		backend = "JACK";
-		backendLogo = ":/icons/images/jacklogo-mini.png";
-		if ( jackPlayer->IsWorking())
-		{
-			_networkPlayer = jackPlayer;
-#ifdef AFTER13RELEASE
-			_jackCanvas = new ClamNetworkCanvas; // TODO: This should be a JackNetworkCanvas
-			backendScroll->setWidget(_jackCanvas);
-#endif//AFTER13RELEASE
-		}
-		else
-			delete jackPlayer;
-#endif
-#ifdef USE_PORTAUDIO
-		if (! _networkPlayer)
-		{
-			backend = "PortAudio";
-			backendLogo = ":/icons/images/portaudiologo-mini.png";
-			_networkPlayer = new CLAM::PANetworkPlayer();
-		}
-#endif
-		_network.SetPlayer( _networkPlayer );
-
 		_playingLabel = new QLabel;
 		statusBar()->addPermanentWidget(_playingLabel);
 		_backendLabel = new QLabel;
 		statusBar()->addPermanentWidget(_backendLabel);
-		_backendLabel->setToolTip(tr("<p>Audio Backend: %1</p>").arg(backend));
-		_backendLabel->setPixmap(QPixmap(backendLogo));
+
 		ui.action_Play->setEnabled(true);
 		ui.action_Stop->setEnabled(false);
 		ui.action_Pause->setEnabled(false);
@@ -257,6 +227,53 @@
 		updateCaption();
 	}
 
+	void setBackend(QString &backend)
+	{
+		QString backendLogo = ":/icons/images/editdelete.png"; // TODO: Change this icon
+		if (_networkPlayer) delete _networkPlayer;
+		_networkPlayer = 0;
+
+#ifdef USE_JACK
+		if (backend=="JACK" || backend=="Auto")
+		{
+			CLAM::JACKNetworkPlayer *jackPlayer = new CLAM::JACKNetworkPlayer();
+			if ( jackPlayer->IsWorking() )
+			{
+				backend = "JACK";
+				backendLogo = ":/icons/images/jacklogo-mini.png";
+				_networkPlayer = jackPlayer;
+#ifdef AFTER13RELEASE
+				_jackCanvas = new ClamNetworkCanvas; // TODO: This should be a JackNetworkCanvas
+				backendScroll->setWidget(_jackCanvas);
+#endif//AFTER13RELEASE
+			}
+			else
+				delete jackPlayer;
+		}
+#endif
+
+#ifdef USE_PORTAUDIO
+		if (backend=="PortAudio" || backend=="Auto")
+		{
+			if (! _networkPlayer)
+			{
+				backend = "PortAudio";
+				backendLogo = ":/icons/images/portaudiologo-mini.png";
+				_networkPlayer = new CLAM::PANetworkPlayer();
+			}
+		}
+#endif
+
+		CLAM_ASSERT(_networkPlayer!=0, "Problem setting the backend.");
+		if (_networkPlayer==0) backend = "None";
+		_network.SetPlayer( _networkPlayer );
+
+		_backendLabel->setToolTip(tr("<p>Audio Backend: %1</p>").arg(backend));
+		_backendLabel->setPixmap(QPixmap(backendLogo));
+
+		updatePlayStatusIndicator();
+	}
+
 	void closeEvent(QCloseEvent *event)
 	{
 		if (not askUserSaveChanges())
Index: src/main.cxx
===================================================================
--- src/main.cxx	(revisión: 12719)
+++ src/main.cxx	(copia de trabajo)
@@ -19,6 +19,8 @@
  *
  */
 
+#include "getopt.hxx"
+
 #include <QtGui/QApplication>
 #include <QtCore/QTranslator>
 #include <QtCore/QLocale>
@@ -37,10 +39,38 @@
 #endif
 #endif
 
+void usage(const std::string &program)
+{
+	std::cout 
+		<< " Usage: " << program
+		<<                      " [file]  Network filename. " << std::endl
+		<< "                      [-b OR --backend]  The backend can be JACK, PortAudio or Auto." << std::endl
+		<< "                      [--help]: This help." << std::endl;
+}
 
-
 int main( int argc, char ** argv )
 {
+    // construct class from command line arguments
+	GetOpt opts(argc, argv);
+	bool help;
+	opts.addSwitch("help", &help);
+	QString backend;
+	opts.addOption('b', "backend", &backend);
+	QString file;
+	opts.addOptionalArgument("file", &file);
+
+    // do the parsing and check for errors
+    if (!opts.parse()) {
+		usage( opts.appName().toStdString() );
+        return 1;
+    }
+
+	if (help)
+	{
+		usage( opts.appName().toStdString() );
+		return 0;
+	}
+
 #ifdef USE_LADSPA
 	RunTimeLadspaLibraryLoader ladspaLoader;
 	ladspaLoader.Load();
@@ -65,8 +95,12 @@
 	QCoreApplication::setApplicationName("Network Editor");
 	MainWindow w;
 	w.show();
-	if (argc>1) w.load(argv[1]);
-	else w.clear();
+
+	if (backend==QString::null) backend="Auto";
+	w.setBackend(backend);
+	if (file!=QString::null) w.load(file);
+	w.clear();
+
 	return app.exec();
 }
 
Index: src/getopt.cxx
===================================================================
--- src/getopt.cxx	(revisión: 0)
+++ src/getopt.cxx	(revisión: 0)
@@ -0,0 +1,633 @@
+#define QT_NO_CAST_ASCII
+#define QT_NO_ASCII_CAST
+
+#include "getopt.hxx"
+
+#include <QtGui/QApplication>
+#include <QtCore/QFileInfo>
+#include <QtCore/QStack>
+
+#include <stdlib.h>
+
+#include <assert.h>
+
+/**
+   \class GetOpt
+
+   \brief A command line option parser.
+
+   This class helps to overcome the repetitive, tedious and
+   error-prone task of parsing the command line options passed to your
+   application by the user. Specify the acceptable syntax with a
+   minimum of statements in a readable way, check it against the
+   actual arguments passed and find the retrieved values in variables
+   of your program. The name \em GetOpt is based on similar utilities
+   build into the Unix shell and other languages.
+
+   A command line that a user might have entered is:
+
+   \code
+   app -v --config=my.cnf -Wall input.dat
+   \endcode
+
+   The typical usage has three stages:
+
+   -# Construct a parser specifying what arguments to parse
+   -# Set up the list of allowed and required options
+   -# Run the parser
+
+   For the first step there are three different constructors that
+   either take arguments directly from \c main(), \c QApplication or a
+   user specified list. Setting up the accepted syntax is done by a
+   set of \c add functions like addSwitch(). The final step of running
+   the parser is simply done by calling parse().
+
+   A short example implementing a \c --verbose switch:
+
+   \code
+   int main(int argc, char **argv)
+   {
+       GetOpt opts(argc, argv);
+       bool verbose;
+       opts.addSwitch("verbose", &verbose);
+       if (!opts.parse())
+           return 1;
+       if (verbose)
+           cout << "VERBOSE mode on" << endl;
+       ...
+   \endcode
+
+   For a better understanding of the function names we'll better
+   define some terms used in the API and its documentation:
+
+   - \em Argument An argument is a plain text token like e.g. a file
+   name one typically passes to an editor when invoking it.
+   - \em Switch A switch is an on/off kind of argument without the need
+     of additional information. Example: \c --debug.
+   - \em Option An option is a normally optional argument with a key-value
+   syntax like \c --output=out.txt or \c -I/usr/include.
+   - \em Short \em Option A short option is a one letter option with a
+   preceding dash. Like \c -v.
+   - \em Long \em Option A long option has a more verbose,
+   multi-letter name like \c --debug.
+   .
+
+   \author froglogic GbR <contact@froglogic.com>
+*/
+
+
+/**
+   Constructs a command line parser from the arguments stored in a
+   previously created QApplication instance.
+
+   Example usage:
+   \code
+   QApplication a(argc, argv);
+
+   GetOpt opt;
+   \endcode
+
+   This constructor is probably the most convenient one to use in a
+   regular Qt application. Note that QApplication may already have
+   removed Qt (or X11) specific arguments. Also see
+   QApplication::argv() and QApplication::argc().
+ */
+GetOpt::GetOpt()
+{
+    if ( !qApp )
+	qFatal( "GetOpt: requires a QApplication instance to be constructed first" );
+
+    init( qApp->argc(), qApp->argv(), 1 );
+}
+
+/**
+   \internal
+ */
+GetOpt::GetOpt( int offset )
+{
+    if ( !qApp )
+	qFatal( "GetOpt: requires a QApplication instance to be constructed first" );
+
+    init( qApp->argc(), qApp->argv(), offset );
+}
+
+/**
+   Construct a command line parser from the array \a argv of string
+   pointers with the size \a argc. Those parameters have the form
+   typically found in the \c main() function. That means that you can
+   simply pass on the arguments specified by the user of your
+   application.
+
+   Example usage:
+
+   \code
+   int main(int argc, char **argv) {
+       GetOpt opt(argc, argv);
+       ...
+   }
+   \endcode
+ */
+GetOpt::GetOpt( int argc, char *argv[] )
+{
+    init( argc, argv );
+}
+
+/**
+   Construct a command line parser from the arguments specified in the
+   list of arguments \a a. This constructor is convenient in those
+   cases where you want to parse a command line assembled on-the-fly
+   instead of relying on the \c argc and \c arg parameters passed to
+   the \c main() function.
+ */
+GetOpt::GetOpt( const QStringList &a )
+    : args( a )
+{
+    init( 0, 0 );
+}
+
+/**
+   \internal
+*/
+void GetOpt::init( int argc, char *argv[], int offset )
+{
+    numReqArgs = numOptArgs = 0;
+    currArg = 1; // appname is not part of the arguments
+    if ( argc ) {
+	// application name
+	aname = QFileInfo( QString::fromUtf8( argv[0] ) ).fileName();
+	// arguments
+	for ( int i = offset; i < argc; ++i )
+	    args.append( QString::fromUtf8( argv[i] ) );
+    }
+}
+
+/**
+   \fn bool GetOpt::parse()
+
+   Parse the command line arguments specified in the constructor under
+   the conditions set by the various \c add*() functions. On success,
+   the given variable reference will be initialized with their
+   respective values and true will be returned. Returns false
+   otherwise.
+
+   In the future there'll be a way to retrieve an error message. In
+   the current version the message will be printed to \c stderr.
+*/
+
+/**
+   \internal
+*/
+bool GetOpt::parse( bool untilFirstSwitchOnly )
+{
+    //    qDebug( "parse(%s)", args.join( QString( "," ) ).ascii() );
+    // push all arguments as we got them on a stack
+    // more pushes might following when parsing condensed arguments
+    // like --key=value.
+    QStack<QString> stack;
+    {
+/*		QStringList::const_iterator it = args.fromLast();
+		const QStringList::const_iterator end = args.end();
+		while ( it != end ) {
+			stack.push( *it );
+			--it;
+		}
+*/
+		QStringList::const_iterator it = args.end();
+		while ( it != args.begin() ) {
+			--it;
+			stack.push( *it );
+		}
+
+    }
+
+    const OptionConstIterator obegin = options.begin();
+    const OptionConstIterator oend = options.end();
+    enum { StartState, ExpectingState, OptionalState } state = StartState;
+    Option currOpt;
+    enum TokenType { LongOpt, ShortOpt, Arg, End } t, currType = End;
+    bool extraLoop = true; // we'll do an extra round. fake an End argument
+    while ( !stack.isEmpty() || extraLoop ) {
+	QString a;
+	QString origA;
+	// identify argument type
+	if ( !stack.isEmpty() ) {
+	    a = stack.pop();
+	    currArg++;
+	    origA = a;
+	    //	    qDebug( "popped %s", a.ascii() );
+	    if ( a.startsWith( QString::fromLatin1( "--" ) ) ) {
+		// recognized long option
+		a = a.mid( 2 );
+		if ( a.isEmpty() ) {
+		    qWarning( "'--' feature not supported, yet" );
+		    exit( 2 );
+		}
+		t = LongOpt;
+		// split key=value style arguments
+		int equal = a.indexOf( '=' ); //FIXME: was int equal = a.find( '=' );
+		if ( equal >= 0 ) {
+		    stack.push( a.mid( equal + 1 ) );
+		    currArg--;
+		    a = a.left( equal );
+		}
+	    } else if ( a.length() == 1 ) {
+		t = Arg;
+	    } else if ( a[0] == '-' ) {
+#if 0 // compat mode for -long style options
+		if ( a.length() == 2 ) {
+		    t = ShortOpt;
+		    a = a[1];
+		} else {
+		    a = a.mid( 1 );
+		    t = LongOpt;
+		    // split key=value style arguments
+		    int equal = a.find( '=' );
+		    if ( equal >= 0 ) {
+			stack.push( a.mid( equal + 1 ) );
+			currArg--;
+			a = a.left( equal );
+		    }
+		}
+#else
+		// short option
+		t = ShortOpt;
+		// followed by an argument ? push it for later processing.
+		if ( a.length() > 2 ) {
+		    stack.push( a.mid( 2 ) );
+		    currArg--;
+		}
+		a = a[1];
+#endif
+	    } else {
+		t = Arg;
+	    }
+	} else {
+	    // faked closing argument
+	    t = End;
+	}
+	// look up among known list of options
+	Option opt;
+	if ( t != End ) {
+	    OptionConstIterator oit = obegin;
+	    while ( oit != oend ) {
+		const Option &o = *oit;
+		if ( ( t == LongOpt && a == o.lname ) || // ### check state
+		     ( t == ShortOpt && a[0].unicode() == o.sname ) ) {
+		    opt = o;
+		    break;
+		}
+		++oit;
+	    }
+	    if ( t == LongOpt && opt.type == OUnknown ) {
+		if ( currOpt.type != OVarLen ) {
+//		    qWarning( "Unknown option --%s", a.toAscii() ); //FIXME
+		    return false;
+		} else {
+		    // VarLength options support arguments starting with '-'
+		    t = Arg;
+		}
+	    } else if ( t == ShortOpt && opt.type == OUnknown ) {
+		if ( currOpt.type != OVarLen ) {
+		    qWarning( "Unknown option -%c", a[0].unicode() );
+		    return false;
+		} else {
+		    // VarLength options support arguments starting with '-'
+		    t = Arg;
+		}
+	    }
+
+	} else {
+	    opt = Option( OEnd );
+	}
+
+	// interpret result
+	switch ( state ) {
+	case StartState:
+	    if ( opt.type == OSwitch ) {
+		setSwitch( opt );
+		setOptions.insert( opt.lname, 1 );
+		setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+	    } else if ( opt.type == OArg1 || opt.type == ORepeat ) {
+		state = ExpectingState;
+		currOpt = opt;
+		currType = t;
+		setOptions.insert( opt.lname, 1 );
+		setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+	    } else if ( opt.type == OOpt || opt.type == OVarLen ) {
+		state = OptionalState;
+		currOpt = opt;
+		currType = t;
+		setOptions.insert( opt.lname, 1 );
+		setOptions.insert( QString( QChar( opt.sname ) ), 1 );
+	    } else if ( opt.type == OEnd ) {
+		// we're done
+	    } else if ( opt.type == OUnknown && t == Arg ) {
+		if ( numReqArgs > 0 ) {
+		    if ( reqArg.stringValue->isNull() ) { // ###
+			*reqArg.stringValue = a;
+		    } else {
+			qWarning( "Too many arguments" );
+			return false;
+		    }
+		} else if ( numOptArgs > 0 ) {
+		    if ( optArg.stringValue->isNull() ) { // ###
+			*optArg.stringValue = a;
+		    } else {
+			qWarning( "Too many arguments" );
+			return false;
+		    }
+		}
+	    } else {
+		qFatal( "unhandled StartState case %d",  opt.type );
+	    }
+	    break;
+	case ExpectingState:
+	    if ( t == Arg ) {
+		if ( currOpt.type == OArg1 ) {
+		    *currOpt.stringValue = a;
+		    state = StartState;
+		} else if ( currOpt.type == ORepeat ) {
+		    currOpt.listValue->append( a );
+		    state = StartState;
+		} else {
+		    abort();
+		}
+	    } else {
+		QString n = currType == LongOpt ?
+			    currOpt.lname : QString( QChar( currOpt.sname ) );
+// 		qWarning( "Expected an argument after '%s' option", n.toAscii(), ); //FIXME
+		return false;
+	    }
+	    break;
+	case OptionalState:
+	    if ( t == Arg ) {
+		if ( currOpt.type == OOpt ) {
+		    *currOpt.stringValue = a;
+		    state = StartState;
+		} else if ( currOpt.type == OVarLen ) {
+		    currOpt.listValue->append( origA );
+		    // remain in this state
+		} else {
+		    abort();
+		}
+	    } else {
+		// optional argument not specified
+		if ( currOpt.type == OOpt )
+		    *currOpt.stringValue = currOpt.def;
+		if ( t != End ) {
+		    // re-evaluate current argument
+		    stack.push( origA );
+		    currArg--;
+		}
+		state = StartState;
+	    }
+	    break;
+	}
+
+	if ( untilFirstSwitchOnly && opt.type == OSwitch )
+	    return true;
+
+	// are we in the extra loop ? if so, flag the final end
+	if ( t == End )
+	    extraLoop = false;
+    }
+
+    if ( numReqArgs > 0 && reqArg.stringValue->isNull() ) {
+	qWarning( "Lacking required argument" );
+	return false;
+    }
+
+    return true;
+}
+
+/**
+   \internal
+*/
+void GetOpt::addOption( Option o )
+{
+    // ### check for conflicts
+    options.append( o );
+}
+
+/**
+   Adds a switch with the long name \a lname. If the switch is found
+   during parsing the bool \a *b will bet set to true. Otherwise the
+   bool will be initialized to false.
+
+   Example:
+
+   \code
+   GetOpt opt;
+   bool verbose;
+   opt.addSwitch("verbose", &verbose);
+   \endcode
+
+   The boolean flag \c verbose will be set to true if \c --verbose has
+   been specified in the command line; false otherwise.
+*/
+void GetOpt::addSwitch( const QString &lname, bool *b )
+{
+    Option opt( OSwitch, 0, lname );
+    opt.boolValue = b;
+    addOption( opt );
+    // ### could do all inits at the beginning of parse()
+    *b = false;
+}
+
+/**
+   \internal
+*/
+void GetOpt::setSwitch( const Option &o )
+{
+    assert( o.type == OSwitch );
+    *o.boolValue = true;
+}
+
+/**
+   Registers an option with the short name \a s and long name \a l to
+   the parser. If this option is found during parsing the value will
+   be stored in the string pointed to by \a v. By default \a *v will
+   be initialized to \c QString::null.
+*/
+void GetOpt::addOption( char s, const QString &l, QString *v )
+{
+    Option opt( OArg1, s, l );
+    opt.stringValue = v;
+    addOption( opt );
+    *v = QString::null;
+}
+
+/**
+   Registers a long option \a l that can have a variable number of
+   corresponding value parameters. As there currently is no way to
+   tell the end of the value list the only sensible use of this option
+   is at the end of the command line.
+
+   Example:
+
+   \code
+   QStringList args;
+   opt.addVarLengthOption("exec", &args);
+   \endcode
+
+   Above code will lead to "-f" and "test.txt" being stored in \a args
+   upon
+
+   \code
+   myapp --exec otherapp -f test.txt
+   \endcode
+ */
+void GetOpt::addVarLengthOption( const QString &l, QStringList *v )
+{
+    Option opt( OVarLen, 0, l );
+    opt.listValue = v;
+    addOption( opt );
+    *v = QStringList();
+}
+
+/**
+   Registers an option with the short name \a s that can be specified
+   repeatedly in the command line. The option values will be stored in
+   the list pointed to by \a v. If no \a s option is found \a *v will
+   remain at its default value of an empty QStringList instance.
+
+   Example:
+
+   To parse the \c -I options in a command line like
+   \code
+   myapp -I/usr/include -I/usr/local/include
+   \endcode
+
+   you can use code like this:
+
+   \code
+   GetOpt opt;
+   QStringList includes;
+   opt.addRepeatableOption('I', &includes);
+   opt.parse();
+   \endcode
+ */
+void GetOpt::addRepeatableOption( char s, QStringList *v )
+{
+    Option opt( ORepeat, s, QString::null );
+    opt.listValue = v;
+    addOption( opt );
+    *v = QStringList();
+}
+
+/**
+   Registers an option with the long name \a l that can be specified
+   repeatedly in the command line.
+
+   \sa addRepeatableOption( char, QStringList* )
+ */
+void GetOpt::addRepeatableOption( const QString &l, QStringList *v )
+{
+    Option opt( ORepeat, 0, l );
+    opt.listValue = v;
+    addOption( opt );
+    *v = QStringList();
+}
+
+/**
+   Adds a long option \a l that has an optional value parameter. If
+   the value is not specified by the user it will be set to \a def.
+
+   Example:
+
+   \code
+   GetOpt opt;
+   QString file;
+   opt.addOptionalOption("dump", &file, "<stdout>");
+   \endcode
+
+   \sa addOption
+ */
+void GetOpt::addOptionalOption( const QString &l, QString *v,
+                                const QString &def )
+{
+    addOptionalOption( 0, l, v, def );
+}
+
+/**
+   Adds a short option \a s that has an optional value parameter. If
+   the value is not specified by the user it will be set to \a def.
+ */
+void GetOpt::addOptionalOption( char s, const QString &l,
+				QString *v, const QString &def )
+{
+    Option opt( OOpt, s, l );
+    opt.stringValue = v;
+    opt.def = def;
+    addOption( opt );
+    *v = QString::null;
+}
+
+/**
+   Registers a required command line argument \a name. If the argument
+   is missing parse() will return false to indicate an error and \a *v
+   will remain with its default QString::null value. Otherwise \a *v
+   will be set to the value of the argument.
+
+   Example:
+
+   To accept simple arguments like
+
+   \code
+   myeditor letter.txt
+   \endcode
+
+   use a call like:
+
+   \code
+   QString &file;
+   opt.addArgument("file", &file);
+   \endcode
+
+   Note: the \a name parameter has a rather descriptive meaning for
+   now. It might be used for generating a usage or error message in
+   the future. Right now, the only current use is in relation with the
+   isSet() function.
+ */
+void GetOpt::addArgument( const QString &name, QString *v )
+{
+    Option opt( OUnknown, 0, name );
+    opt.stringValue = v;
+    reqArg = opt;
+    ++numReqArgs;
+    *v = QString::null;
+}
+
+/**
+   Registers an optional command line argument \a name. For a more
+   detailed description see the addArgument() documentation.
+
+ */
+void GetOpt::addOptionalArgument( const QString &name, QString *v )
+{
+    Option opt( OUnknown, 0, name );
+    opt.stringValue = v;
+    optArg = opt;
+    ++numOptArgs;
+    *v = QString::null;
+}
+
+/**
+   Returns true if the (long) option or switch \a name has been found
+   in the command line; returns false otherwise. Leading hyphens are
+   not part of the name.
+
+   As the set/not set decision can also be made depending on the value
+   of the variable reference used in the respective \c add*() call
+   there's generally little use for this function.
+*/
+
+bool GetOpt::isSet( const QString &name ) const
+{
+    return setOptions.find( name ) != setOptions.end();
+}
+
+/**
+   \fn int GetOpt::currentArgument() const
+   \internal
+*/
Index: src/getopt.hxx
===================================================================
--- src/getopt.hxx	(revisión: 0)
+++ src/getopt.hxx	(revisión: 0)
@@ -0,0 +1,122 @@
+/**********************************************************************
+ * Copyright (c) 2003, 2004, froglogic Porten & Stadlbauer GbR
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ *    * Neither the name of the froglogic nor the names of its
+ *      contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ **********************************************************************/
+
+#ifndef GETOPT_H
+#define GETOPT_H
+
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+
+class GetOpt {
+public:
+    GetOpt();
+    GetOpt( int offset );
+    GetOpt( int argc, char *argv[] );
+    GetOpt( const QStringList &a );
+
+    QString appName() const { return aname; }
+
+    // switch (no arguments)
+    void addSwitch( const QString &lname, bool *b );
+
+    // options (with arguments, sometimes optional)
+    void addOption( char s, const QString &l, QString *v );
+    void addVarLengthOption( const QString &l, QStringList *v );
+    void addRepeatableOption( char s, QStringList *v );
+    void addRepeatableOption( const QString &l, QStringList *v );
+    void addOptionalOption( const QString &l, QString *v,
+                                const QString &def );
+    void addOptionalOption( char s, const QString &l,
+				QString *v, const QString &def );
+
+    // bare arguments
+    void addArgument( const QString &name, QString *v );
+    void addOptionalArgument( const QString &name, QString *v );
+
+    bool parse( bool untilFirstSwitchOnly );
+    bool parse() { return parse( false ); }
+
+    bool isSet( const QString &name ) const;
+
+    int currentArgument() const { return currArg; }
+
+private:
+    enum OptionType { OUnknown, OEnd, OSwitch, OArg1, OOpt, ORepeat, OVarLen };
+
+    struct Option;
+    friend struct Option;
+
+    struct Option {
+        Option( OptionType t = OUnknown,
+                char s = 0, const QString &l = QString::null )
+            : type( t ),
+              sname( s ),
+              lname( l ),
+              boolValue( 0 ) { }
+
+        OptionType type;
+        char sname;		// short option name (0 if none)
+        QString lname;	// long option name  (null if none)
+        union {
+            bool *boolValue;
+            QString *stringValue;
+            QStringList *listValue;
+        };
+        QString def;
+    };
+
+    QList<Option> options;
+    typedef QList<Option>::const_iterator OptionConstIterator;
+    QMap<QString, int> setOptions;
+
+    void init( int argc, char *argv[], int offset = 1 );
+    void addOption( Option o );
+    void setSwitch( const Option &o );
+
+    QStringList args;
+    QString aname;
+
+    int numReqArgs;
+    int numOptArgs;
+    Option reqArg;
+    Option optArg;
+
+    int currArg;
+};
+
+#endif
+
