You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1299 lines
31 KiB
1299 lines
31 KiB
15 years ago
|
/*
|
||
|
Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License version 2 as published by the Free Software Foundation.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#include <config.h>
|
||
|
|
||
|
#include <sys/param.h>
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#ifdef HAVE_LIMITS_H
|
||
|
#include <limits.h>
|
||
|
#endif
|
||
|
|
||
|
#include <qdir.h>
|
||
|
#include <qfile.h>
|
||
|
#include <qasciidict.h>
|
||
|
#include <qstrlist.h>
|
||
|
|
||
|
#include "kcmdlineargs.h"
|
||
|
#include <kaboutdata.h>
|
||
|
#include <klocale.h>
|
||
|
#include <kapplication.h>
|
||
|
#include <kglobal.h>
|
||
|
#include <kstringhandler.h>
|
||
|
#include <kstaticdeleter.h>
|
||
|
|
||
|
#ifdef Q_WS_X11
|
||
|
#define DISPLAY "DISPLAY"
|
||
|
#elif defined(Q_WS_QWS)
|
||
|
#define DISPLAY "QWS_DISPLAY"
|
||
|
#endif
|
||
|
|
||
|
#ifdef Q_WS_WIN
|
||
|
#include <win32_utils.h>
|
||
|
#endif
|
||
|
|
||
|
template class QAsciiDict<QCString>;
|
||
|
template class QPtrList<KCmdLineArgs>;
|
||
|
|
||
|
class KCmdLineParsedOptions : public QAsciiDict<QCString>
|
||
|
{
|
||
|
public:
|
||
|
KCmdLineParsedOptions()
|
||
|
: QAsciiDict<QCString>( 7 ) { }
|
||
|
|
||
|
// WABA: Huh?
|
||
|
// The compiler doesn't find KCmdLineParsedOptions::write(s) by itself ???
|
||
|
// WABA: No, because there is another write function that hides the
|
||
|
// write function in the base class even though this function has a
|
||
|
// different signature. (obscure C++ feature)
|
||
|
QDataStream& save( QDataStream &s) const
|
||
|
{ return QGDict::write(s); }
|
||
|
|
||
|
QDataStream& load( QDataStream &s)
|
||
|
{ return QGDict::read(s); }
|
||
|
|
||
|
protected:
|
||
|
virtual QDataStream& write( QDataStream &s, QPtrCollection::Item data) const
|
||
|
{
|
||
|
QCString *str = (QCString *) data;
|
||
|
s << (*str);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
virtual QDataStream& read( QDataStream &s, QPtrCollection::Item &item)
|
||
|
{
|
||
|
QCString *str = new QCString;
|
||
|
s >> (*str);
|
||
|
item = (void *)str;
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
class KCmdLineParsedArgs : public QStrList
|
||
|
{
|
||
|
public:
|
||
|
KCmdLineParsedArgs()
|
||
|
: QStrList( true ) { }
|
||
|
QDataStream& save( QDataStream &s) const
|
||
|
{ return QGList::write(s); }
|
||
|
|
||
|
QDataStream& load( QDataStream &s)
|
||
|
{ return QGList::read(s); }
|
||
|
};
|
||
|
|
||
|
|
||
|
class KCmdLineArgsList: public QPtrList<KCmdLineArgs>
|
||
|
{
|
||
|
public:
|
||
|
KCmdLineArgsList() { }
|
||
|
};
|
||
|
|
||
|
KCmdLineArgsList *KCmdLineArgs::argsList = 0;
|
||
|
int KCmdLineArgs::argc = 0;
|
||
|
char **KCmdLineArgs::argv = 0;
|
||
|
char *KCmdLineArgs::mCwd = 0;
|
||
|
static KStaticDeleter <char> mCwdd;
|
||
|
const KAboutData *KCmdLineArgs::about = 0;
|
||
|
bool KCmdLineArgs::parsed = false;
|
||
|
bool KCmdLineArgs::ignoreUnknown = false;
|
||
|
|
||
|
//
|
||
|
// Static functions
|
||
|
//
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::init(int _argc, char **_argv, const char *_appname, const char* programName,
|
||
|
const char *_description, const char *_version, bool noKApp)
|
||
|
{
|
||
|
init(_argc, _argv,
|
||
|
new KAboutData(_appname, programName, _version, _description),
|
||
|
noKApp);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::init(int _argc, char **_argv, const char *_appname,
|
||
|
const char *_description, const char *_version, bool noKApp)
|
||
|
{
|
||
|
init(_argc, _argv,
|
||
|
new KAboutData(_appname, _appname, _version, _description),
|
||
|
noKApp);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::initIgnore(int _argc, char **_argv, const char *_appname )
|
||
|
{
|
||
|
init(_argc, _argv,
|
||
|
new KAboutData(_appname, _appname, "unknown", "KDE Application", false));
|
||
|
ignoreUnknown = true;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::init(const KAboutData* ab)
|
||
|
{
|
||
|
char **_argv = (char **) malloc(sizeof(char *));
|
||
|
_argv[0] = (char *) ab->appName();
|
||
|
init(1,_argv,ab, true);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, bool noKApp)
|
||
|
{
|
||
|
argc = _argc;
|
||
|
argv = _argv;
|
||
|
|
||
|
if (!argv)
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
||
|
fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
|
||
|
// Strip path from argv[0]
|
||
|
if (argc) {
|
||
|
char *p = strrchr( argv[0], '/');
|
||
|
if (p)
|
||
|
argv[0] = p+1;
|
||
|
}
|
||
|
|
||
|
about = _about;
|
||
|
parsed = false;
|
||
|
mCwd = mCwdd.setObject(mCwd, new char [PATH_MAX+1], true);
|
||
|
(void) getcwd(mCwd, PATH_MAX);
|
||
|
#ifdef Q_WS_WIN
|
||
|
win32_slashify(mCwd, PATH_MAX);
|
||
|
#endif
|
||
|
if (!noKApp)
|
||
|
KApplication::addCmdLineOptions();
|
||
|
}
|
||
|
|
||
|
QString KCmdLineArgs::cwd()
|
||
|
{
|
||
|
return QFile::decodeName(QCString(mCwd));
|
||
|
}
|
||
|
|
||
|
const char * KCmdLineArgs::appName()
|
||
|
{
|
||
|
if (!argc) return 0;
|
||
|
return argv[0];
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions *options, const char *name,
|
||
|
const char *id, const char *afterId)
|
||
|
{
|
||
|
if (!argsList)
|
||
|
argsList = new KCmdLineArgsList();
|
||
|
|
||
|
int pos = argsList->count();
|
||
|
|
||
|
if (pos && id && argsList->last() && !argsList->last()->name)
|
||
|
pos--;
|
||
|
|
||
|
KCmdLineArgs *args;
|
||
|
int i = 0;
|
||
|
for(args = argsList->first(); args; args = argsList->next(), i++)
|
||
|
{
|
||
|
if (!id && !args->id)
|
||
|
return; // Options already present.
|
||
|
|
||
|
if (id && args->id && (::qstrcmp(id, args->id) == 0))
|
||
|
return; // Options already present.
|
||
|
|
||
|
if (afterId && args->id && (::qstrcmp(afterId, args->id) == 0))
|
||
|
pos = i+1;
|
||
|
}
|
||
|
|
||
|
assert( parsed == false ); // You must add _ALL_ cmd line options
|
||
|
// before accessing the arguments!
|
||
|
args = new KCmdLineArgs(options, name, id);
|
||
|
argsList->insert(pos, args);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::saveAppArgs( QDataStream &ds)
|
||
|
{
|
||
|
if (!parsed)
|
||
|
parseAllArgs();
|
||
|
|
||
|
// Remove Qt and KDE options.
|
||
|
removeArgs("qt");
|
||
|
removeArgs("kde");
|
||
|
|
||
|
QCString qCwd = mCwd;
|
||
|
ds << qCwd;
|
||
|
|
||
|
uint count = argsList ? argsList->count() : 0;
|
||
|
ds << count;
|
||
|
|
||
|
if (!count) return;
|
||
|
|
||
|
KCmdLineArgs *args;
|
||
|
for(args = argsList->first(); args; args = argsList->next())
|
||
|
{
|
||
|
ds << QCString(args->id);
|
||
|
args->save(ds);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::loadAppArgs( QDataStream &ds)
|
||
|
{
|
||
|
parsed = true; // don't reparse argc/argv!
|
||
|
|
||
|
// Remove Qt and KDE options.
|
||
|
removeArgs("qt");
|
||
|
removeArgs("kde");
|
||
|
|
||
|
KCmdLineArgs *args;
|
||
|
if ( argsList ) {
|
||
|
for(args = argsList->first(); args; args = argsList->next())
|
||
|
{
|
||
|
args->clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ds.atEnd())
|
||
|
return;
|
||
|
|
||
|
QCString qCwd;
|
||
|
ds >> qCwd;
|
||
|
delete [] mCwd;
|
||
|
|
||
|
mCwd = mCwdd.setObject(mCwd, new char[qCwd.length()+1], true);
|
||
|
strncpy(mCwd, qCwd.data(), qCwd.length()+1);
|
||
|
|
||
|
uint count;
|
||
|
ds >> count;
|
||
|
|
||
|
while(count--)
|
||
|
{
|
||
|
QCString id;
|
||
|
ds >> id;
|
||
|
assert( argsList );
|
||
|
for(args = argsList->first(); args; args = argsList->next())
|
||
|
{
|
||
|
if (args->id == id)
|
||
|
{
|
||
|
args->load(ds);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
parsed = true;
|
||
|
}
|
||
|
|
||
|
KCmdLineArgs *KCmdLineArgs::parsedArgs(const char *id)
|
||
|
{
|
||
|
KCmdLineArgs *args = argsList ? argsList->first() : 0;
|
||
|
while(args)
|
||
|
{
|
||
|
if ((id && ::qstrcmp(args->id, id) == 0) || (!id && !args->id))
|
||
|
{
|
||
|
if (!parsed)
|
||
|
parseAllArgs();
|
||
|
return args;
|
||
|
}
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
|
||
|
return args;
|
||
|
}
|
||
|
|
||
|
void KCmdLineArgs::removeArgs(const char *id)
|
||
|
{
|
||
|
KCmdLineArgs *args = argsList ? argsList->first() : 0;
|
||
|
while(args)
|
||
|
{
|
||
|
if (args->id && id && ::qstrcmp(args->id, id) == 0)
|
||
|
{
|
||
|
if (!parsed)
|
||
|
parseAllArgs();
|
||
|
break;
|
||
|
}
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
|
||
|
if (args)
|
||
|
delete args;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* @return:
|
||
|
* 0 - option not found.
|
||
|
* 1 - option found // -fork
|
||
|
* 2 - inverse option found ('no') // -nofork
|
||
|
* 3 - option + arg found // -fork now
|
||
|
*
|
||
|
* +4 - no more options follow // !fork
|
||
|
*/
|
||
|
static int
|
||
|
findOption(const KCmdLineOptions *options, QCString &opt,
|
||
|
const char *&opt_name, const char *&def, bool &enabled)
|
||
|
{
|
||
|
int result;
|
||
|
bool inverse;
|
||
|
int len = opt.length();
|
||
|
while(options && options->name)
|
||
|
{
|
||
|
result = 0;
|
||
|
inverse = false;
|
||
|
opt_name = options->name;
|
||
|
if ((opt_name[0] == ':') || (opt_name[0] == 0))
|
||
|
{
|
||
|
options++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (opt_name[0] == '!')
|
||
|
{
|
||
|
opt_name++;
|
||
|
result = 4;
|
||
|
}
|
||
|
if ((opt_name[0] == 'n') && (opt_name[1] == 'o'))
|
||
|
{
|
||
|
opt_name += 2;
|
||
|
inverse = true;
|
||
|
}
|
||
|
if (strncmp(opt.data(), opt_name, len) == 0)
|
||
|
{
|
||
|
opt_name += len;
|
||
|
if (!opt_name[0])
|
||
|
{
|
||
|
if (inverse)
|
||
|
return result+2;
|
||
|
|
||
|
if (!options->description)
|
||
|
{
|
||
|
options++;
|
||
|
if (!options->name)
|
||
|
return result+0;
|
||
|
QCString nextOption = options->name;
|
||
|
int p = nextOption.find(' ');
|
||
|
if (p > 0)
|
||
|
nextOption = nextOption.left(p);
|
||
|
if (nextOption[0] == '!')
|
||
|
nextOption = nextOption.mid(1);
|
||
|
if (strncmp(nextOption.data(), "no", 2) == 0)
|
||
|
{
|
||
|
nextOption = nextOption.mid(2);
|
||
|
enabled = !enabled;
|
||
|
}
|
||
|
result = findOption(options, nextOption, opt_name, def, enabled);
|
||
|
assert(result);
|
||
|
opt = nextOption;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
if (opt_name[0] == ' ')
|
||
|
{
|
||
|
opt_name++;
|
||
|
def = options->def;
|
||
|
return result+3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
options++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::findOption(const char *_opt, QCString opt, int &i, bool _enabled, bool &moreOptions)
|
||
|
{
|
||
|
KCmdLineArgs *args = argsList->first();
|
||
|
const char *opt_name;
|
||
|
const char *def;
|
||
|
QCString argument;
|
||
|
int j = opt.find('=');
|
||
|
if (j != -1)
|
||
|
{
|
||
|
argument = opt.mid(j+1);
|
||
|
opt = opt.left(j);
|
||
|
}
|
||
|
|
||
|
bool enabled = true;
|
||
|
int result = 0;
|
||
|
while (args)
|
||
|
{
|
||
|
enabled = _enabled;
|
||
|
result = ::findOption(args->options, opt, opt_name, def, enabled);
|
||
|
if (result) break;
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
if (!args && (_opt[0] == '-') && _opt[1] && (_opt[1] != '-'))
|
||
|
{
|
||
|
// Option not found check if it is a valid option
|
||
|
// in the style of -Pprinter1 or ps -aux
|
||
|
int p = 1;
|
||
|
while (true)
|
||
|
{
|
||
|
QCString singleCharOption = " ";
|
||
|
singleCharOption[0] = _opt[p];
|
||
|
args = argsList->first();
|
||
|
while (args)
|
||
|
{
|
||
|
enabled = _enabled;
|
||
|
result = ::findOption(args->options, singleCharOption, opt_name, def, enabled);
|
||
|
if (result) break;
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
if (!args)
|
||
|
break; // Unknown argument
|
||
|
|
||
|
p++;
|
||
|
if (result == 1) // Single option
|
||
|
{
|
||
|
args->setOption(singleCharOption, enabled);
|
||
|
if (_opt[p])
|
||
|
continue; // Next option
|
||
|
else
|
||
|
return; // Finished
|
||
|
}
|
||
|
else if (result == 3) // This option takes an argument
|
||
|
{
|
||
|
if (argument.isEmpty())
|
||
|
{
|
||
|
argument = _opt+p;
|
||
|
}
|
||
|
args->setOption(singleCharOption, argument);
|
||
|
return;
|
||
|
}
|
||
|
break; // Unknown argument
|
||
|
}
|
||
|
args = 0;
|
||
|
result = 0;
|
||
|
}
|
||
|
|
||
|
if (!args || !result)
|
||
|
{
|
||
|
if (ignoreUnknown)
|
||
|
return;
|
||
|
enable_i18n();
|
||
|
usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
|
||
|
}
|
||
|
|
||
|
if ((result & 4) != 0)
|
||
|
{
|
||
|
result &= ~4;
|
||
|
moreOptions = false;
|
||
|
}
|
||
|
|
||
|
if (result == 3) // This option takes an argument
|
||
|
{
|
||
|
if (!enabled)
|
||
|
{
|
||
|
if (ignoreUnknown)
|
||
|
return;
|
||
|
enable_i18n();
|
||
|
usage( i18n("Unknown option '%1'.").arg(QString::fromLocal8Bit(_opt)));
|
||
|
}
|
||
|
if (argument.isEmpty())
|
||
|
{
|
||
|
i++;
|
||
|
if (i >= argc)
|
||
|
{
|
||
|
enable_i18n();
|
||
|
usage( i18n("'%1' missing.").arg( opt_name));
|
||
|
}
|
||
|
argument = argv[i];
|
||
|
}
|
||
|
args->setOption(opt, argument);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
args->setOption(opt, enabled);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::printQ(const QString &msg)
|
||
|
{
|
||
|
QCString localMsg = msg.local8Bit();
|
||
|
fprintf(stdout, "%s", localMsg.data());
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::parseAllArgs()
|
||
|
{
|
||
|
bool allowArgs = false;
|
||
|
bool inOptions = true;
|
||
|
bool everythingAfterArgIsArgs = false;
|
||
|
KCmdLineArgs *appOptions = argsList->last();
|
||
|
if (!appOptions->id)
|
||
|
{
|
||
|
const KCmdLineOptions *option = appOptions->options;
|
||
|
while(option && option->name)
|
||
|
{
|
||
|
if (option->name[0] == '+')
|
||
|
allowArgs = true;
|
||
|
if ( option->name[0] == '!' && option->name[1] == '+' )
|
||
|
{
|
||
|
allowArgs = true;
|
||
|
everythingAfterArgIsArgs = true;
|
||
|
}
|
||
|
option++;
|
||
|
}
|
||
|
}
|
||
|
for(int i = 1; i < argc; i++)
|
||
|
{
|
||
|
if (!argv[i])
|
||
|
continue;
|
||
|
|
||
|
if ((argv[i][0] == '-') && argv[i][1] && inOptions)
|
||
|
{
|
||
|
bool enabled = true;
|
||
|
const char *option = &argv[i][1];
|
||
|
const char *orig = argv[i];
|
||
|
if (option[0] == '-')
|
||
|
{
|
||
|
option++;
|
||
|
argv[i]++;
|
||
|
if (!option[0])
|
||
|
{
|
||
|
inOptions = false;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
if (::qstrcmp(option, "help") == 0)
|
||
|
{
|
||
|
usage(0);
|
||
|
}
|
||
|
else if (strncmp(option, "help-",5) == 0)
|
||
|
{
|
||
|
usage(option+5);
|
||
|
}
|
||
|
else if ( (::qstrcmp(option, "version") == 0) ||
|
||
|
(::qstrcmp(option, "v") == 0))
|
||
|
{
|
||
|
printQ( QString("Qt: %1\n").arg(qVersion()));
|
||
|
printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING));
|
||
|
printQ( QString("%1: %2\n").
|
||
|
arg(about->programName()).arg(about->version()));
|
||
|
exit(0);
|
||
|
} else if ( (::qstrcmp(option, "license") == 0) )
|
||
|
{
|
||
|
enable_i18n();
|
||
|
printQ( about->license() );
|
||
|
printQ( "\n" );
|
||
|
exit(0);
|
||
|
} else if ( ::qstrcmp( option, "author") == 0 ) {
|
||
|
enable_i18n();
|
||
|
if ( about ) {
|
||
|
const QValueList<KAboutPerson> authors = about->authors();
|
||
|
if ( !authors.isEmpty() ) {
|
||
|
QString authorlist;
|
||
|
for (QValueList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
|
||
|
QString email;
|
||
|
if ( !(*it).emailAddress().isEmpty() )
|
||
|
email = " <" + (*it).emailAddress() + ">";
|
||
|
authorlist += QString(" ") + (*it).name() + email + "\n";
|
||
|
}
|
||
|
printQ( i18n("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2").arg ( QString(about->programName()) ).arg( authorlist ) );
|
||
|
}
|
||
|
} else {
|
||
|
printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
|
||
|
}
|
||
|
if (about)
|
||
|
{
|
||
|
if (!about->customAuthorTextEnabled ())
|
||
|
{
|
||
|
if (about->bugAddress().isEmpty() || about->bugAddress() == "submit@bugs.kde.org" )
|
||
|
printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
|
||
|
else {
|
||
|
if( about->authors().count() == 1 && about->authors().first().emailAddress() == about->bugAddress() )
|
||
|
printQ( i18n( "Please report bugs to %1.\n" ).arg( about->authors().first().emailAddress() ) );
|
||
|
else
|
||
|
printQ( i18n( "Please report bugs to %1.\n" ).arg(about->bugAddress()) );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printQ(about->customAuthorPlainText());
|
||
|
}
|
||
|
}
|
||
|
exit(0);
|
||
|
} else {
|
||
|
if ((option[0] == 'n') && (option[1] == 'o'))
|
||
|
{
|
||
|
option += 2;
|
||
|
enabled = false;
|
||
|
}
|
||
|
findOption(orig, option, i, enabled, inOptions);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Check whether appOptions allows these arguments
|
||
|
if (!allowArgs)
|
||
|
{
|
||
|
if (ignoreUnknown)
|
||
|
continue;
|
||
|
enable_i18n();
|
||
|
usage( i18n("Unexpected argument '%1'.").arg(QString::fromLocal8Bit(argv[i])));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
appOptions->addArgument(argv[i]);
|
||
|
if (everythingAfterArgIsArgs)
|
||
|
inOptions = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
parsed = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* For KApplication only:
|
||
|
*
|
||
|
* Return argc
|
||
|
*/
|
||
|
int *
|
||
|
KCmdLineArgs::qt_argc()
|
||
|
{
|
||
|
if (!argsList)
|
||
|
KApplication::addCmdLineOptions(); // Lazy bastards!
|
||
|
|
||
|
static int qt_argc = -1;
|
||
|
if( qt_argc != -1 )
|
||
|
return &qt_argc;
|
||
|
|
||
|
KCmdLineArgs *args = parsedArgs("qt");
|
||
|
assert(args); // No qt options have been added!
|
||
|
if (!argv)
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
||
|
fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
|
||
|
assert(argc >= (args->count()+1));
|
||
|
qt_argc = args->count() +1;
|
||
|
return &qt_argc;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* For KApplication only:
|
||
|
*
|
||
|
* Return argv
|
||
|
*/
|
||
|
char ***
|
||
|
KCmdLineArgs::qt_argv()
|
||
|
{
|
||
|
if (!argsList)
|
||
|
KApplication::addCmdLineOptions(); // Lazy bastards!
|
||
|
|
||
|
static char** qt_argv;
|
||
|
if( qt_argv != NULL )
|
||
|
return &qt_argv;
|
||
|
|
||
|
KCmdLineArgs *args = parsedArgs("qt");
|
||
|
assert(args); // No qt options have been added!
|
||
|
if (!argv)
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
||
|
fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
|
||
|
qt_argv = new char*[ args->count() + 2 ];
|
||
|
qt_argv[ 0 ] = qstrdup( appName());
|
||
|
int i = 0;
|
||
|
for(; i < args->count(); i++)
|
||
|
{
|
||
|
qt_argv[i+1] = qstrdup((char *) args->arg(i));
|
||
|
}
|
||
|
qt_argv[i+1] = 0;
|
||
|
|
||
|
return &qt_argv;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::enable_i18n()
|
||
|
{
|
||
|
// called twice or too late
|
||
|
if (KGlobal::_locale)
|
||
|
return;
|
||
|
|
||
|
if (!KGlobal::_instance) {
|
||
|
KInstance *instance = new KInstance(about);
|
||
|
(void) instance->config();
|
||
|
// Don't delete instance!
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::usage(const QString &error)
|
||
|
{
|
||
|
assert(KGlobal::_locale);
|
||
|
QCString localError = error.local8Bit();
|
||
|
if (localError[error.length()-1] == '\n')
|
||
|
localError = localError.left(error.length()-1);
|
||
|
fprintf(stderr, "%s: %s\n", argv[0], localError.data());
|
||
|
|
||
|
QString tmp = i18n("Use --help to get a list of available command line options.");
|
||
|
localError = tmp.local8Bit();
|
||
|
fprintf(stderr, "%s: %s\n", argv[0], localError.data());
|
||
|
exit(254);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::usage(const char *id)
|
||
|
{
|
||
|
enable_i18n();
|
||
|
assert(argsList != 0); // It's an error to call usage(...) without
|
||
|
// having done addCmdLineOptions first!
|
||
|
|
||
|
QString optionFormatString = " %1 %2\n";
|
||
|
QString optionFormatStringDef = " %1 %2 [%3]\n";
|
||
|
QString optionHeaderString = i18n("\n%1:\n");
|
||
|
QString tmp;
|
||
|
QString usage;
|
||
|
|
||
|
KCmdLineArgs *args = argsList->last();
|
||
|
|
||
|
if (!(args->id) && (args->options) &&
|
||
|
(args->options->name) && (args->options->name[0] != '+'))
|
||
|
{
|
||
|
usage = i18n("[options] ")+usage;
|
||
|
}
|
||
|
|
||
|
while(args)
|
||
|
{
|
||
|
if (args->name)
|
||
|
{
|
||
|
usage = i18n("[%1-options]").arg(args->name)+" "+usage;
|
||
|
}
|
||
|
args = argsList->prev();
|
||
|
}
|
||
|
|
||
|
KCmdLineArgs *appOptions = argsList->last();
|
||
|
if (!appOptions->id)
|
||
|
{
|
||
|
const KCmdLineOptions *option = appOptions->options;
|
||
|
while(option && option->name)
|
||
|
{
|
||
|
if (option->name[0] == '+')
|
||
|
usage = usage + (option->name+1) + " ";
|
||
|
else if ( option->name[0] == '!' && option->name[1] == '+' )
|
||
|
usage = usage + (option->name+2) + " ";
|
||
|
|
||
|
option++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printQ(i18n("Usage: %1 %2\n").arg(argv[0]).arg(usage));
|
||
|
printQ("\n"+about->shortDescription()+"\n");
|
||
|
|
||
|
printQ(optionHeaderString.arg(i18n("Generic options")));
|
||
|
printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
|
||
|
|
||
|
args = argsList->first();
|
||
|
while(args)
|
||
|
{
|
||
|
if (args->name && args->id)
|
||
|
{
|
||
|
QString option = QString("--help-%1").arg(args->id);
|
||
|
QString desc = i18n("Show %1 specific options").arg(args->name);
|
||
|
|
||
|
printQ(optionFormatString.arg(option, -25).arg(desc));
|
||
|
}
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
|
||
|
printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
|
||
|
printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
|
||
|
printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
|
||
|
printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
|
||
|
printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
|
||
|
|
||
|
args = argsList->first(); // Sets current to 1st.
|
||
|
|
||
|
bool showAll = id && (::qstrcmp(id, "all") == 0);
|
||
|
|
||
|
if (!showAll)
|
||
|
{
|
||
|
while(args)
|
||
|
{
|
||
|
if (!id && !args->id) break;
|
||
|
if (id && (::qstrcmp(args->id, id) == 0)) break;
|
||
|
args = argsList->next();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while(args)
|
||
|
{
|
||
|
bool hasArgs = false;
|
||
|
bool hasOptions = false;
|
||
|
QString optionsHeader;
|
||
|
if (args->name)
|
||
|
optionsHeader = optionHeaderString.arg(i18n("%1 options").arg(QString::fromLatin1(args->name)));
|
||
|
else
|
||
|
optionsHeader = i18n("\nOptions:\n");
|
||
|
|
||
|
while (args)
|
||
|
{
|
||
|
const KCmdLineOptions *option = args->options;
|
||
|
QCString opt = "";
|
||
|
//
|
||
|
while(option && option->name)
|
||
|
{
|
||
|
QString description;
|
||
|
QString descriptionRest;
|
||
|
QStringList dl;
|
||
|
|
||
|
// Option header
|
||
|
if (option->name[0] == ':')
|
||
|
{
|
||
|
if (option->description)
|
||
|
{
|
||
|
optionsHeader = "\n"+i18n(option->description);
|
||
|
if (!optionsHeader.endsWith("\n"))
|
||
|
optionsHeader.append("\n");
|
||
|
hasOptions = false;
|
||
|
}
|
||
|
option++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Free-form comment
|
||
|
if (option->name[0] == 0)
|
||
|
{
|
||
|
if (option->description)
|
||
|
{
|
||
|
QString tmp = "\n"+i18n(option->description);
|
||
|
if (!tmp.endsWith("\n"))
|
||
|
tmp.append("\n");
|
||
|
printQ(tmp);
|
||
|
}
|
||
|
option++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Options
|
||
|
if (option->description)
|
||
|
{
|
||
|
description = i18n(option->description);
|
||
|
dl = QStringList::split("\n", description, true);
|
||
|
description = dl.first();
|
||
|
dl.remove( dl.begin() );
|
||
|
}
|
||
|
QCString name = option->name;
|
||
|
if (name[0] == '!')
|
||
|
name = name.mid(1);
|
||
|
|
||
|
if (name[0] == '+')
|
||
|
{
|
||
|
if (!hasArgs)
|
||
|
{
|
||
|
printQ(i18n("\nArguments:\n"));
|
||
|
hasArgs = true;
|
||
|
}
|
||
|
|
||
|
name = name.mid(1);
|
||
|
if ((name[0] == '[') && (name[name.length()-1] == ']'))
|
||
|
name = name.mid(1, name.length()-2);
|
||
|
printQ(optionFormatString.arg(name, -25)
|
||
|
.arg(description));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!hasOptions)
|
||
|
{
|
||
|
printQ(optionsHeader);
|
||
|
hasOptions = true;
|
||
|
}
|
||
|
|
||
|
if ((name.length() == 1) || (name[1] == ' '))
|
||
|
name = "-"+name;
|
||
|
else
|
||
|
name = "--"+name;
|
||
|
if (!option->description)
|
||
|
{
|
||
|
opt = name + ", ";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
opt = opt + name;
|
||
|
if (!option->def)
|
||
|
{
|
||
|
printQ(optionFormatString.arg(opt, -25)
|
||
|
.arg(description));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printQ(optionFormatStringDef.arg(opt, -25)
|
||
|
.arg(description).arg(option->def));
|
||
|
}
|
||
|
opt = "";
|
||
|
}
|
||
|
}
|
||
|
for(QStringList::Iterator it = dl.begin();
|
||
|
it != dl.end();
|
||
|
++it)
|
||
|
{
|
||
|
printQ(optionFormatString.arg("", -25).arg(*it));
|
||
|
}
|
||
|
|
||
|
option++;
|
||
|
}
|
||
|
args = argsList->next();
|
||
|
if (!args || args->name || !args->id) break;
|
||
|
}
|
||
|
if (!showAll) break;
|
||
|
}
|
||
|
|
||
|
exit(254);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Member functions
|
||
|
//
|
||
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*
|
||
|
* The given arguments are assumed to be constants.
|
||
|
*/
|
||
|
KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions *_options,
|
||
|
const char *_name, const char *_id)
|
||
|
: options(_options), name(_name), id(_id)
|
||
|
{
|
||
|
parsedOptionList = 0;
|
||
|
parsedArgList = 0;
|
||
|
isQt = (::qstrcmp(id, "qt") == 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Destructor.
|
||
|
*/
|
||
|
KCmdLineArgs::~KCmdLineArgs()
|
||
|
{
|
||
|
delete parsedOptionList;
|
||
|
delete parsedArgList;
|
||
|
if (argsList)
|
||
|
argsList->removeRef(this);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::clear()
|
||
|
{
|
||
|
delete parsedArgList;
|
||
|
parsedArgList = 0;
|
||
|
delete parsedOptionList;
|
||
|
parsedOptionList = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::reset()
|
||
|
{
|
||
|
if ( argsList ) {
|
||
|
argsList->setAutoDelete( true );
|
||
|
argsList->clear();
|
||
|
delete argsList;
|
||
|
argsList = 0;
|
||
|
}
|
||
|
parsed = false;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::save( QDataStream &ds) const
|
||
|
{
|
||
|
uint count = 0;
|
||
|
if (parsedOptionList)
|
||
|
parsedOptionList->save( ds );
|
||
|
else
|
||
|
ds << count;
|
||
|
|
||
|
if (parsedArgList)
|
||
|
parsedArgList->save( ds );
|
||
|
else
|
||
|
ds << count;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::load( QDataStream &ds)
|
||
|
{
|
||
|
if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
|
||
|
if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
|
||
|
|
||
|
parsedOptionList->load( ds );
|
||
|
parsedArgList->load( ds );
|
||
|
|
||
|
if (parsedOptionList->count() == 0)
|
||
|
{
|
||
|
delete parsedOptionList;
|
||
|
parsedOptionList = 0;
|
||
|
}
|
||
|
if (parsedArgList->count() == 0)
|
||
|
{
|
||
|
delete parsedArgList;
|
||
|
parsedArgList = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::setOption(const QCString &opt, bool enabled)
|
||
|
{
|
||
|
if (isQt)
|
||
|
{
|
||
|
// Qt does it own parsing.
|
||
|
QCString arg = "-";
|
||
|
if( !enabled )
|
||
|
arg += "no";
|
||
|
arg += opt;
|
||
|
addArgument(arg);
|
||
|
}
|
||
|
if (!parsedOptionList) {
|
||
|
parsedOptionList = new KCmdLineParsedOptions;
|
||
|
parsedOptionList->setAutoDelete(true);
|
||
|
}
|
||
|
|
||
|
if (enabled)
|
||
|
parsedOptionList->replace( opt, new QCString("t") );
|
||
|
else
|
||
|
parsedOptionList->replace( opt, new QCString("f") );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::setOption(const QCString &opt, const char *value)
|
||
|
{
|
||
|
if (isQt)
|
||
|
{
|
||
|
// Qt does it's own parsing.
|
||
|
QCString arg = "-";
|
||
|
arg += opt;
|
||
|
addArgument(arg);
|
||
|
addArgument(value);
|
||
|
|
||
|
#ifdef Q_WS_X11
|
||
|
// Hack coming up!
|
||
|
if (arg == "-display")
|
||
|
{
|
||
|
setenv(DISPLAY, value, true);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
if (!parsedOptionList) {
|
||
|
parsedOptionList = new KCmdLineParsedOptions;
|
||
|
parsedOptionList->setAutoDelete(true);
|
||
|
}
|
||
|
|
||
|
parsedOptionList->insert( opt, new QCString(value) );
|
||
|
}
|
||
|
|
||
|
QCString
|
||
|
KCmdLineArgs::getOption(const char *_opt) const
|
||
|
{
|
||
|
QCString *value = 0;
|
||
|
if (parsedOptionList)
|
||
|
{
|
||
|
value = parsedOptionList->find(_opt);
|
||
|
}
|
||
|
|
||
|
if (value)
|
||
|
return (*value);
|
||
|
|
||
|
// Look up the default.
|
||
|
const char *opt_name;
|
||
|
const char *def;
|
||
|
bool dummy = true;
|
||
|
QCString opt = _opt;
|
||
|
int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
|
||
|
|
||
|
if (result != 3)
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
||
|
fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
|
||
|
_opt, _opt);
|
||
|
fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
return QCString(def);
|
||
|
}
|
||
|
|
||
|
QCStringList
|
||
|
KCmdLineArgs::getOptionList(const char *_opt) const
|
||
|
{
|
||
|
QCStringList result;
|
||
|
if (!parsedOptionList)
|
||
|
return result;
|
||
|
|
||
|
while(true)
|
||
|
{
|
||
|
QCString *value = parsedOptionList->take(_opt);
|
||
|
if (!value)
|
||
|
break;
|
||
|
result.prepend(*value);
|
||
|
delete value;
|
||
|
}
|
||
|
|
||
|
// Reinsert items in dictionary
|
||
|
// WABA: This is rather silly, but I don't want to add restrictions
|
||
|
// to the API like "you can only call this function once".
|
||
|
// I can't access all items without taking them out of the list.
|
||
|
// So taking them out and then putting them back is the only way.
|
||
|
for(QCStringList::ConstIterator it=result.begin();
|
||
|
it != result.end();
|
||
|
++it)
|
||
|
{
|
||
|
parsedOptionList->insert(_opt, new QCString(*it));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
KCmdLineArgs::isSet(const char *_opt) const
|
||
|
{
|
||
|
// Look up the default.
|
||
|
const char *opt_name;
|
||
|
const char *def;
|
||
|
bool dummy = true;
|
||
|
QCString opt = _opt;
|
||
|
int result = ::findOption( options, opt, opt_name, def, dummy) & ~4;
|
||
|
|
||
|
if (result == 0)
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
||
|
fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
|
||
|
_opt, _opt);
|
||
|
fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
|
||
|
QCString *value = 0;
|
||
|
if (parsedOptionList)
|
||
|
{
|
||
|
value = parsedOptionList->find(opt);
|
||
|
}
|
||
|
|
||
|
if (value)
|
||
|
{
|
||
|
if (result == 3)
|
||
|
return true;
|
||
|
else
|
||
|
return ((*value)[0] == 't');
|
||
|
}
|
||
|
|
||
|
if (result == 3)
|
||
|
return false; // String option has 'false' as default.
|
||
|
|
||
|
// We return 'true' as default if the option was listed as '-nofork'
|
||
|
// We return 'false' as default if the option was listed as '-fork'
|
||
|
return (result == 2);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
KCmdLineArgs::count() const
|
||
|
{
|
||
|
if (!parsedArgList)
|
||
|
return 0;
|
||
|
return parsedArgList->count();
|
||
|
}
|
||
|
|
||
|
const char *
|
||
|
KCmdLineArgs::arg(int n) const
|
||
|
{
|
||
|
if (!parsedArgList || (n >= (int) parsedArgList->count()))
|
||
|
{
|
||
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
|
||
|
fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
|
||
|
n);
|
||
|
|
||
|
assert( 0 );
|
||
|
exit(255);
|
||
|
}
|
||
|
|
||
|
return parsedArgList->at(n);
|
||
|
}
|
||
|
|
||
|
KURL
|
||
|
KCmdLineArgs::url(int n) const
|
||
|
{
|
||
|
return makeURL( arg(n) );
|
||
|
}
|
||
|
|
||
|
KURL KCmdLineArgs::makeURL(const char *_urlArg)
|
||
|
{
|
||
|
const QString urlArg = QFile::decodeName(_urlArg);
|
||
|
QFileInfo fileInfo(urlArg);
|
||
|
if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix
|
||
|
KURL result;
|
||
|
result.setPath(urlArg);
|
||
|
return result; // Absolute path.
|
||
|
}
|
||
|
|
||
|
if ( KURL::isRelativeURL(urlArg) || fileInfo.exists() ) {
|
||
|
KURL result;
|
||
|
result.setPath( cwd()+'/'+urlArg );
|
||
|
result.cleanPath();
|
||
|
return result; // Relative path
|
||
|
}
|
||
|
|
||
|
return KURL(urlArg); // Argument is a URL
|
||
|
}
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::addArgument(const char *argument)
|
||
|
{
|
||
|
if (!parsedArgList)
|
||
|
parsedArgList = new KCmdLineParsedArgs;
|
||
|
|
||
|
parsedArgList->append(argument);
|
||
|
}
|
||
|
|
||
|
static const KCmdLineOptions kde_tempfile_option[] =
|
||
|
{
|
||
|
{ "tempfile", I18N_NOOP("The files/URLs opened by the application will be deleted after use"), 0},
|
||
|
KCmdLineLastOption
|
||
|
};
|
||
|
|
||
|
void
|
||
|
KCmdLineArgs::addTempFileOption()
|
||
|
{
|
||
|
KCmdLineArgs::addCmdLineOptions( kde_tempfile_option, "KDE-tempfile", "kde-tempfile" );
|
||
|
}
|
||
|
|
||
|
bool KCmdLineArgs::isTempFileSet()
|
||
|
{
|
||
|
KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
|
||
|
if ( args )
|
||
|
return args->isSet( "tempfile" );
|
||
|
return false;
|
||
|
}
|