mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 02:42:48 +00:00

optional feature that requires "-tray" command line argument and replaces what the `ksystraycmd` program was doing. requires "X-KDE-SysTray" entry in the desktop file as indicator that the application supports "-tray" argument, unlike `ksystraycmd` does not spawn extra process and even session management will work properly for it (the argument is manually added to the restart command) the feature is very much tide to KMainWindow (and derived classes) but the overhead is next to none when the "-tray" argument is not specified (the status notifier is not created in such case) however if created an expensive tooltip update is done whenever a window changes (may have to look into optimizing it but then again - most of the code does nothing unless the "-tray" argument is specified) Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
1561 lines
42 KiB
C++
1561 lines
42 KiB
C++
/*
|
|
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 "kcmdlineargs.h"
|
|
#include "kdebug.h"
|
|
#include "kglobalsettings.h"
|
|
#include "kaboutdata.h"
|
|
#include "klocale.h"
|
|
#include "kdeversion.h"
|
|
#include "kcomponentdata.h"
|
|
#include "kglobal.h"
|
|
#include "kurl.h"
|
|
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QHash>
|
|
#include <QtCore/QTextCodec>
|
|
|
|
#include <sys/param.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <locale.h>
|
|
#include <limits.h>
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Design notes:
|
|
//
|
|
// These classes deal with a lot of text, some of which needs to be
|
|
// marked for translation. Since at the time when these object and calls are
|
|
// made the translation catalogs are usually still not initialized, the
|
|
// translation has to be delayed. This is achieved by using KLocalizedString
|
|
// for translatable strings. KLocalizedStrings are produced by ki18n* calls,
|
|
// instead of the more usuall i18n* calls which produce QString by trying to
|
|
// translate immediately.
|
|
//
|
|
// All the non-translatable string arguments to methods are taken QByteArray,
|
|
// all the translatable are KLocalizedString. The getter methods always return
|
|
// proper QString: the non-translatable strings supplied by the code are
|
|
// treated with QString::fromUtf8(), those coming from the outside with
|
|
// QTextCodec::toUnicode(), and translatable strings are finalized to QStrings
|
|
// at the point of getter calls (i.e. delayed translation).
|
|
//
|
|
// The code below uses locally defined s->decodeInput(QByteArray) and
|
|
// s->encodeOutput(QString) calls to centralize the conversion of raw external
|
|
// bytes (instead of QString::to/fromLocal8Bit(), QFile::decodeName, etc.)
|
|
// -----------------------------------------------------------------------------
|
|
|
|
#ifdef Q_WS_X11
|
|
#define DISPLAY "DISPLAY"
|
|
#else
|
|
#define DISPLAY "NODISPLAY"
|
|
#endif
|
|
|
|
//
|
|
// Helper classes
|
|
//
|
|
|
|
class KCmdLineParsedOptions : public QHash<QByteArray,QByteArray>
|
|
{
|
|
public:
|
|
KCmdLineParsedOptions() { }
|
|
};
|
|
|
|
class KCmdLineParsedArgs : public QList<QByteArray>
|
|
{
|
|
public:
|
|
KCmdLineParsedArgs() { }
|
|
};
|
|
|
|
|
|
class KCmdLineArgsList: public QList<KCmdLineArgs*>
|
|
{
|
|
public:
|
|
KCmdLineArgsList() { }
|
|
~KCmdLineArgsList() {
|
|
while (count())
|
|
delete takeFirst();
|
|
}
|
|
};
|
|
|
|
//
|
|
// KCmdLineOptions
|
|
//
|
|
|
|
class KCmdLineOptionsPrivate {
|
|
public:
|
|
QList<QByteArray> names;
|
|
QList<KLocalizedString> descriptions;
|
|
QStringList defaults;
|
|
};
|
|
|
|
KCmdLineOptions::KCmdLineOptions ()
|
|
: d(new KCmdLineOptionsPrivate)
|
|
{}
|
|
|
|
KCmdLineOptions::~KCmdLineOptions ()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
KCmdLineOptions::KCmdLineOptions (const KCmdLineOptions &options)
|
|
: d(new KCmdLineOptionsPrivate(*(options.d)))
|
|
{
|
|
}
|
|
|
|
KCmdLineOptions& KCmdLineOptions::operator= (const KCmdLineOptions &options)
|
|
{
|
|
if (this != &options) {
|
|
*d = *(options.d);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
KCmdLineOptions &KCmdLineOptions::add (const QByteArray &name,
|
|
const KLocalizedString &description,
|
|
const QByteArray &defaultValue)
|
|
{
|
|
d->names.append(name);
|
|
d->descriptions.append(description);
|
|
d->defaults.append(QString::fromUtf8(defaultValue));
|
|
return *this;
|
|
}
|
|
|
|
KCmdLineOptions &KCmdLineOptions::add (const KCmdLineOptions &other)
|
|
{
|
|
d->names += other.d->names;
|
|
d->descriptions += other.d->descriptions;
|
|
d->defaults += other.d->defaults;
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
// KCmdLineArgs static data and methods
|
|
//
|
|
|
|
class KCmdLineArgsStatic {
|
|
public:
|
|
|
|
KCmdLineArgsList *argsList; // All options.
|
|
const KAboutData *about;
|
|
|
|
int all_argc; // The original argc
|
|
char **all_argv; // The original argv
|
|
char *appName;
|
|
bool parsed : 1; // Whether we have parsed the arguments since calling init
|
|
bool ignoreUnknown : 1; // Ignore unknown options and arguments
|
|
QByteArray mCwd; // Current working directory. Important for KUnqiueApp!
|
|
KCmdLineArgs::StdCmdLineArgs mStdargs;
|
|
|
|
KCmdLineOptions qt_options;
|
|
KCmdLineOptions kde_options;
|
|
|
|
KCmdLineArgsStatic ();
|
|
|
|
~KCmdLineArgsStatic ();
|
|
|
|
QTextCodec *codec; // codec for converting raw input to QString
|
|
|
|
/**
|
|
* @internal
|
|
* Convertes raw command line argument data to proper QString.
|
|
*
|
|
* @param rawstr raw text
|
|
* @return properly decoded QString
|
|
*/
|
|
static QString decodeInput(const QByteArray &rawstr);
|
|
|
|
/**
|
|
* @internal
|
|
* Convertes QString to raw command line output.
|
|
*
|
|
* @param str string to be encoded
|
|
* @return raw text
|
|
*/
|
|
static QByteArray encodeOutput(const QString &str);
|
|
|
|
/**
|
|
* @internal
|
|
* Shell output with proper decoding.
|
|
*/
|
|
void printQ(const QString &msg);
|
|
|
|
/**
|
|
* @internal
|
|
* Try to match given option in the list of options.
|
|
* Returns match status.
|
|
*
|
|
* @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, QByteArray &opt,
|
|
QByteArray &opt_name, QString &def, bool &enabled);
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Checks what to do with a single option
|
|
*/
|
|
static void findOption(const QByteArray &optv, const QByteArray &_opt,
|
|
int &i, bool _enabled, bool &moreOptions);
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Parse all arguments, verify correct syntax and put all arguments
|
|
* where they belong.
|
|
*/
|
|
static void parseAllArgs();
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Remove named options.
|
|
*
|
|
* @param id The name of the options to be removed.
|
|
*/
|
|
static void removeArgs(const QByteArray &id);
|
|
};
|
|
|
|
K_GLOBAL_STATIC(KCmdLineArgsStatic, s)
|
|
|
|
KCmdLineArgsStatic::KCmdLineArgsStatic () {
|
|
// Global data
|
|
argsList = 0;
|
|
all_argc = 0;
|
|
all_argv = 0;
|
|
appName = 0;
|
|
mCwd.clear();
|
|
about = 0;
|
|
parsed = false;
|
|
ignoreUnknown = false;
|
|
mStdargs = 0;
|
|
|
|
// Text codec.
|
|
codec = QTextCodec::codecForLocale();
|
|
|
|
// Qt options
|
|
//FIXME: Check if other options are specific to Qt/X11
|
|
#ifdef Q_WS_X11
|
|
qt_options.add("display <displayname>", ki18n("Use the X-server display 'displayname'"));
|
|
#endif
|
|
qt_options.add("session <sessionId>", ki18n("Restore the application for the given 'sessionId'"));
|
|
qt_options.add("nograb", ki18n("tells Katie to never grab the mouse or the keyboard"));
|
|
qt_options.add("dograb", ki18n("running under a debugger can cause an implicit\n-nograb, use -dograb to override"));
|
|
qt_options.add("sync", ki18n("switches to synchronous mode for debugging"));
|
|
qt_options.add("title <title>", ki18n("sets the application title (caption)"));
|
|
qt_options.add("reverse", ki18n("mirrors the whole layout of widgets"));
|
|
qt_options.add("stylesheet <file.qss>", ki18n("applies the Katie stylesheet to the application widgets"));
|
|
qt_options.add("style <style>", ki18n("sets the application GUI style"));
|
|
// KDE options
|
|
kde_options.add("caption <caption>", ki18n("Use 'caption' as name in the titlebar"));
|
|
kde_options.add("icon <icon>", ki18n("Use 'icon' as the application icon"));
|
|
kde_options.add("config <filename>", ki18n("Use alternative configuration file"));
|
|
kde_options.add("nocrashhandler", ki18n("Disable crash handler, to get core dumps"));
|
|
#ifdef Q_WS_X11
|
|
kde_options.add("waitforwm", ki18n("Waits for a WM_NET compatible windowmanager"));
|
|
#endif
|
|
kde_options.add("tray", ki18n("Show tray icon"));
|
|
kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format (usually WidthxHeight+XPos+YPos)"));
|
|
kde_options.add("smkey <sessionKey>"); // this option is obsolete and exists only to allow smooth upgrades from sessions
|
|
}
|
|
|
|
KCmdLineArgsStatic::~KCmdLineArgsStatic ()
|
|
{
|
|
delete argsList;
|
|
// KAboutData object is deleted by ~KCleanUpGlobalStatic.
|
|
//delete about;
|
|
}
|
|
|
|
//
|
|
// KCmdLineArgs private data and methods
|
|
//
|
|
|
|
class KCmdLineArgsPrivate
|
|
{
|
|
friend class KCmdLineArgsStatic;
|
|
public:
|
|
KCmdLineArgsPrivate(const KCmdLineOptions &_options, const KLocalizedString &_name, const QByteArray &_id)
|
|
: options(_options)
|
|
, name(_name)
|
|
, id(_id)
|
|
, parsedOptionList(0)
|
|
, parsedArgList(0)
|
|
, isQt(id == "qt")
|
|
{
|
|
}
|
|
~KCmdLineArgsPrivate()
|
|
{
|
|
delete parsedOptionList;
|
|
delete parsedArgList;
|
|
}
|
|
const KCmdLineOptions options;
|
|
const KLocalizedString name;
|
|
const QByteArray id;
|
|
KCmdLineParsedOptions *parsedOptionList;
|
|
KCmdLineParsedArgs *parsedArgList;
|
|
bool isQt;
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Set a boolean option
|
|
*/
|
|
void setOption(const QByteArray &option, bool enabled);
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Set a string option
|
|
*/
|
|
void setOption(const QByteArray &option, const QByteArray &value);
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Add an argument
|
|
*/
|
|
void addArgument(const QByteArray &argument);
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Save to a stream.
|
|
*/
|
|
void save( QDataStream &) const;
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* Restore from a stream.
|
|
*/
|
|
void load( QDataStream &);
|
|
};
|
|
|
|
//
|
|
// Static functions
|
|
//
|
|
|
|
QString
|
|
KCmdLineArgsStatic::decodeInput(const QByteArray &rawstr)
|
|
{
|
|
return s->codec->toUnicode(rawstr);
|
|
}
|
|
|
|
QByteArray
|
|
KCmdLineArgsStatic::encodeOutput(const QString &str)
|
|
{
|
|
return s->codec->fromUnicode(str);
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsStatic::printQ(const QString &msg)
|
|
{
|
|
fprintf(stdout, "%s", encodeOutput(msg).data());
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::init(int _argc, char **_argv,
|
|
const QByteArray &_appname,
|
|
const QByteArray &_catalog,
|
|
const KLocalizedString &_programName,
|
|
const QByteArray &_version,
|
|
const KLocalizedString &_description,
|
|
StdCmdLineArgs stdargs)
|
|
{
|
|
init(_argc, _argv,
|
|
new KAboutData(_appname, _catalog, _programName, _version, _description),
|
|
stdargs);
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::initIgnore(int _argc, char **_argv, const QByteArray &_appname )
|
|
{
|
|
init(_argc, _argv,
|
|
new KAboutData(_appname, 0, ki18n(_appname), "unknown", ki18n("KDE Application")));
|
|
s->ignoreUnknown = true;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::init(const KAboutData* ab)
|
|
{
|
|
char **_argv = (char **) malloc(sizeof(char *));
|
|
_argv[0] = (char *) s->encodeOutput(ab->appName()).data();
|
|
init(1,_argv,ab, CmdLineArgNone);
|
|
}
|
|
|
|
|
|
void
|
|
KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, StdCmdLineArgs stdargs)
|
|
{
|
|
s->all_argc = _argc;
|
|
s->all_argv = _argv;
|
|
|
|
if (!s->all_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 (s->all_argc) {
|
|
char *p = strrchr(s->all_argv[0], QDir::separator().toLatin1());
|
|
if (p)
|
|
s->appName = p+1;
|
|
else
|
|
s->appName = s->all_argv[0];
|
|
}
|
|
|
|
s->about = _about;
|
|
s->parsed = false;
|
|
s->mCwd = QDir::currentPath().toLocal8Bit(); //currentPath() uses fromLocal8Bit internally apparently
|
|
addStdCmdLineOptions(stdargs);
|
|
}
|
|
|
|
QString KCmdLineArgs::cwd()
|
|
{
|
|
return QString::fromLocal8Bit(s->mCwd);
|
|
}
|
|
|
|
QString KCmdLineArgs::appName()
|
|
{
|
|
if (!s->appName) return QString();
|
|
return s->decodeInput(s->appName);
|
|
}
|
|
|
|
/**
|
|
* Add Qt and KDE command line options to KCmdLineArgs.
|
|
*/
|
|
void KCmdLineArgs::addStdCmdLineOptions(StdCmdLineArgs stdargs) {
|
|
if (stdargs & KCmdLineArgs::CmdLineArgQt) {
|
|
KCmdLineArgs::addCmdLineOptions(s->qt_options, ki18n("Katie"), "qt");
|
|
}
|
|
if (stdargs & KCmdLineArgs::CmdLineArgKDE) {
|
|
KCmdLineArgs::addCmdLineOptions(s->kde_options, ki18n("KDE"), "kde");
|
|
}
|
|
s->mStdargs = stdargs;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions &options, const KLocalizedString &name,
|
|
const QByteArray &id, const QByteArray &afterId)
|
|
{
|
|
if (!s->argsList)
|
|
s->argsList = new KCmdLineArgsList;
|
|
|
|
int pos = s->argsList->count();
|
|
// To make sure that the named options come before unnamed.
|
|
if (pos > 0 && !id.isEmpty() && s->argsList->last()->d->name.isEmpty())
|
|
pos--;
|
|
|
|
KCmdLineArgsList::Iterator args;
|
|
int i = 0;
|
|
for(args = s->argsList->begin(); args != s->argsList->end(); ++args, i++)
|
|
{
|
|
if (id == (*args)->d->id) {
|
|
return; // Options already present.
|
|
}
|
|
|
|
// Only check for afterId if it has been given non-empty, as the
|
|
// unnamed option group should come after all named groups.
|
|
if (!afterId.isEmpty() && afterId == (*args)->d->id)
|
|
pos = i+1;
|
|
}
|
|
|
|
Q_ASSERT( s->parsed == false ); // You must add _ALL_ cmd line options
|
|
// before accessing the arguments!
|
|
s->argsList->insert(pos, new KCmdLineArgs(options, name, id));
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::saveAppArgs( QDataStream &ds)
|
|
{
|
|
if (!s->parsed)
|
|
s->parseAllArgs();
|
|
|
|
// Remove Qt and KDE options.
|
|
s->removeArgs("qt");
|
|
s->removeArgs("kde");
|
|
|
|
ds << s->mCwd;
|
|
|
|
uint count = s->argsList ? s->argsList->count() : 0;
|
|
ds << count;
|
|
|
|
if (!count) return;
|
|
|
|
KCmdLineArgsList::Iterator args;
|
|
for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
|
|
{
|
|
ds << (*args)->d->id;
|
|
(*args)->d->save(ds);
|
|
}
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::loadAppArgs( QDataStream &ds)
|
|
{
|
|
s->parsed = true; // don't reparse argc/argv!
|
|
|
|
// Remove Katie and KDE options.
|
|
s->removeArgs("qt");
|
|
s->removeArgs("kde");
|
|
|
|
KCmdLineArgsList::Iterator args;
|
|
if ( s->argsList ) {
|
|
for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
|
|
{
|
|
(*args)->clear();
|
|
}
|
|
}
|
|
|
|
if (ds.atEnd())
|
|
return;
|
|
|
|
QByteArray qCwd;
|
|
ds >> qCwd;
|
|
|
|
s->mCwd = qCwd;
|
|
|
|
uint count;
|
|
ds >> count;
|
|
|
|
while(count--)
|
|
{
|
|
QByteArray id;
|
|
ds >> id;
|
|
Q_ASSERT( s->argsList );
|
|
bool found = false;
|
|
for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
|
|
{
|
|
if ((*args)->d->id == id)
|
|
{
|
|
(*args)->d->load(ds);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
kWarning() << "Argument definitions for" << id << "not found!";
|
|
// The next ds >> id will do nonsensical things...
|
|
}
|
|
}
|
|
s->parsed = true;
|
|
}
|
|
|
|
KCmdLineArgs *KCmdLineArgs::parsedArgs(const QByteArray &id)
|
|
{
|
|
if (!s->argsList)
|
|
return 0;
|
|
KCmdLineArgsList::Iterator args = s->argsList->begin();
|
|
while(args != s->argsList->end())
|
|
{
|
|
if ((*args)->d->id == id)
|
|
{
|
|
if (!s->parsed)
|
|
s->parseAllArgs();
|
|
return *args;
|
|
}
|
|
++args;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void KCmdLineArgsStatic::removeArgs(const QByteArray &id)
|
|
{
|
|
if (!s->argsList)
|
|
return;
|
|
KCmdLineArgsList::Iterator args = s->argsList->begin();
|
|
while(args != s->argsList->end())
|
|
{
|
|
if ((*args)->d->id == id)
|
|
{
|
|
if (!s->parsed)
|
|
s->parseAllArgs();
|
|
break;
|
|
}
|
|
++args;
|
|
}
|
|
|
|
if (args != s->argsList->end()) {
|
|
KCmdLineArgs *a = *args;
|
|
s->argsList->erase(args);
|
|
delete a;
|
|
}
|
|
}
|
|
|
|
int
|
|
KCmdLineArgsStatic::findOption(const KCmdLineOptions &options, QByteArray &opt,
|
|
QByteArray &opt_name, QString &def, bool &enabled)
|
|
{
|
|
for (int i = 0; i < options.d->names.size(); i++)
|
|
{
|
|
int result = 0;
|
|
bool inverse = false;
|
|
opt_name = options.d->names[i];
|
|
if (opt_name.startsWith(':') || opt_name.isEmpty())
|
|
{
|
|
continue;
|
|
}
|
|
if (opt_name.startsWith('!'))
|
|
{
|
|
opt_name = opt_name.mid(1);
|
|
result = 4;
|
|
}
|
|
if (opt_name.startsWith("no") && !opt_name.contains('<')) // krazy:exclude=strings
|
|
{
|
|
opt_name = opt_name.mid(2);
|
|
inverse = true;
|
|
}
|
|
|
|
int len = opt.length();
|
|
if (opt == opt_name.left(len))
|
|
{
|
|
opt_name = opt_name.mid(len);
|
|
if (opt_name.isEmpty())
|
|
{
|
|
if (inverse)
|
|
return result+2;
|
|
|
|
if (options.d->descriptions[i].isEmpty())
|
|
{
|
|
i++;
|
|
if (i >= options.d->names.size())
|
|
return result+0;
|
|
QByteArray nextOption = options.d->names[i];
|
|
int p = nextOption.indexOf(' ');
|
|
if (p > 0)
|
|
nextOption = nextOption.left(p);
|
|
if (nextOption.startsWith('!'))
|
|
nextOption = nextOption.mid(1);
|
|
if (nextOption.startsWith("no") && !nextOption.contains('<')) // krazy:exclude=strings
|
|
{
|
|
nextOption = nextOption.mid(2);
|
|
enabled = !enabled;
|
|
}
|
|
result = findOption(options, nextOption, opt_name, def, enabled);
|
|
Q_ASSERT(result);
|
|
opt = nextOption;
|
|
return result;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
if (opt_name.startsWith(' '))
|
|
{
|
|
opt_name = opt_name.mid(1);
|
|
def = options.d->defaults[i];
|
|
return result+3;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsStatic::findOption(const QByteArray &optv, const QByteArray &_opt,
|
|
int &i, bool _enabled, bool &moreOptions)
|
|
{
|
|
KCmdLineArgsList::Iterator args = s->argsList->begin();
|
|
QByteArray opt = _opt;
|
|
QByteArray opt_name;
|
|
QString def;
|
|
QByteArray argument;
|
|
int j = opt.indexOf('=');
|
|
if (j != -1)
|
|
{
|
|
argument = opt.mid(j+1);
|
|
opt = opt.left(j);
|
|
}
|
|
|
|
bool enabled = true;
|
|
int result = 0;
|
|
while (args != s->argsList->end())
|
|
{
|
|
enabled = _enabled;
|
|
result = findOption((*args)->d->options, opt, opt_name, def, enabled);
|
|
if (result) break;
|
|
++args;
|
|
}
|
|
if ((args == s->argsList->end()) &&
|
|
(optv.startsWith('-') && !optv.startsWith("--"))) // krazy:exclude=strings
|
|
{
|
|
// Option not found check if it is a valid option
|
|
// in the style of -Pprinter1 or ps -aux
|
|
int p = 1;
|
|
while (true)
|
|
{
|
|
QByteArray singleCharOption = " "; // krazy:exclude=doublequote_chars
|
|
singleCharOption[0] = optv[p];
|
|
args = s->argsList->begin();
|
|
while (args != s->argsList->end())
|
|
{
|
|
enabled = _enabled;
|
|
result = findOption((*args)->d->options, singleCharOption,
|
|
opt_name, def, enabled);
|
|
if (result) break;
|
|
++args;
|
|
}
|
|
if (args == s->argsList->end())
|
|
break; // Unknown argument
|
|
|
|
p++;
|
|
if (result == 1) // Single option
|
|
{
|
|
(*args)->d->setOption(singleCharOption, enabled);
|
|
if (p < optv.length())
|
|
continue; // Next option
|
|
else
|
|
return; // Finished
|
|
}
|
|
else if (result == 3) // This option takes an argument
|
|
{
|
|
if (argument.isEmpty())
|
|
{
|
|
argument = optv.mid(p);
|
|
}
|
|
(*args)->d->setOption(singleCharOption, argument);
|
|
return;
|
|
}
|
|
break; // Unknown argument
|
|
}
|
|
args = s->argsList->end();
|
|
result = 0;
|
|
}
|
|
|
|
if (args == s->argsList->end() || !result)
|
|
{
|
|
if (s->ignoreUnknown)
|
|
return;
|
|
KCmdLineArgs::enable_i18n();
|
|
KCmdLineArgs::usageError( i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt)));
|
|
}
|
|
|
|
if ((result & 4) != 0)
|
|
{
|
|
result &= ~4;
|
|
moreOptions = false;
|
|
}
|
|
|
|
if (result == 3) // This option takes an argument
|
|
{
|
|
if (!enabled)
|
|
{
|
|
if (s->ignoreUnknown)
|
|
return;
|
|
KCmdLineArgs::enable_i18n();
|
|
KCmdLineArgs::usageError( i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt)));
|
|
}
|
|
if (argument.isEmpty())
|
|
{
|
|
i++;
|
|
if (i >= s->all_argc)
|
|
{
|
|
KCmdLineArgs::enable_i18n();
|
|
KCmdLineArgs::usageError( i18nc("@info:shell %1 is cmdoption name","'%1' missing.", QString::fromLocal8Bit(opt_name)));
|
|
}
|
|
argument = s->all_argv[i];
|
|
}
|
|
(*args)->d->setOption(opt, argument);
|
|
}
|
|
else
|
|
{
|
|
(*args)->d->setOption(opt, enabled);
|
|
}
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsStatic::parseAllArgs()
|
|
{
|
|
bool allowArgs = false;
|
|
bool inOptions = true;
|
|
bool everythingAfterArgIsArgs = false;
|
|
KCmdLineArgs *appOptions = s->argsList->last();
|
|
if (appOptions->d->id.isEmpty())
|
|
{
|
|
foreach(const QByteArray& name, appOptions->d->options.d->names)
|
|
{
|
|
everythingAfterArgIsArgs = everythingAfterArgIsArgs || name.startsWith("!+");
|
|
allowArgs = allowArgs || name.startsWith('+') || everythingAfterArgIsArgs;
|
|
}
|
|
}
|
|
for(int i = 1; i < s->all_argc; i++)
|
|
{
|
|
if (!s->all_argv[i])
|
|
continue;
|
|
|
|
if ((s->all_argv[i][0] == '-') && s->all_argv[i][1] && inOptions)
|
|
{
|
|
bool enabled = true;
|
|
QByteArray orig = s->all_argv[i];
|
|
QByteArray option = orig.mid(1);
|
|
if (option.startsWith('-'))
|
|
{
|
|
option = option.mid(1);
|
|
if (option.isEmpty())
|
|
{
|
|
inOptions = false;
|
|
continue;
|
|
}
|
|
}
|
|
if (option == "help")
|
|
{
|
|
KCmdLineArgs::usage();
|
|
}
|
|
else if (option.startsWith("help-")) // krazy:exclude=strings
|
|
{
|
|
KCmdLineArgs::usage(option.mid(5));
|
|
}
|
|
else if ((option == "version") || (option == "v"))
|
|
{
|
|
KCmdLineArgs::enable_i18n();
|
|
s->printQ(i18nc("@info:shell message on appcmd --version; do not translate 'Development Platform'"
|
|
"%3 application name, other %n version strings",
|
|
"Katie: %1\n"
|
|
"Katana Development Platform: %2\n"
|
|
"%3: %4\n",
|
|
QString::fromLatin1(qVersion()),
|
|
QString::fromLatin1(KDE_VERSION_STRING),
|
|
s->about->programName(), s->about->version()));
|
|
exit(0);
|
|
} else if (option == "license")
|
|
{
|
|
KCmdLineArgs::enable_i18n();
|
|
s->printQ(s->about->license());
|
|
s->printQ(QString::fromLatin1("\n"));
|
|
exit(0);
|
|
} else if (option == "author") {
|
|
KCmdLineArgs::enable_i18n();
|
|
if ( s->about ) {
|
|
const QList<KAboutPerson> authors = s->about->authors();
|
|
if ( !authors.isEmpty() ) {
|
|
QString authorlist;
|
|
for (QList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
|
|
QString email;
|
|
if ( !(*it).emailAddress().isEmpty() )
|
|
email = QString::fromLatin1(" <") + (*it).emailAddress() + QLatin1String(">");
|
|
authorlist += QString::fromLatin1(" ") + (*it).name() + email + QLatin1Char('\n');
|
|
}
|
|
s->printQ( i18nc("the 2nd argument is a list of name+address, one on each line","%1 was written by\n%2", QString(s->about->programName()) , authorlist ) );
|
|
}
|
|
} else {
|
|
s->printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
|
|
}
|
|
if (s->about)
|
|
{
|
|
if (s->about->bugAddress().isEmpty() || s->about->bugAddress() == QLatin1String(KDE_BUG_REPORT_EMAIL))
|
|
s->printQ( i18n( "Please use %1.\n", QLatin1String(KDE_BUG_REPORT_URL) ) );
|
|
}
|
|
exit(0);
|
|
} else {
|
|
if (option.startsWith("no")) // krazy:exclude=strings
|
|
{
|
|
bool noHasParameter=false;
|
|
foreach(const QByteArray& name, appOptions->d->options.d->names)
|
|
{
|
|
if (name.contains(option + QByteArray(" ")) && name.contains('<'))
|
|
{
|
|
noHasParameter=true;
|
|
break;
|
|
}
|
|
}
|
|
if (!noHasParameter)
|
|
{
|
|
option = option.mid(2);
|
|
enabled = false;
|
|
}
|
|
}
|
|
s->findOption(orig, option, i, enabled, inOptions);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check whether appOptions allows these arguments
|
|
if (!allowArgs)
|
|
{
|
|
if (s->ignoreUnknown)
|
|
continue;
|
|
KCmdLineArgs::enable_i18n();
|
|
KCmdLineArgs::usageError(i18n("Unexpected argument '%1'.", Qt::escape(s->decodeInput(s->all_argv[i]))));
|
|
}
|
|
else
|
|
{
|
|
appOptions->d->addArgument(s->all_argv[i]);
|
|
if (everythingAfterArgIsArgs)
|
|
inOptions = false;
|
|
}
|
|
}
|
|
}
|
|
s->parsed = true;
|
|
}
|
|
|
|
int & KCmdLineArgs::qtArgc()
|
|
{
|
|
if (!s->argsList)
|
|
addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt); // Lazy bastards!
|
|
|
|
static int qt_argc = -1;
|
|
if( qt_argc != -1 )
|
|
return qt_argc;
|
|
|
|
if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
|
|
{
|
|
qt_argc = 2;
|
|
return qt_argc;
|
|
}
|
|
|
|
KCmdLineArgs *args = parsedArgs("qt");
|
|
Q_ASSERT(args); // No qt options have been added!
|
|
if (!s->all_argv)
|
|
{
|
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
|
fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
|
|
|
|
assert( 0 );
|
|
exit(255);
|
|
}
|
|
|
|
Q_ASSERT(s->all_argc >= (args->count()+1));
|
|
qt_argc = args->count() +1;
|
|
return qt_argc;
|
|
}
|
|
|
|
static char** s_qt_argv = nullptr;
|
|
|
|
char **
|
|
KCmdLineArgs::qtArgv()
|
|
{
|
|
if (!s->argsList)
|
|
addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt); // Lazy bastards!
|
|
|
|
if( s_qt_argv != nullptr )
|
|
return s_qt_argv;
|
|
|
|
if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
|
|
{
|
|
s_qt_argv = new char*[2];
|
|
s_qt_argv[0] = qstrdup(s->all_argc?s->all_argv[0]:"");
|
|
s_qt_argv[1] = 0;
|
|
|
|
return s_qt_argv;
|
|
}
|
|
|
|
KCmdLineArgs *args = parsedArgs("qt");
|
|
if (!args)
|
|
{
|
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
|
fprintf(stderr, "The \"qt\" options have not be added to KCmdLineArgs!\n\n");
|
|
|
|
assert( 0 );
|
|
exit(255);
|
|
}
|
|
if (!s->all_argv)
|
|
{
|
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
|
fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
|
|
|
|
assert( 0 );
|
|
exit(255);
|
|
}
|
|
|
|
int count=args->count();
|
|
s_qt_argv = new char*[ count + 2 ];
|
|
s_qt_argv[0] = qstrdup(s->all_argc?s->all_argv[0]:"");
|
|
int i = 0;
|
|
for(; i < count; i++)
|
|
{
|
|
s_qt_argv[i+1] = qstrdup(args->d->parsedArgList->at(i));
|
|
}
|
|
s_qt_argv[i+1] = 0;
|
|
|
|
return s_qt_argv;
|
|
}
|
|
|
|
const KAboutData *
|
|
KCmdLineArgs::aboutData()
|
|
{
|
|
return s->about;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::enable_i18n()
|
|
{
|
|
// called twice or too late
|
|
if (KGlobal::hasLocale())
|
|
return;
|
|
|
|
if (!KGlobal::hasMainComponent()) {
|
|
KComponentData mainComponentData(s->about);
|
|
mainComponentData.config();
|
|
// mainComponentData is now the main component and won't disappear until KGlobal deletes it
|
|
}
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::usageError(const QString &error)
|
|
{
|
|
Q_ASSERT(KGlobal::hasLocale());
|
|
QByteArray localError = s->encodeOutput(error);
|
|
if (localError.endsWith('\n'))
|
|
localError.chop(1);
|
|
fprintf(stderr, "%s: %s\n", s->appName, localError.data());
|
|
|
|
QString tmp = i18n("Use --help to get a list of available command line options.");
|
|
localError = s->encodeOutput(tmp);
|
|
fprintf(stderr, "%s: %s\n", s->appName, localError.data());
|
|
exit(254);
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::usage(const QByteArray &id)
|
|
{
|
|
enable_i18n();
|
|
Q_ASSERT(s->argsList != 0); // It's an error to call usage(...) without
|
|
// having done addCmdLineOptions first!
|
|
|
|
QString optionFormatString = QString::fromLatin1(" %1 %2\n");
|
|
QString optionFormatStringDef = QString::fromLatin1(" %1 %2 [%3]\n");
|
|
QString tmp;
|
|
QString usage;
|
|
|
|
KCmdLineArgsList::Iterator args = --(s->argsList->end());
|
|
|
|
if ((*args)->d->id.isEmpty() && ((*args)->d->options.d->names.size() > 0) &&
|
|
!(*args)->d->options.d->names[0].startsWith('+'))
|
|
{
|
|
usage = i18n("[options] ")+usage;
|
|
}
|
|
|
|
while(true)
|
|
{
|
|
if (!(*args)->d->name.isEmpty())
|
|
{
|
|
usage = i18n("[%1-options]", (*args)->d->name.toString())+QLatin1Char(' ')+usage;
|
|
}
|
|
if (args == s->argsList->begin())
|
|
break;
|
|
--args;
|
|
}
|
|
|
|
KCmdLineArgs *appOptions = s->argsList->last();
|
|
if (appOptions->d->id.isEmpty())
|
|
{
|
|
const KCmdLineOptions &option = appOptions->d->options;
|
|
for (int i = 0; i < option.d->names.size(); i++)
|
|
{
|
|
QByteArray opt_name = option.d->names[i];
|
|
if (opt_name.startsWith('+'))
|
|
usage += QString::fromLatin1(opt_name.mid(1)) + QLatin1Char(' ');
|
|
else if ( opt_name.startsWith("!+") )
|
|
usage += QString::fromLatin1(opt_name.mid(2)) + QLatin1Char(' ');
|
|
}
|
|
}
|
|
|
|
s->printQ(i18n("Usage: %1 %2\n", QString::fromLocal8Bit(s->appName), Qt::escape(usage)));
|
|
s->printQ(QLatin1Char('\n')+s->about->shortDescription()+QLatin1Char('\n'));
|
|
|
|
s->printQ(i18n("\nGeneric options:\n"));
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("--help"), -25)
|
|
.arg(i18n("Show help about options")));
|
|
|
|
args = s->argsList->begin();
|
|
while(args != s->argsList->end())
|
|
{
|
|
if (!(*args)->d->name.isEmpty() && !(*args)->d->id.isEmpty())
|
|
{
|
|
QString option = QString::fromLatin1("--help-%1").arg(QString::fromLatin1((*args)->d->id));
|
|
QString desc = i18n("Show %1 specific options", (*args)->d->name.toString());
|
|
|
|
s->printQ(optionFormatString.arg(option, -25).arg(desc));
|
|
}
|
|
++args;
|
|
}
|
|
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("--help-all"),-25).arg(i18n("Show all options")));
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("--author"),-25).arg(i18n("Show author information")));
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("-v, --version"),-25).arg(i18n("Show version information")));
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("--license"),-25).arg(i18n("Show license information")));
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1("--"), -25).arg(i18n("End of options")));
|
|
|
|
args = s->argsList->begin(); // Sets current to 1st.
|
|
|
|
bool showAll = (id == "all");
|
|
|
|
if (!showAll)
|
|
{
|
|
while(args != s->argsList->end())
|
|
{
|
|
if (id == (*args)->d->id) break;
|
|
++args;
|
|
}
|
|
}
|
|
|
|
while(args != s->argsList->end())
|
|
{
|
|
bool hasArgs = false;
|
|
bool hasOptions = false;
|
|
QString optionsHeader;
|
|
if (!(*args)->d->name.isEmpty())
|
|
optionsHeader = i18n("\n%1 options:\n", (*args)->d->name.toString());
|
|
else
|
|
optionsHeader = i18n("\nOptions:\n");
|
|
|
|
while (args != s->argsList->end())
|
|
{
|
|
const KCmdLineOptions &option = (*args)->d->options;
|
|
QByteArray opt;
|
|
|
|
for (int i = 0; i < option.d->names.size(); i++)
|
|
{
|
|
QString description;
|
|
QStringList dl;
|
|
|
|
QString descriptionFull;
|
|
if (!option.d->descriptions[i].isEmpty()) {
|
|
descriptionFull = option.d->descriptions[i].toString();
|
|
}
|
|
|
|
// Option header
|
|
if (option.d->names[i].startsWith(':'))
|
|
{
|
|
if (!descriptionFull.isEmpty())
|
|
{
|
|
optionsHeader = QLatin1Char('\n')+descriptionFull;
|
|
if (!optionsHeader.endsWith(QLatin1Char('\n')))
|
|
optionsHeader.append(QLatin1Char('\n'));
|
|
hasOptions = false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Free-form comment
|
|
if (option.d->names[i].isEmpty())
|
|
{
|
|
if (!descriptionFull.isEmpty())
|
|
{
|
|
tmp = QLatin1Char('\n')+descriptionFull;
|
|
if (!tmp.endsWith(QLatin1Char('\n')))
|
|
tmp.append(QLatin1Char('\n'));
|
|
s->printQ(tmp);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Options
|
|
if (!descriptionFull.isEmpty())
|
|
{
|
|
dl = descriptionFull.split(QLatin1Char('\n'), QString::KeepEmptyParts);
|
|
description = dl.first();
|
|
dl.erase( dl.begin() );
|
|
}
|
|
QByteArray name = option.d->names[i];
|
|
if (name.startsWith('!'))
|
|
name = name.mid(1);
|
|
|
|
if (name.startsWith('+'))
|
|
{
|
|
if (!hasArgs)
|
|
{
|
|
s->printQ(i18n("\nArguments:\n"));
|
|
hasArgs = true;
|
|
}
|
|
|
|
name = name.mid(1);
|
|
if (name.startsWith('[') && name.endsWith(']'))
|
|
name = name.mid(1, name.length()-2);
|
|
s->printQ(optionFormatString.arg(QString::fromLocal8Bit(name), -25).arg(description));
|
|
}
|
|
else
|
|
{
|
|
if (!hasOptions)
|
|
{
|
|
s->printQ(optionsHeader);
|
|
hasOptions = true;
|
|
}
|
|
|
|
if ((name.length() == 1) || (name[1] == ' '))
|
|
name = '-'+name;
|
|
else
|
|
name = "--"+name;
|
|
if (descriptionFull.isEmpty())
|
|
{
|
|
opt = name + ", ";
|
|
}
|
|
else
|
|
{
|
|
opt = opt + name;
|
|
if (option.d->defaults[i].isEmpty())
|
|
{
|
|
s->printQ(optionFormatString.arg(QString::fromLatin1(opt), -25).arg(description));
|
|
}
|
|
else
|
|
{
|
|
s->printQ(optionFormatStringDef.arg(QString::fromLatin1(opt), -25)
|
|
.arg(description).arg(option.d->defaults[i]));
|
|
}
|
|
opt.clear();
|
|
}
|
|
}
|
|
for(QStringList::Iterator it = dl.begin();
|
|
it != dl.end();
|
|
++it)
|
|
{
|
|
s->printQ(optionFormatString.arg(QString(), -25).arg(*it));
|
|
}
|
|
}
|
|
|
|
++args;
|
|
if (args == s->argsList->end() || !(*args)->d->name.isEmpty() || (*args)->d->id.isEmpty())
|
|
break;
|
|
}
|
|
if (!showAll) break;
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
//
|
|
// Member functions
|
|
//
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* The given arguments are assumed to be constants.
|
|
*/
|
|
KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions &_options,
|
|
const KLocalizedString &_name,
|
|
const QByteArray &_id)
|
|
: d(new KCmdLineArgsPrivate(_options, _name, _id))
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
KCmdLineArgs::~KCmdLineArgs()
|
|
{
|
|
if (!s.isDestroyed() && s->argsList)
|
|
s->argsList->removeAll(this);
|
|
delete d;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::setCwd( const QByteArray &cwd )
|
|
{
|
|
s->mCwd = cwd;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::clear()
|
|
{
|
|
delete d->parsedArgList; d->parsedArgList = 0;
|
|
delete d->parsedOptionList; d->parsedOptionList = 0;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::reset()
|
|
{
|
|
delete s->argsList; s->argsList = 0;
|
|
s->parsed = false;
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsPrivate::save( QDataStream &ds) const
|
|
{
|
|
if (parsedOptionList)
|
|
ds << (*(parsedOptionList));
|
|
else
|
|
ds << quint32(0);
|
|
|
|
if (parsedArgList)
|
|
ds << (*(parsedArgList));
|
|
else
|
|
ds << quint32(0);
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsPrivate::load( QDataStream &ds)
|
|
{
|
|
if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
|
|
if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
|
|
|
|
ds >> (*(parsedOptionList));
|
|
ds >> (*(parsedArgList));
|
|
|
|
if (parsedOptionList->count() == 0)
|
|
{
|
|
delete parsedOptionList; parsedOptionList = 0;
|
|
}
|
|
if (parsedArgList->count() == 0)
|
|
{
|
|
delete parsedArgList; parsedArgList = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsPrivate::setOption(const QByteArray &opt, bool enabled)
|
|
{
|
|
if (isQt)
|
|
{
|
|
// Qt does it own parsing.
|
|
QByteArray argString = "-"; // krazy:exclude=doublequote_chars
|
|
if( !enabled )
|
|
argString += "no";
|
|
argString += opt;
|
|
addArgument(argString);
|
|
}
|
|
if (!parsedOptionList) {
|
|
parsedOptionList = new KCmdLineParsedOptions;
|
|
}
|
|
|
|
if (enabled)
|
|
parsedOptionList->insert( opt, "t" ); // krazy:exclude=doublequote_chars
|
|
else
|
|
parsedOptionList->insert( opt, "f" ); // krazy:exclude=doublequote_chars
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsPrivate::setOption(const QByteArray &opt, const QByteArray &value)
|
|
{
|
|
if (isQt)
|
|
{
|
|
// Katie does it's own parsing.
|
|
QByteArray argString = "-"; // krazy:exclude=doublequote_chars
|
|
argString += opt;
|
|
addArgument(argString);
|
|
addArgument(value);
|
|
|
|
#if defined(Q_WS_X11)
|
|
// Hack coming up!
|
|
if (argString == "-display")
|
|
{
|
|
setenv(DISPLAY, value.data(), true);
|
|
}
|
|
#endif
|
|
}
|
|
if (!parsedOptionList) {
|
|
parsedOptionList = new KCmdLineParsedOptions;
|
|
}
|
|
|
|
parsedOptionList->insertMulti( opt, value );
|
|
}
|
|
|
|
QString
|
|
KCmdLineArgs::getOption(const QByteArray &_opt) const
|
|
{
|
|
QByteArray opt = _opt;
|
|
QByteArray value;
|
|
if (d->parsedOptionList)
|
|
{
|
|
value = d->parsedOptionList->value(opt);
|
|
}
|
|
if (!value.isEmpty())
|
|
return QString::fromLocal8Bit(value);
|
|
|
|
// Look up the default.
|
|
QByteArray opt_name;
|
|
QString def;
|
|
bool dummy = true;
|
|
int result = s->findOption( d->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.data(), opt.data());
|
|
fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
|
|
|
|
Q_ASSERT( 0 );
|
|
exit(255);
|
|
}
|
|
return def;
|
|
}
|
|
|
|
QStringList
|
|
KCmdLineArgs::getOptionList(const QByteArray &opt) const
|
|
{
|
|
QStringList result;
|
|
if (!d->parsedOptionList)
|
|
return result;
|
|
|
|
while(true)
|
|
{
|
|
QByteArray value = d->parsedOptionList->take(opt);
|
|
if (value.isEmpty())
|
|
break;
|
|
result.prepend(QString::fromLocal8Bit(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.
|
|
Q_FOREACH(const QString &str, result)
|
|
{
|
|
d->parsedOptionList->insertMulti(opt, str.toLocal8Bit());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
KCmdLineArgs::isSet(const QByteArray &_opt) const
|
|
{
|
|
// Look up the default.
|
|
QByteArray opt = _opt;
|
|
QByteArray opt_name;
|
|
QString def;
|
|
int result = 0;
|
|
KCmdLineArgsList::Iterator args = s->argsList->begin();
|
|
while (args != s->argsList->end())
|
|
{
|
|
bool dummy = true;
|
|
result = s->findOption((*args)->d->options, opt, opt_name, def, dummy) & ~4;
|
|
if (result) break;
|
|
++args;
|
|
}
|
|
|
|
if (result == 0)
|
|
{
|
|
fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
|
|
fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
|
|
opt.data(), opt.data());
|
|
fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
|
|
|
|
Q_ASSERT( 0 );
|
|
exit(255);
|
|
}
|
|
|
|
QByteArray value;
|
|
if (d->parsedOptionList)
|
|
{
|
|
value = d->parsedOptionList->value(opt);
|
|
}
|
|
|
|
if (!value.isEmpty())
|
|
{
|
|
if (result == 3)
|
|
return true;
|
|
else
|
|
return (value.at(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
|
|
{
|
|
return d->parsedArgList?d->parsedArgList->count():0;
|
|
}
|
|
|
|
QString
|
|
KCmdLineArgs::arg(int n) const
|
|
{
|
|
if (!d->parsedArgList || (n >= (int) d->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);
|
|
|
|
Q_ASSERT( 0 );
|
|
exit(255);
|
|
}
|
|
|
|
return QString::fromLocal8Bit(d->parsedArgList->at(n));
|
|
}
|
|
|
|
KUrl
|
|
KCmdLineArgs::url(int n) const
|
|
{
|
|
return makeURL( arg(n).toUtf8() );
|
|
}
|
|
|
|
KUrl KCmdLineArgs::makeURL(const QByteArray &_urlArg)
|
|
{
|
|
const QString urlArg = QString::fromUtf8(_urlArg);
|
|
QFileInfo fileInfo(urlArg);
|
|
if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix
|
|
KUrl result;
|
|
result.setPath(QDir::fromNativeSeparators(urlArg));
|
|
return result; // Absolute path.
|
|
}
|
|
|
|
if ( KUrl::isRelativeUrl(urlArg) || fileInfo.exists() ) {
|
|
KUrl result;
|
|
result.setPath(cwd()+QLatin1Char('/')+urlArg);
|
|
result.cleanPath();
|
|
return result; // Relative path
|
|
}
|
|
|
|
return KUrl(urlArg); // Argument is a URL
|
|
}
|
|
|
|
void
|
|
KCmdLineArgsPrivate::addArgument(const QByteArray &argument)
|
|
{
|
|
if (!parsedArgList)
|
|
parsedArgList = new KCmdLineParsedArgs;
|
|
|
|
parsedArgList->append(argument);
|
|
}
|
|
|
|
void
|
|
KCmdLineArgs::addTempFileOption()
|
|
{
|
|
KCmdLineOptions tmpopt;
|
|
tmpopt.add( "tempfile", ki18n("The files/URLs opened by the application will be deleted after use") );
|
|
KCmdLineArgs::addCmdLineOptions( tmpopt, ki18n("KDE-tempfile"), "kde-tempfile" );
|
|
}
|
|
|
|
bool KCmdLineArgs::isTempFileSet()
|
|
{
|
|
KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
|
|
return args && args->isSet( "tempfile" );
|
|
}
|
|
|
|
QStringList KCmdLineArgs::allArguments()
|
|
{
|
|
QStringList lst;
|
|
|
|
for(int i = 0; i < s->all_argc; i++) {
|
|
char* arg = s->all_argv[i];
|
|
if (!arg)
|
|
continue;
|
|
lst.append(QString::fromLocal8Bit(arg));
|
|
}
|
|
return lst;
|
|
}
|