00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "kcmdlineargs.h"
00020
00021 #include <config.h>
00022
00023 #include <sys/param.h>
00024
00025 #include <assert.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <locale.h>
00031
00032 #ifdef HAVE_LIMITS_H
00033 #include <limits.h>
00034 #endif
00035
00036 #include <QtCore/QDir>
00037 #include <QtCore/QFile>
00038 #include <QtCore/QHash>
00039 #include <QtCore/QTextCodec>
00040
00041 #include "kaboutdata.h"
00042 #include "klocale.h"
00043 #include "kdeversion.h"
00044 #include "kcomponentdata.h"
00045 #include "kglobal.h"
00046 #include "kstringhandler.h"
00047 #include "kurl.h"
00048
00049 #include "kuitsemantics_p.h"
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 #ifdef Q_WS_X11
00075 #define DISPLAY "DISPLAY"
00076 #elif defined(Q_WS_QWS)
00077 #define DISPLAY "QWS_DISPLAY"
00078 #else
00079 #define DISPLAY "NODISPLAY"
00080 #endif
00081
00082
00083
00084
00085
00086 class KCmdLineParsedOptions : public QHash<QString,QString>
00087 {
00088 public:
00089 KCmdLineParsedOptions() { }
00090 };
00091
00092 class KCmdLineParsedArgs : public QList<QString>
00093 {
00094 public:
00095 KCmdLineParsedArgs() { }
00096 };
00097
00098
00099 class KCmdLineArgsList: public QList<KCmdLineArgs*>
00100 {
00101 public:
00102 KCmdLineArgsList() { }
00103 ~KCmdLineArgsList() {
00104 while (count())
00105 delete takeFirst();
00106 }
00107 };
00108
00109
00110
00111
00112
00113 class KCmdLineOptionsPrivate {
00114 public:
00115 QStringList names;
00116 QList<KLocalizedString> descriptions;
00117 QStringList defaults;
00118 };
00119
00120 KCmdLineOptions::KCmdLineOptions ()
00121 : d(new KCmdLineOptionsPrivate)
00122 {}
00123
00124 KCmdLineOptions::~KCmdLineOptions ()
00125 {
00126 delete d;
00127 }
00128
00129 KCmdLineOptions::KCmdLineOptions (const KCmdLineOptions &options)
00130 : d(new KCmdLineOptionsPrivate(*(options.d)))
00131 {
00132 }
00133
00134 KCmdLineOptions& KCmdLineOptions::operator= (const KCmdLineOptions &options)
00135 {
00136 if (this != &options) {
00137 *d = *(options.d);
00138 }
00139 return *this;
00140 }
00141
00142 KCmdLineOptions &KCmdLineOptions::add (const QByteArray &name,
00143 const KLocalizedString &description,
00144 const QByteArray &defaultValue)
00145 {
00146 d->names.append(QString::fromUtf8(name));
00147 d->descriptions.append(description);
00148 d->defaults.append(QString::fromUtf8(defaultValue));
00149 return *this;
00150 }
00151
00152 KCmdLineOptions &KCmdLineOptions::add (const KCmdLineOptions &other)
00153 {
00154 d->names += other.d->names;
00155 d->descriptions += other.d->descriptions;
00156 d->defaults += other.d->defaults;
00157 return *this;
00158 }
00159
00160
00161
00162
00163
00164 class KCmdLineArgsStatic {
00165 public:
00166
00167 KCmdLineArgsList *argsList;
00168 const KAboutData *about;
00169
00170 int argc;
00171 char **argv;
00172 bool parsed : 1;
00173 bool ignoreUnknown : 1;
00174 QString mCwd;
00175 KCmdLineArgs::StdCmdLineArgs mStdargs;
00176
00177 KCmdLineOptions qt_options;
00178 KCmdLineOptions kde_options;
00179
00180 KCmdLineArgsStatic ();
00181
00182 ~KCmdLineArgsStatic ();
00183
00184 QTextCodec *codec;
00185
00193 static QString decodeInput(const QByteArray &rawstr);
00194
00202 static QByteArray encodeOutput(const QString &str);
00203
00208 void printQ(const QString &msg);
00209
00223 static int findOption(const KCmdLineOptions &options, QString &opt,
00224 QString &opt_name, QString &def, bool &enabled);
00225
00231 static void findOption(const QString &optv, const QString &_opt,
00232 int &i, bool _enabled, bool &moreOptions);
00233
00240 static void parseAllArgs();
00241
00249 static void removeArgs(const QString &id);
00250 };
00251
00252 K_GLOBAL_STATIC(KCmdLineArgsStatic, s)
00253
00254 KCmdLineArgsStatic::KCmdLineArgsStatic () {
00255
00256 argsList = 0;
00257 argc = 0;
00258 argv = 0;
00259 mCwd.clear();
00260 about = 0;
00261 parsed = false;
00262 ignoreUnknown = false;
00263 mStdargs = 0;
00264
00265
00266 codec = QTextCodec::codecForLocale();
00267 setlocale(LC_ALL, "");
00268
00269
00270
00271 #ifdef Q_WS_X11
00272 qt_options.add("display <displayname>", ki18n("Use the X-server display 'displayname'"));
00273 #elif defined(Q_WS_QWS)
00274 qt_options.add("display <displayname>", ki18n("Use the QWS display 'displayname'"));
00275 #else
00276 #endif
00277 qt_options.add("session <sessionId>", ki18n("Restore the application for the given 'sessionId'"));
00278 qt_options.add("cmap", ki18n("Causes the application to install a private color\nmap on an 8-bit display"));
00279 qt_options.add("ncols <count>", ki18n("Limits the number of colors allocated in the color\ncube on an 8-bit display, if the application is\nusing the QApplication::ManyColor color\nspecification"));
00280 qt_options.add("nograb", ki18n("tells Qt to never grab the mouse or the keyboard"));
00281 qt_options.add("dograb", ki18n("running under a debugger can cause an implicit\n-nograb, use -dograb to override"));
00282 qt_options.add("sync", ki18n("switches to synchronous mode for debugging"));
00283 qt_options.add("fn");
00284 qt_options.add("font <fontname>", ki18n("defines the application font"));
00285 qt_options.add("bg");
00286 qt_options.add("background <color>", ki18n("sets the default background color and an\napplication palette (light and dark shades are\ncalculated)"));
00287 qt_options.add("fg");
00288 qt_options.add("foreground <color>", ki18n("sets the default foreground color"));
00289 qt_options.add("btn");
00290 qt_options.add("button <color>", ki18n("sets the default button color"));
00291 qt_options.add("name <name>", ki18n("sets the application name"));
00292 qt_options.add("title <title>", ki18n("sets the application title (caption)"));
00293 #ifdef Q_WS_X11
00294 qt_options.add("visual TrueColor", ki18n("forces the application to use a TrueColor visual on\nan 8-bit display"));
00295 qt_options.add("inputstyle <inputstyle>", ki18n("sets XIM (X Input Method) input style. Possible\nvalues are onthespot, overthespot, offthespot and\nroot"));
00296 qt_options.add("im <XIM server>", ki18n("set XIM server"));
00297 qt_options.add("noxim", ki18n("disable XIM"));
00298 #endif
00299 #ifdef Q_WS_QWS
00300 qt_options.add("qws", ki18n("forces the application to run as QWS Server"));
00301 #endif
00302 qt_options.add("reverse", ki18n("mirrors the whole layout of widgets"));
00303 qt_options.add("stylesheet <file.qss>", ki18n("applies the Qt stylesheet to the application widgets"));
00304 #if QT_VERSION >= 0x040a00
00305 # error Qt version larger than 4.9, please fix me
00306 #endif
00307 if (qVersion()[2] >= '5')
00308 qt_options.add("graphicssystem <system>", ki18n("use a different graphics system instead of the default one, options are raster and opengl (experimental)"));
00309
00310 kde_options.add("caption <caption>", ki18n("Use 'caption' as name in the titlebar"));
00311 kde_options.add("icon <icon>", ki18n("Use 'icon' as the application icon"));
00312 kde_options.add("config <filename>", ki18n("Use alternative configuration file"));
00313 kde_options.add("nocrashhandler", ki18n("Disable crash handler, to get core dumps"));
00314 #ifdef Q_WS_X11
00315 kde_options.add("waitforwm", ki18n("Waits for a WM_NET compatible windowmanager"));
00316 #endif
00317 kde_options.add("style <style>", ki18n("sets the application GUI style"));
00318 kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format"));
00319 #ifndef Q_WS_WIN
00320 kde_options.add("smkey <sessionKey>");
00321 #endif
00322 }
00323
00324 KCmdLineArgsStatic::~KCmdLineArgsStatic ()
00325 {
00326 delete argsList;
00327
00328
00329 }
00330
00331
00332
00333
00334
00335 class KCmdLineArgsPrivate
00336 {
00337 friend class KCmdLineArgsStatic;
00338 public:
00339 KCmdLineArgsPrivate(const KCmdLineOptions &_options, const KLocalizedString &_name, const QString &_id)
00340 : options(_options)
00341 , name(_name)
00342 , id(_id)
00343 , parsedOptionList(0)
00344 , parsedArgList(0)
00345 , isQt(id == "qt")
00346 {}
00347 ~KCmdLineArgsPrivate()
00348 {
00349 delete parsedOptionList;
00350 delete parsedArgList;
00351 }
00352 const KCmdLineOptions options;
00353 const KLocalizedString name;
00354 const QString id;
00355 KCmdLineParsedOptions *parsedOptionList;
00356 KCmdLineParsedArgs *parsedArgList;
00357 bool isQt;
00358
00364 void setOption(const QString &option, bool enabled);
00365
00371 void setOption(const QString &option, const QString &value);
00372
00378 void addArgument(const QString &argument);
00379
00385 void save( QDataStream &) const;
00386
00392 void load( QDataStream &);
00393 };
00394
00395
00396
00397
00398
00399 QString
00400 KCmdLineArgsStatic::decodeInput(const QByteArray &rawstr)
00401 {
00402 return s->codec->toUnicode(rawstr);
00403 }
00404
00405 QByteArray
00406 KCmdLineArgsStatic::encodeOutput(const QString &str)
00407 {
00408 return s->codec->fromUnicode(str);
00409 }
00410
00411 void
00412 KCmdLineArgsStatic::printQ(const QString &msg)
00413 {
00414 fprintf(stdout, "%s", encodeOutput(msg).data());
00415 }
00416
00417 void
00418 KCmdLineArgs::init(int _argc, char **_argv,
00419 const QByteArray &_appname,
00420 const QByteArray &_catalog,
00421 const KLocalizedString &_programName,
00422 const QByteArray &_version,
00423 const KLocalizedString &_description,
00424 StdCmdLineArgs stdargs)
00425 {
00426 init(_argc, _argv,
00427 new KAboutData(_appname, _catalog, _programName, _version, _description),
00428 stdargs);
00429 }
00430
00431 void
00432 KCmdLineArgs::initIgnore(int _argc, char **_argv, const QByteArray &_appname )
00433 {
00434 init(_argc, _argv,
00435 new KAboutData(_appname, 0, ki18n(_appname), "unknown", ki18n("KDE Application")));
00436 s->ignoreUnknown = true;
00437 }
00438
00439 void
00440 KCmdLineArgs::init(const KAboutData* ab)
00441 {
00442 char **_argv = (char **) malloc(sizeof(char *));
00443 _argv[0] = (char *) s->encodeOutput(ab->appName()).data();
00444 init(1,_argv,ab, CmdLineArgNone);
00445 }
00446
00447
00448 void
00449 KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, StdCmdLineArgs stdargs)
00450 {
00451 s->argc = _argc;
00452 s->argv = _argv;
00453
00454 if (!s->argv)
00455 {
00456 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00457 fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
00458
00459 assert( 0 );
00460 exit(255);
00461 }
00462
00463
00464 if (s->argc) {
00465 char *p = strrchr( s->argv[0], '/');
00466 if (p)
00467 s->argv[0] = p+1;
00468 }
00469
00470 s->about = _about;
00471 s->parsed = false;
00472 s->mCwd = QDir::currentPath();
00473 addStdCmdLineOptions(stdargs);
00474 }
00475
00476 QString KCmdLineArgs::cwd()
00477 {
00478 return s->mCwd;
00479 }
00480
00481 QString KCmdLineArgs::appName()
00482 {
00483 if (!s->argc) return QString();
00484 return s->decodeInput(s->argv[0]);
00485 }
00486
00490 void KCmdLineArgs::addStdCmdLineOptions(StdCmdLineArgs stdargs) {
00491 if (stdargs & KCmdLineArgs::CmdLineArgQt) {
00492 KCmdLineArgs::addCmdLineOptions(s->qt_options, ki18n("Qt"), "qt");
00493 }
00494 if (stdargs & KCmdLineArgs::CmdLineArgKDE) {
00495 KCmdLineArgs::addCmdLineOptions(s->kde_options, ki18n("KDE"), "kde");
00496 }
00497 s->mStdargs = stdargs;
00498 }
00499
00500 void
00501 KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions &options, const KLocalizedString &name,
00502 const QByteArray &_id, const QByteArray &_afterId)
00503 {
00504 if (!s->argsList)
00505 s->argsList = new KCmdLineArgsList;
00506
00507 QString id = QString::fromUtf8(_id);
00508 QString afterId = QString::fromUtf8(_afterId);
00509
00510 int pos = s->argsList->count();
00511
00512 if (pos > 0 && !id.isEmpty() && s->argsList->last()->d->name.isEmpty())
00513 pos--;
00514
00515 KCmdLineArgsList::Iterator args;
00516 int i = 0;
00517 for(args = s->argsList->begin(); args != s->argsList->end(); ++args, i++)
00518 {
00519 if (id == (*args)->d->id)
00520 return;
00521
00522
00523
00524 if (!afterId.isEmpty() && afterId == (*args)->d->id)
00525 pos = i+1;
00526 }
00527
00528 Q_ASSERT( s->parsed == false );
00529
00530 s->argsList->insert(pos, new KCmdLineArgs(options, name, id.toUtf8()));
00531 }
00532
00533 void
00534 KCmdLineArgs::saveAppArgs( QDataStream &ds)
00535 {
00536 if (!s->parsed)
00537 s->parseAllArgs();
00538
00539
00540 s->removeArgs("qt");
00541 s->removeArgs("kde");
00542
00543 QByteArray qCwd = QFile::encodeName(s->mCwd);
00544 ds << qCwd;
00545
00546 uint count = s->argsList ? s->argsList->count() : 0;
00547 ds << count;
00548
00549 if (!count) return;
00550
00551 KCmdLineArgsList::Iterator args;
00552 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00553 {
00554 ds << (*args)->d->id;
00555 (*args)->d->save(ds);
00556 }
00557 }
00558
00559 void
00560 KCmdLineArgs::loadAppArgs( QDataStream &ds)
00561 {
00562 s->parsed = true;
00563
00564
00565 s->removeArgs("qt");
00566 s->removeArgs("kde");
00567
00568 KCmdLineArgsList::Iterator args;
00569 if ( s->argsList ) {
00570 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00571 {
00572 (*args)->clear();
00573 }
00574 }
00575
00576 if (ds.atEnd())
00577 return;
00578
00579 QByteArray qCwd;
00580 ds >> qCwd;
00581
00582 s->mCwd = QFile::decodeName(qCwd);
00583
00584 uint count;
00585 ds >> count;
00586
00587 while(count--)
00588 {
00589 QByteArray idRaw;
00590 ds >> idRaw;
00591 QString id = idRaw;
00592 Q_ASSERT( s->argsList );
00593 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00594 {
00595 if ((*args)->d->id == id)
00596 {
00597 (*args)->d->load(ds);
00598 break;
00599 }
00600 }
00601 }
00602 s->parsed = true;
00603 }
00604
00605 KCmdLineArgs *KCmdLineArgs::parsedArgs(const QByteArray &_id)
00606 {
00607 QString id = QString::fromUtf8(_id);
00608 if (!s->argsList)
00609 return 0;
00610 KCmdLineArgsList::Iterator args = s->argsList->begin();
00611 while(args != s->argsList->end())
00612 {
00613 if ((*args)->d->id == id)
00614 {
00615 if (!s->parsed)
00616 s->parseAllArgs();
00617 return *args;
00618 }
00619 ++args;
00620 }
00621
00622 return 0;
00623 }
00624
00625 void KCmdLineArgsStatic::removeArgs(const QString &id)
00626 {
00627 if (!s->argsList)
00628 return;
00629 KCmdLineArgsList::Iterator args = s->argsList->begin();
00630 while(args != s->argsList->end())
00631 {
00632 if ((*args)->d->id == id)
00633 {
00634 if (!s->parsed)
00635 s->parseAllArgs();
00636 break;
00637 }
00638 ++args;
00639 }
00640
00641 if (args != s->argsList->end()) {
00642 KCmdLineArgs *a = *args;
00643 s->argsList->erase(args);
00644 delete a;
00645 }
00646 }
00647
00648 int
00649 KCmdLineArgsStatic::findOption(const KCmdLineOptions &options, QString &opt,
00650 QString &opt_name, QString &def, bool &enabled)
00651 {
00652 int result;
00653 bool inverse;
00654
00655 for (int i = 0; i < options.d->names.size(); i++)
00656 {
00657 result = 0;
00658 inverse = false;
00659 opt_name = options.d->names[i].toUtf8();
00660 if (opt_name.startsWith(':') || opt_name.isEmpty())
00661 {
00662 continue;
00663 }
00664 if (opt_name.startsWith('!'))
00665 {
00666 opt_name = opt_name.mid(1);
00667 result = 4;
00668 }
00669 if (opt_name.startsWith("no"))
00670 {
00671 opt_name = opt_name.mid(2);
00672 inverse = true;
00673 }
00674
00675 int len = opt.length();
00676 if (opt == opt_name.left(len))
00677 {
00678 opt_name = opt_name.mid(len);
00679 if (opt_name.isEmpty())
00680 {
00681 if (inverse)
00682 return result+2;
00683
00684 if (options.d->descriptions[i].isEmpty())
00685 {
00686 i++;
00687 if (i >= options.d->names.size())
00688 return result+0;
00689 QString nextOption = options.d->names[i].toUtf8();
00690 int p = nextOption.indexOf(' ');
00691 if (p > 0)
00692 nextOption = nextOption.left(p);
00693 if (nextOption.startsWith('!'))
00694 nextOption = nextOption.mid(1);
00695 if (nextOption.startsWith("no"))
00696 {
00697 nextOption = nextOption.mid(2);
00698 enabled = !enabled;
00699 }
00700 result = findOption(options, nextOption, opt_name, def, enabled);
00701 Q_ASSERT(result);
00702 opt = nextOption;
00703 return result;
00704 }
00705
00706 return 1;
00707 }
00708 if (opt_name.startsWith(' '))
00709 {
00710 opt_name = opt_name.mid(1);
00711 def = options.d->defaults[i].toUtf8();
00712 return result+3;
00713 }
00714 }
00715 }
00716 return 0;
00717 }
00718
00719 void
00720 KCmdLineArgsStatic::findOption(const QString &optv, const QString &_opt,
00721 int &i, bool _enabled, bool &moreOptions)
00722 {
00723 KCmdLineArgsList::Iterator args = s->argsList->begin();
00724 QString opt = _opt;
00725 QString opt_name;
00726 QString def;
00727 QString argument;
00728 int j = opt.indexOf('=');
00729 if (j != -1)
00730 {
00731 argument = opt.mid(j+1);
00732 opt = opt.left(j);
00733 }
00734 #ifdef Q_WS_MACX
00735 if(opt.startsWith("psn_"))
00736 opt = "psn";
00737 #endif
00738
00739 bool enabled = true;
00740 int result = 0;
00741 while (args != s->argsList->end())
00742 {
00743 enabled = _enabled;
00744 result = findOption((*args)->d->options, opt, opt_name, def, enabled);
00745 if (result) break;
00746 ++args;
00747 }
00748 if ((args == s->argsList->end()) &&
00749 (optv.startsWith('-') && !optv.startsWith("--")))
00750 {
00751
00752
00753 int p = 1;
00754 while (true)
00755 {
00756 QString singleCharOption = " ";
00757 singleCharOption[0] = optv[p];
00758 args = s->argsList->begin();
00759 while (args != s->argsList->end())
00760 {
00761 enabled = _enabled;
00762 result = findOption((*args)->d->options, singleCharOption,
00763 opt_name, def, enabled);
00764 if (result) break;
00765 ++args;
00766 }
00767 if (args == s->argsList->end())
00768 break;
00769
00770 p++;
00771 if (result == 1)
00772 {
00773 (*args)->d->setOption(singleCharOption, enabled);
00774 if (p < optv.length())
00775 continue;
00776 else
00777 return;
00778 }
00779 else if (result == 3)
00780 {
00781 if (argument.isEmpty())
00782 {
00783 argument = optv.mid(p);
00784 }
00785 (*args)->d->setOption(singleCharOption, argument);
00786 return;
00787 }
00788 break;
00789 }
00790 args = s->argsList->end();
00791 result = 0;
00792 }
00793
00794 if (args == s->argsList->end() || !result)
00795 {
00796 if (s->ignoreUnknown)
00797 return;
00798 #ifdef Q_WS_MACX
00799 if (_opt.startsWith("psn_", Qt::CaseInsensitive))
00800 return;
00801 #endif
00802 KCmdLineArgs::enable_i18n();
00803 KCmdLineArgs::usageError( i18n("Unknown option '%1'.", _opt));
00804 }
00805
00806 if ((result & 4) != 0)
00807 {
00808 result &= ~4;
00809 moreOptions = false;
00810 }
00811
00812 if (result == 3)
00813 {
00814 if (!enabled)
00815 {
00816 if (s->ignoreUnknown)
00817 return;
00818 #ifdef Q_WS_MACX
00819 if (_opt.startsWith("psn_", Qt::CaseInsensitive))
00820 return;
00821 #endif
00822 KCmdLineArgs::enable_i18n();
00823 KCmdLineArgs::usageError( i18n("Unknown option '%1'.", _opt));
00824 }
00825 if (argument.isEmpty())
00826 {
00827 i++;
00828 if (i >= s->argc)
00829 {
00830 KCmdLineArgs::enable_i18n();
00831 KCmdLineArgs::usageError( i18nc("@info:shell %1 is cmdoption name","'%1' missing.", opt_name));
00832 }
00833 argument = s->decodeInput(s->argv[i]);
00834 }
00835 (*args)->d->setOption(opt, argument);
00836 }
00837 else
00838 {
00839 (*args)->d->setOption(opt, enabled);
00840 }
00841 }
00842
00843 void
00844 KCmdLineArgsStatic::parseAllArgs()
00845 {
00846 bool allowArgs = false;
00847 bool inOptions = true;
00848 bool everythingAfterArgIsArgs = false;
00849 KCmdLineArgs *appOptions = s->argsList->last();
00850 if (appOptions->d->id.isEmpty())
00851 {
00852 const KCmdLineOptions &option = appOptions->d->options;
00853 for (int i = 0; i < option.d->names.size(); i++)
00854 {
00855 if (option.d->names[i].startsWith('+'))
00856 allowArgs = true;
00857 if ( option.d->names[i].startsWith("!+") )
00858 {
00859 allowArgs = true;
00860 everythingAfterArgIsArgs = true;
00861 }
00862 }
00863 }
00864 for(int i = 1; i < s->argc; i++)
00865 {
00866 if (!s->argv[i])
00867 continue;
00868
00869 if ((s->argv[i][0] == '-') && s->argv[i][1] && inOptions)
00870 {
00871 bool enabled = true;
00872 QString orig = decodeInput(s->argv[i]);
00873 QString option = orig.mid(1);
00874 if (option.startsWith('-'))
00875 {
00876 option = option.mid(1);
00877 s->argv[i]++;
00878 if (option.isEmpty())
00879 {
00880 inOptions = false;
00881 continue;
00882 }
00883 }
00884 if (option == "help")
00885 {
00886 KCmdLineArgs::usage();
00887 }
00888 else if (option.startsWith("help-"))
00889 {
00890 KCmdLineArgs::usage(option.mid(5).toUtf8());
00891 }
00892 else if ((option == "version") || (option == "v"))
00893 {
00894 s->printQ( QString("Qt: %1\n").arg(qVersion()));
00895 s->printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING));
00896 s->printQ( QString("%1: %2\n"). arg(s->about->programName()).arg(s->about->version()));
00897 exit(0);
00898 } else if (option == "license")
00899 {
00900 KCmdLineArgs::enable_i18n();
00901 s->printQ( s->about->license() );
00902 s->printQ( "\n" );
00903 exit(0);
00904 } else if (option == "author") {
00905 KCmdLineArgs::enable_i18n();
00906 if ( s->about ) {
00907 const QList<KAboutPerson> authors = s->about->authors();
00908 if ( !authors.isEmpty() ) {
00909 QString authorlist;
00910 for (QList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
00911 QString email;
00912 if ( !(*it).emailAddress().isEmpty() )
00913 email = " <" + (*it).emailAddress() + ">";
00914 authorlist += QString(" ") + (*it).name() + email + '\n';
00915 }
00916 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 ) );
00917 }
00918 } else {
00919 s->printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
00920 }
00921 if (s->about)
00922 {
00923 if (!s->about->customAuthorTextEnabled ())
00924 {
00925 if (s->about->bugAddress().isEmpty() || s->about->bugAddress() == "submit@bugs.kde.org" )
00926 s->printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
00927 else {
00928 s->printQ( i18n( "Please report bugs to %1.\n" , s->about->bugAddress()) );
00929 }
00930 }
00931 else
00932 {
00933 s->printQ(s->about->customAuthorPlainText());
00934 }
00935 }
00936 exit(0);
00937 } else {
00938 if (option.startsWith("no"))
00939 {
00940 option = option.mid(2);
00941 enabled = false;
00942 }
00943 s->findOption(orig, option, i, enabled, inOptions);
00944 }
00945 }
00946 else
00947 {
00948
00949 if (!allowArgs)
00950 {
00951 if (s->ignoreUnknown)
00952 continue;
00953 KCmdLineArgs::enable_i18n();
00954 KCmdLineArgs::usageError(i18n("Unexpected argument '%1'.", KuitSemantics::escape(s->decodeInput(s->argv[i]))));
00955 }
00956 else
00957 {
00958 appOptions->d->addArgument(s->decodeInput(s->argv[i]));
00959 if (everythingAfterArgIsArgs)
00960 inOptions = false;
00961 }
00962 }
00963 }
00964 s->parsed = true;
00965 }
00966
00967 int & KCmdLineArgs::qtArgc()
00968 {
00969 if (!s->argsList)
00970 addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt);
00971
00972 static int qt_argc = -1;
00973 if( qt_argc != -1 )
00974 return qt_argc;
00975
00976 if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
00977 {
00978 qt_argc = 2;
00979 return qt_argc;
00980 }
00981
00982 KCmdLineArgs *args = parsedArgs("qt");
00983 Q_ASSERT(args);
00984 if (!s->argv)
00985 {
00986 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00987 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00988
00989 assert( 0 );
00990 exit(255);
00991 }
00992
00993 Q_ASSERT(s->argc >= (args->count()+1));
00994 qt_argc = args->count() +1;
00995 return qt_argc;
00996 }
00997
00998 static char** s_qt_argv;
00999
01000 char **
01001 KCmdLineArgs::qtArgv()
01002 {
01003 if (!s->argsList)
01004 addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt);
01005
01006 if( s_qt_argv != NULL )
01007 return s_qt_argv;
01008
01009 if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
01010 {
01011 s_qt_argv = new char*[2];
01012 s_qt_argv[0] = qstrdup(s->encodeOutput(appName()));
01013 s_qt_argv[1] = 0;
01014
01015 return s_qt_argv;
01016 }
01017
01018 KCmdLineArgs *args = parsedArgs("qt");
01019 Q_ASSERT(args);
01020 if (!s->argv)
01021 {
01022 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01023 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
01024
01025 assert( 0 );
01026 exit(255);
01027 }
01028
01029 s_qt_argv = new char*[ args->count() + 2 ];
01030 s_qt_argv[0] = qstrdup(s->encodeOutput(appName()));
01031 int i = 0;
01032 for(; i < args->count(); i++)
01033 {
01034 s_qt_argv[i+1] = qstrdup(s->encodeOutput(args->arg(i)));
01035 }
01036 s_qt_argv[i+1] = 0;
01037
01038 return s_qt_argv;
01039 }
01040
01041 const KAboutData *
01042 KCmdLineArgs::aboutData()
01043 {
01044 return s->about;
01045 }
01046
01047 void
01048 KCmdLineArgs::enable_i18n()
01049 {
01050
01051 if (KGlobal::hasLocale())
01052 return;
01053
01054 if (!KGlobal::hasMainComponent()) {
01055 KComponentData mainComponentData(s->about);
01056 mainComponentData.config();
01057
01058 }
01059 }
01060
01061 void
01062 KCmdLineArgs::usageError(const QString &error)
01063 {
01064 Q_ASSERT(KGlobal::hasLocale());
01065 QByteArray localError = s->encodeOutput(error);
01066 if (localError.endsWith('\n'))
01067 localError.chop(1);
01068 fprintf(stderr, "%s: %s\n", s->argv[0], localError.data());
01069
01070 QString tmp = i18n("Use --help to get a list of available command line options.");
01071 localError = s->encodeOutput(tmp);
01072 fprintf(stderr, "%s: %s\n", s->argv[0], localError.data());
01073 exit(254);
01074 }
01075
01076 void
01077 KCmdLineArgs::usage(const QByteArray &id)
01078 {
01079 enable_i18n();
01080 Q_ASSERT(s->argsList != 0);
01081
01082
01083 QString optionFormatString = " %1 %2\n";
01084 QString optionFormatStringDef = " %1 %2 [%3]\n";
01085 QString tmp;
01086 QString usage;
01087
01088 KCmdLineArgsList::Iterator args = --(s->argsList->end());
01089
01090 if ((*args)->d->id.isEmpty() && ((*args)->d->options.d->names.size() > 0) &&
01091 !(*args)->d->options.d->names[0].startsWith('+'))
01092 {
01093 usage = i18n("[options] ")+usage;
01094 }
01095
01096 while(true)
01097 {
01098 if (!(*args)->d->name.isEmpty())
01099 {
01100 usage = i18n("[%1-options]", (*args)->d->name.toString())+' '+usage;
01101 }
01102 if (args == s->argsList->begin())
01103 break;
01104 --args;
01105 }
01106
01107 KCmdLineArgs *appOptions = s->argsList->last();
01108 if (appOptions->d->id.isEmpty())
01109 {
01110 const KCmdLineOptions &option = appOptions->d->options;
01111 for (int i = 0; i < option.d->names.size(); i++)
01112 {
01113 QString opt_name = option.d->names[i];
01114 if (opt_name.startsWith('+'))
01115 usage = usage + (opt_name.mid(1)) + ' ';
01116 else if ( opt_name.startsWith("!+") )
01117 usage = usage + (opt_name.mid(2)) + ' ';
01118 }
01119 }
01120
01121 s->printQ(i18n("Usage: %1 %2\n", s->argv[0], KuitSemantics::escape(usage)));
01122 s->printQ('\n'+s->about->shortDescription()+'\n');
01123
01124 s->printQ(i18n("\nGeneric options:\n"));
01125 s->printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
01126
01127 args = s->argsList->begin();
01128 while(args != s->argsList->end())
01129 {
01130 if (!(*args)->d->name.isEmpty() && !(*args)->d->id.isEmpty())
01131 {
01132 QString option = QString("--help-%1").arg((*args)->d->id);
01133 QString desc = i18n("Show %1 specific options", (*args)->d->name.toString());
01134
01135 s->printQ(optionFormatString.arg(option, -25).arg(desc));
01136 }
01137 ++args;
01138 }
01139
01140 s->printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
01141 s->printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
01142 s->printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
01143 s->printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
01144 s->printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
01145
01146 args = s->argsList->begin();
01147
01148 bool showAll = (id == "all");
01149
01150 if (!showAll)
01151 {
01152 while(args != s->argsList->end())
01153 {
01154 if (id == (*args)->d->id) break;
01155 ++args;
01156 }
01157 }
01158
01159 while(args != s->argsList->end())
01160 {
01161 bool hasArgs = false;
01162 bool hasOptions = false;
01163 QString optionsHeader;
01164 if (!(*args)->d->name.isEmpty())
01165 optionsHeader = i18n("\n%1 options:\n", (*args)->d->name.toString());
01166 else
01167 optionsHeader = i18n("\nOptions:\n");
01168
01169 while (args != s->argsList->end())
01170 {
01171 const KCmdLineOptions &option = (*args)->d->options;
01172 QString opt;
01173
01174 for (int i = 0; i < option.d->names.size(); i++)
01175 {
01176 QString description;
01177 QStringList dl;
01178
01179 QString descriptionFull;
01180 if (!option.d->descriptions[i].isEmpty()) {
01181 descriptionFull = option.d->descriptions[i].toString();
01182 }
01183
01184
01185 if (option.d->names[i].startsWith(':'))
01186 {
01187 if (!descriptionFull.isEmpty())
01188 {
01189 optionsHeader = '\n'+descriptionFull;
01190 if (!optionsHeader.endsWith('\n'))
01191 optionsHeader.append('\n');
01192 hasOptions = false;
01193 }
01194 continue;
01195 }
01196
01197
01198 if (option.d->names[i].isEmpty())
01199 {
01200 if (!descriptionFull.isEmpty())
01201 {
01202 tmp = '\n'+descriptionFull;
01203 if (!tmp.endsWith('\n'))
01204 tmp.append('\n');
01205 s->printQ(tmp);
01206 }
01207 continue;
01208 }
01209
01210
01211 if (!descriptionFull.isEmpty())
01212 {
01213 dl = descriptionFull.split( '\n', QString::KeepEmptyParts);
01214 description = dl.first();
01215 dl.erase( dl.begin() );
01216 }
01217 QString name = option.d->names[i];
01218 if (name.startsWith('!'))
01219 name = name.mid(1);
01220
01221 if (name.startsWith('+'))
01222 {
01223 if (!hasArgs)
01224 {
01225 s->printQ(i18n("\nArguments:\n"));
01226 hasArgs = true;
01227 }
01228
01229 name = name.mid(1);
01230 if (name.startsWith('[') && name.endsWith(']'))
01231 name = name.mid(1, name.length()-2);
01232 s->printQ(optionFormatString.arg(name, -25).arg(description));
01233 }
01234 else
01235 {
01236 if (!hasOptions)
01237 {
01238 s->printQ(optionsHeader);
01239 hasOptions = true;
01240 }
01241
01242 if ((name.length() == 1) || (name[1] == ' '))
01243 name = '-'+name;
01244 else
01245 name = "--"+name;
01246 if (descriptionFull.isEmpty())
01247 {
01248 opt = name + ", ";
01249 }
01250 else
01251 {
01252 opt = opt + name;
01253 if (option.d->defaults[i].isEmpty())
01254 {
01255 s->printQ(optionFormatString.arg(QString( opt ), -25).arg(description));
01256 }
01257 else
01258 {
01259 s->printQ(optionFormatStringDef.arg(QString( opt ), -25)
01260 .arg(description, option.d->defaults[i]));
01261 }
01262 opt = "";
01263 }
01264 }
01265 for(QStringList::Iterator it = dl.begin();
01266 it != dl.end();
01267 ++it)
01268 {
01269 s->printQ(optionFormatString.arg("", -25).arg(*it));
01270 }
01271 }
01272
01273 ++args;
01274 if (args == s->argsList->end() || !(*args)->d->name.isEmpty() || (*args)->d->id.isEmpty())
01275 break;
01276 }
01277 if (!showAll) break;
01278 }
01279
01280 exit(0);
01281 }
01282
01283
01284
01285
01286
01292 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions &_options,
01293 const KLocalizedString &_name,
01294 const QByteArray &_id)
01295 : d(new KCmdLineArgsPrivate(_options, _name, _id))
01296 {
01297 }
01298
01302 KCmdLineArgs::~KCmdLineArgs()
01303 {
01304 if (!s.isDestroyed() && s->argsList)
01305 s->argsList->removeAll(this);
01306 delete d;
01307 }
01308
01309 void
01310 KCmdLineArgs::setCwd( const QByteArray &cwd )
01311 {
01312 s->mCwd = QString::fromUtf8(cwd);
01313 }
01314
01315 void
01316 KCmdLineArgs::clear()
01317 {
01318 delete d->parsedArgList;
01319 d->parsedArgList = 0;
01320 delete d->parsedOptionList;
01321 d->parsedOptionList = 0;
01322 }
01323
01324 void
01325 KCmdLineArgs::reset()
01326 {
01327 if ( s->argsList ) {
01328 delete s->argsList;
01329 s->argsList = 0;
01330 }
01331 s->parsed = false;
01332 }
01333
01334 void
01335 KCmdLineArgsPrivate::save( QDataStream &ds) const
01336 {
01337 if (parsedOptionList)
01338 ds << (*(parsedOptionList));
01339 else
01340 ds << quint32(0);
01341
01342 if (parsedArgList)
01343 ds << (*(parsedArgList));
01344 else
01345 ds << quint32(0);
01346 }
01347
01348 void
01349 KCmdLineArgsPrivate::load( QDataStream &ds)
01350 {
01351 if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
01352 if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
01353
01354 ds >> (*(parsedOptionList));
01355 ds >> (*(parsedArgList));
01356
01357 if (parsedOptionList->count() == 0)
01358 {
01359 delete parsedOptionList;
01360 parsedOptionList = 0;
01361 }
01362 if (parsedArgList->count() == 0)
01363 {
01364 delete parsedArgList;
01365 parsedArgList = 0;
01366 }
01367 }
01368
01369 void
01370 KCmdLineArgsPrivate::setOption(const QString &opt, bool enabled)
01371 {
01372 if (isQt)
01373 {
01374
01375 QString argString = "-";
01376 if( !enabled )
01377 argString += "no";
01378 argString += opt;
01379 addArgument(argString);
01380 }
01381 if (!parsedOptionList) {
01382 parsedOptionList = new KCmdLineParsedOptions;
01383 }
01384
01385 if (enabled)
01386 parsedOptionList->insert( opt, QString::fromUtf8("t") );
01387 else
01388 parsedOptionList->insert( opt, QString::fromUtf8("f") );
01389 }
01390
01391 void
01392 KCmdLineArgsPrivate::setOption(const QString &opt, const QString &value)
01393 {
01394 if (isQt)
01395 {
01396
01397 QString argString = "-";
01398 argString += opt;
01399 addArgument(argString);
01400 addArgument(value);
01401
01402 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01403
01404 if (argString == "-display")
01405 {
01406 setenv(DISPLAY, s->encodeOutput(value).data(), true);
01407 }
01408 #endif
01409 }
01410 if (!parsedOptionList) {
01411 parsedOptionList = new KCmdLineParsedOptions;
01412 }
01413
01414 parsedOptionList->insertMulti( opt, value );
01415 }
01416
01417 QString
01418 KCmdLineArgs::getOption(const QByteArray &_opt) const
01419 {
01420 QString opt = QString::fromUtf8(_opt);
01421 QString value;
01422 if (d->parsedOptionList)
01423 {
01424 value = d->parsedOptionList->value(opt);
01425 }
01426 if (!value.isEmpty())
01427 return value;
01428
01429
01430 QString opt_name;
01431 QString def;
01432 bool dummy = true;
01433 int result = s->findOption( d->options, opt, opt_name, def, dummy) & ~4;
01434
01435 if (result != 3)
01436 {
01437 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01438 fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
01439 s->encodeOutput(opt).data(), s->encodeOutput(opt).data());
01440 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01441
01442 Q_ASSERT( 0 );
01443 exit(255);
01444 }
01445 return def;
01446 }
01447
01448 QStringList
01449 KCmdLineArgs::getOptionList(const QByteArray &_opt) const
01450 {
01451 QString opt = QString::fromUtf8(_opt);
01452
01453 QStringList result;
01454 if (!d->parsedOptionList)
01455 return result;
01456
01457 while(true)
01458 {
01459 QString value = d->parsedOptionList->take(opt);
01460 if (value.isEmpty())
01461 break;
01462 result.prepend(value);
01463 }
01464
01465
01466
01467
01468
01469
01470 Q_FOREACH(const QString &str, result)
01471 {
01472 d->parsedOptionList->insertMulti(opt, str);
01473 }
01474 return result;
01475 }
01476
01477 bool
01478 KCmdLineArgs::isSet(const QByteArray &_opt) const
01479 {
01480
01481 QString opt = QString::fromUtf8(_opt);
01482 QString opt_name;
01483 QString def;
01484 int result = 0;
01485 KCmdLineArgsList::Iterator args = s->argsList->begin();
01486 while (args != s->argsList->end())
01487 {
01488 bool dummy = true;
01489 result = s->findOption((*args)->d->options, opt, opt_name, def, dummy) & ~4;
01490 if (result) break;
01491 ++args;
01492 }
01493
01494 if (result == 0)
01495 {
01496 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01497 fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
01498 s->encodeOutput(opt).data(), s->encodeOutput(opt).data());
01499 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01500
01501 Q_ASSERT( 0 );
01502 exit(255);
01503 }
01504
01505 QString value;
01506 if (d->parsedOptionList)
01507 {
01508 value = d->parsedOptionList->value(opt);
01509 }
01510
01511 if (!value.isEmpty())
01512 {
01513 if (result == 3)
01514 return true;
01515 else
01516 return (value[0] == 't');
01517 }
01518
01519 if (result == 3)
01520 return false;
01521
01522
01523
01524 return (result == 2);
01525 }
01526
01527 int
01528 KCmdLineArgs::count() const
01529 {
01530 if (!d->parsedArgList)
01531 return 0;
01532 return d->parsedArgList->count();
01533 }
01534
01535 QString
01536 KCmdLineArgs::arg(int n) const
01537 {
01538 if (!d->parsedArgList || (n >= (int) d->parsedArgList->count()))
01539 {
01540 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
01541 fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
01542 n);
01543
01544 Q_ASSERT( 0 );
01545 exit(255);
01546 }
01547
01548 return d->parsedArgList->at(n);
01549 }
01550
01551 KUrl
01552 KCmdLineArgs::url(int n) const
01553 {
01554 return makeURL( arg(n).toUtf8() );
01555 }
01556
01557 KUrl KCmdLineArgs::makeURL(const QByteArray &_urlArg)
01558 {
01559 const QString urlArg = QString::fromUtf8(_urlArg);
01560 QFileInfo fileInfo(urlArg);
01561 if (!fileInfo.isRelative()) {
01562 KUrl result;
01563 result.setPath(QDir::fromNativeSeparators(urlArg));
01564 return result;
01565 }
01566
01567 if ( KUrl::isRelativeUrl(urlArg) || fileInfo.exists() ) {
01568 KUrl result;
01569 result.setPath( cwd()+'/'+urlArg );
01570 result.cleanPath();
01571 return result;
01572 }
01573
01574 return KUrl(urlArg);
01575 }
01576
01577 void
01578 KCmdLineArgsPrivate::addArgument(const QString &argument)
01579 {
01580 if (!parsedArgList)
01581 parsedArgList = new KCmdLineParsedArgs;
01582
01583 parsedArgList->append(argument);
01584 }
01585
01586 void
01587 KCmdLineArgs::addTempFileOption()
01588 {
01589 KCmdLineOptions tmpopt;
01590 tmpopt.add( "tempfile", ki18n("The files/URLs opened by the application will be deleted after use") );
01591 KCmdLineArgs::addCmdLineOptions( tmpopt, ki18n("KDE-tempfile"), "kde-tempfile" );
01592 }
01593
01594 bool KCmdLineArgs::isTempFileSet()
01595 {
01596 KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
01597 if ( args )
01598 return args->isSet( "tempfile" );
01599 return false;
01600 }