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 = QString();
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
00305
00306 kde_options.add("caption <caption>", ki18n("Use 'caption' as name in the titlebar"));
00307 kde_options.add("icon <icon>", ki18n("Use 'icon' as the application icon"));
00308 kde_options.add("config <filename>", ki18n("Use alternative configuration file"));
00309 kde_options.add("nocrashhandler", ki18n("Disable crash handler, to get core dumps"));
00310 #ifdef Q_WS_X11
00311 kde_options.add("waitforwm", ki18n("Waits for a WM_NET compatible windowmanager"));
00312 #endif
00313 kde_options.add("style <style>", ki18n("sets the application GUI style"));
00314 kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format"));
00315 #ifndef Q_WS_WIN
00316 kde_options.add("smkey <sessionKey>");
00317 #endif
00318 }
00319
00320 KCmdLineArgsStatic::~KCmdLineArgsStatic ()
00321 {
00322 delete argsList;
00323
00324
00325 }
00326
00327
00328
00329
00330
00331 class KCmdLineArgsPrivate
00332 {
00333 friend class KCmdLineArgsStatic;
00334 public:
00335 KCmdLineArgsPrivate(const KCmdLineOptions &_options, const KLocalizedString &_name, const QString &_id)
00336 : options(_options)
00337 , name(_name)
00338 , id(_id)
00339 , parsedOptionList(0)
00340 , parsedArgList(0)
00341 , isQt(id == "qt")
00342 {}
00343 ~KCmdLineArgsPrivate()
00344 {
00345 delete parsedOptionList;
00346 delete parsedArgList;
00347 }
00348 const KCmdLineOptions options;
00349 const KLocalizedString name;
00350 const QString id;
00351 KCmdLineParsedOptions *parsedOptionList;
00352 KCmdLineParsedArgs *parsedArgList;
00353 bool isQt;
00354
00360 void setOption(const QString &option, bool enabled);
00361
00367 void setOption(const QString &option, const QString &value);
00368
00374 void addArgument(const QString &argument);
00375
00381 void save( QDataStream &) const;
00382
00388 void load( QDataStream &);
00389 };
00390
00391
00392
00393
00394
00395 QString
00396 KCmdLineArgsStatic::decodeInput(const QByteArray &rawstr)
00397 {
00398 return s->codec->toUnicode(rawstr);
00399 }
00400
00401 QByteArray
00402 KCmdLineArgsStatic::encodeOutput(const QString &str)
00403 {
00404 return s->codec->fromUnicode(str);
00405 }
00406
00407 void
00408 KCmdLineArgsStatic::printQ(const QString &msg)
00409 {
00410 fprintf(stdout, "%s", encodeOutput(msg).data());
00411 }
00412
00413 void
00414 KCmdLineArgs::init(int _argc, char **_argv,
00415 const QByteArray &_appname,
00416 const QByteArray &_catalog,
00417 const KLocalizedString &_programName,
00418 const QByteArray &_version,
00419 const KLocalizedString &_description,
00420 StdCmdLineArgs stdargs)
00421 {
00422 init(_argc, _argv,
00423 new KAboutData(_appname, _catalog, _programName, _version, _description),
00424 stdargs);
00425 }
00426
00427 void
00428 KCmdLineArgs::initIgnore(int _argc, char **_argv, const QByteArray &_appname )
00429 {
00430 init(_argc, _argv,
00431 new KAboutData(_appname, 0, ki18n(_appname), "unknown", ki18n("KDE Application")));
00432 s->ignoreUnknown = true;
00433 }
00434
00435 void
00436 KCmdLineArgs::init(const KAboutData* ab)
00437 {
00438 char **_argv = (char **) malloc(sizeof(char *));
00439 _argv[0] = (char *) s->encodeOutput(ab->appName()).data();
00440 init(1,_argv,ab, CmdLineArgNone);
00441 }
00442
00443
00444 void
00445 KCmdLineArgs::init(int _argc, char **_argv, const KAboutData *_about, StdCmdLineArgs stdargs)
00446 {
00447 s->argc = _argc;
00448 s->argv = _argv;
00449
00450 if (!s->argv)
00451 {
00452 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00453 fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
00454
00455 assert( 0 );
00456 exit(255);
00457 }
00458
00459
00460 if (s->argc) {
00461 char *p = strrchr( s->argv[0], '/');
00462 if (p)
00463 s->argv[0] = p+1;
00464 }
00465
00466 s->about = _about;
00467 s->parsed = false;
00468 s->mCwd = QDir::currentPath();
00469 addStdCmdLineOptions(stdargs);
00470 }
00471
00472 QString KCmdLineArgs::cwd()
00473 {
00474 return s->mCwd;
00475 }
00476
00477 QString KCmdLineArgs::appName()
00478 {
00479 if (!s->argc) return QString();
00480 return s->decodeInput(s->argv[0]);
00481 }
00482
00486 void KCmdLineArgs::addStdCmdLineOptions(StdCmdLineArgs stdargs) {
00487 if (stdargs & KCmdLineArgs::CmdLineArgQt) {
00488 KCmdLineArgs::addCmdLineOptions(s->qt_options, ki18n("Qt"), "qt");
00489 }
00490 if (stdargs & KCmdLineArgs::CmdLineArgKDE) {
00491 KCmdLineArgs::addCmdLineOptions(s->kde_options, ki18n("KDE"), "kde");
00492 }
00493 s->mStdargs = stdargs;
00494 }
00495
00496 void
00497 KCmdLineArgs::addCmdLineOptions( const KCmdLineOptions &options, const KLocalizedString &name,
00498 const QByteArray &_id, const QByteArray &_afterId)
00499 {
00500 if (!s->argsList)
00501 s->argsList = new KCmdLineArgsList;
00502
00503 QString id = QString::fromUtf8(_id);
00504 QString afterId = QString::fromUtf8(_afterId);
00505
00506 int pos = s->argsList->count();
00507
00508 if (pos > 0 && !id.isEmpty() && s->argsList->last()->d->name.isEmpty())
00509 pos--;
00510
00511 KCmdLineArgsList::Iterator args;
00512 int i = 0;
00513 for(args = s->argsList->begin(); args != s->argsList->end(); ++args, i++)
00514 {
00515 if (id == (*args)->d->id)
00516 return;
00517
00518
00519
00520 if (!afterId.isEmpty() && afterId == (*args)->d->id)
00521 pos = i+1;
00522 }
00523
00524 Q_ASSERT( s->parsed == false );
00525
00526 s->argsList->insert(pos, new KCmdLineArgs(options, name, id.toUtf8()));
00527 }
00528
00529 void
00530 KCmdLineArgs::saveAppArgs( QDataStream &ds)
00531 {
00532 if (!s->parsed)
00533 s->parseAllArgs();
00534
00535
00536 s->removeArgs("qt");
00537 s->removeArgs("kde");
00538
00539 QByteArray qCwd = QFile::encodeName(s->mCwd);
00540 ds << qCwd;
00541
00542 uint count = s->argsList ? s->argsList->count() : 0;
00543 ds << count;
00544
00545 if (!count) return;
00546
00547 KCmdLineArgsList::Iterator args;
00548 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00549 {
00550 ds << (*args)->d->id;
00551 (*args)->d->save(ds);
00552 }
00553 }
00554
00555 void
00556 KCmdLineArgs::loadAppArgs( QDataStream &ds)
00557 {
00558 s->parsed = true;
00559
00560
00561 s->removeArgs("qt");
00562 s->removeArgs("kde");
00563
00564 KCmdLineArgsList::Iterator args;
00565 if ( s->argsList ) {
00566 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00567 {
00568 (*args)->clear();
00569 }
00570 }
00571
00572 if (ds.atEnd())
00573 return;
00574
00575 QByteArray qCwd;
00576 ds >> qCwd;
00577
00578 s->mCwd = QFile::decodeName(qCwd);
00579
00580 uint count;
00581 ds >> count;
00582
00583 while(count--)
00584 {
00585 QByteArray idRaw;
00586 ds >> idRaw;
00587 QString id = idRaw;
00588 Q_ASSERT( s->argsList );
00589 for(args = s->argsList->begin(); args != s->argsList->end(); ++args)
00590 {
00591 if ((*args)->d->id == id)
00592 {
00593 (*args)->d->load(ds);
00594 break;
00595 }
00596 }
00597 }
00598 s->parsed = true;
00599 }
00600
00601 KCmdLineArgs *KCmdLineArgs::parsedArgs(const QByteArray &_id)
00602 {
00603 QString id = QString::fromUtf8(_id);
00604 if (!s->argsList)
00605 return 0;
00606 KCmdLineArgsList::Iterator args = s->argsList->begin();
00607 while(args != s->argsList->end())
00608 {
00609 if ((*args)->d->id == id)
00610 {
00611 if (!s->parsed)
00612 s->parseAllArgs();
00613 return *args;
00614 }
00615 ++args;
00616 }
00617
00618 return 0;
00619 }
00620
00621 void KCmdLineArgsStatic::removeArgs(const QString &id)
00622 {
00623 if (!s->argsList)
00624 return;
00625 KCmdLineArgsList::Iterator args = s->argsList->begin();
00626 while(args != s->argsList->end())
00627 {
00628 if ((*args)->d->id == id)
00629 {
00630 if (!s->parsed)
00631 s->parseAllArgs();
00632 break;
00633 }
00634 ++args;
00635 }
00636
00637 if (args != s->argsList->end()) {
00638 KCmdLineArgs *a = *args;
00639 s->argsList->erase(args);
00640 delete a;
00641 }
00642 }
00643
00644 int
00645 KCmdLineArgsStatic::findOption(const KCmdLineOptions &options, QString &opt,
00646 QString &opt_name, QString &def, bool &enabled)
00647 {
00648 int result;
00649 bool inverse;
00650
00651 for (int i = 0; i < options.d->names.size(); i++)
00652 {
00653 result = 0;
00654 inverse = false;
00655 opt_name = options.d->names[i].toUtf8();
00656 if (opt_name.startsWith(':') || opt_name.isEmpty())
00657 {
00658 continue;
00659 }
00660 if (opt_name.startsWith('!'))
00661 {
00662 opt_name = opt_name.mid(1);
00663 result = 4;
00664 }
00665 if (opt_name.startsWith("no"))
00666 {
00667 opt_name = opt_name.mid(2);
00668 inverse = true;
00669 }
00670
00671 int len = opt.length();
00672 if (opt == opt_name.left(len))
00673 {
00674 opt_name = opt_name.mid(len);
00675 if (opt_name.isEmpty())
00676 {
00677 if (inverse)
00678 return result+2;
00679
00680 if (options.d->descriptions[i].isEmpty())
00681 {
00682 i++;
00683 if (i >= options.d->names.size())
00684 return result+0;
00685 QString nextOption = options.d->names[i].toUtf8();
00686 int p = nextOption.indexOf(' ');
00687 if (p > 0)
00688 nextOption = nextOption.left(p);
00689 if (nextOption.startsWith('!'))
00690 nextOption = nextOption.mid(1);
00691 if (nextOption.startsWith("no"))
00692 {
00693 nextOption = nextOption.mid(2);
00694 enabled = !enabled;
00695 }
00696 result = findOption(options, nextOption, opt_name, def, enabled);
00697 Q_ASSERT(result);
00698 opt = nextOption;
00699 return result;
00700 }
00701
00702 return 1;
00703 }
00704 if (opt_name.startsWith(' '))
00705 {
00706 opt_name = opt_name.mid(1);
00707 def = options.d->defaults[i].toUtf8();
00708 return result+3;
00709 }
00710 }
00711 }
00712 return 0;
00713 }
00714
00715 void
00716 KCmdLineArgsStatic::findOption(const QString &optv, const QString &_opt,
00717 int &i, bool _enabled, bool &moreOptions)
00718 {
00719 KCmdLineArgsList::Iterator args = s->argsList->begin();
00720 QString opt = _opt;
00721 QString opt_name;
00722 QString def;
00723 QString argument;
00724 int j = opt.indexOf('=');
00725 if (j != -1)
00726 {
00727 argument = opt.mid(j+1);
00728 opt = opt.left(j);
00729 }
00730 #ifdef Q_WS_MACX
00731 if(opt.startsWith("psn_"))
00732 opt = "psn";
00733 #endif
00734
00735 bool enabled = true;
00736 int result = 0;
00737 while (args != s->argsList->end())
00738 {
00739 enabled = _enabled;
00740 result = findOption((*args)->d->options, opt, opt_name, def, enabled);
00741 if (result) break;
00742 ++args;
00743 }
00744 if ((args == s->argsList->end()) &&
00745 (optv.startsWith('-') && !optv.startsWith("--")))
00746 {
00747
00748
00749 int p = 1;
00750 while (true)
00751 {
00752 QString singleCharOption = " ";
00753 singleCharOption[0] = optv[p];
00754 args = s->argsList->begin();
00755 while (args != s->argsList->end())
00756 {
00757 enabled = _enabled;
00758 result = findOption((*args)->d->options, singleCharOption,
00759 opt_name, def, enabled);
00760 if (result) break;
00761 ++args;
00762 }
00763 if (args == s->argsList->end())
00764 break;
00765
00766 p++;
00767 if (result == 1)
00768 {
00769 (*args)->d->setOption(singleCharOption, enabled);
00770 if (p < optv.length())
00771 continue;
00772 else
00773 return;
00774 }
00775 else if (result == 3)
00776 {
00777 if (argument.isEmpty())
00778 {
00779 argument = optv.mid(p);
00780 }
00781 (*args)->d->setOption(singleCharOption, argument);
00782 return;
00783 }
00784 break;
00785 }
00786 args = s->argsList->end();
00787 result = 0;
00788 }
00789
00790 if (args == s->argsList->end() || !result)
00791 {
00792 if (s->ignoreUnknown)
00793 return;
00794 #ifdef Q_WS_MACX
00795 if (_opt.startsWith("psn_", Qt::CaseInsensitive))
00796 return;
00797 #endif
00798 KCmdLineArgs::enable_i18n();
00799 KCmdLineArgs::usageError( i18n("Unknown option '%1'.", _opt));
00800 }
00801
00802 if ((result & 4) != 0)
00803 {
00804 result &= ~4;
00805 moreOptions = false;
00806 }
00807
00808 if (result == 3)
00809 {
00810 if (!enabled)
00811 {
00812 if (s->ignoreUnknown)
00813 return;
00814 #ifdef Q_WS_MACX
00815 if (_opt.startsWith("psn_", Qt::CaseInsensitive))
00816 return;
00817 #endif
00818 KCmdLineArgs::enable_i18n();
00819 KCmdLineArgs::usageError( i18n("Unknown option '%1'.", _opt));
00820 }
00821 if (argument.isEmpty())
00822 {
00823 i++;
00824 if (i >= s->argc)
00825 {
00826 KCmdLineArgs::enable_i18n();
00827 KCmdLineArgs::usageError( i18nc("@info:shell %1 is cmdoption name","'%1' missing.", opt_name));
00828 }
00829 argument = s->decodeInput(s->argv[i]);
00830 }
00831 (*args)->d->setOption(opt, argument);
00832 }
00833 else
00834 {
00835 (*args)->d->setOption(opt, enabled);
00836 }
00837 }
00838
00839 void
00840 KCmdLineArgsStatic::parseAllArgs()
00841 {
00842 bool allowArgs = false;
00843 bool inOptions = true;
00844 bool everythingAfterArgIsArgs = false;
00845 KCmdLineArgs *appOptions = s->argsList->last();
00846 if (appOptions->d->id.isEmpty())
00847 {
00848 const KCmdLineOptions &option = appOptions->d->options;
00849 for (int i = 0; i < option.d->names.size(); i++)
00850 {
00851 if (option.d->names[i].startsWith('+'))
00852 allowArgs = true;
00853 if ( option.d->names[i].startsWith("!+") )
00854 {
00855 allowArgs = true;
00856 everythingAfterArgIsArgs = true;
00857 }
00858 }
00859 }
00860 for(int i = 1; i < s->argc; i++)
00861 {
00862 if (!s->argv[i])
00863 continue;
00864
00865 if ((s->argv[i][0] == '-') && s->argv[i][1] && inOptions)
00866 {
00867 bool enabled = true;
00868 QString orig = decodeInput(s->argv[i]);
00869 QString option = orig.mid(1);
00870 if (option.startsWith('-'))
00871 {
00872 option = option.mid(1);
00873 s->argv[i]++;
00874 if (option.isEmpty())
00875 {
00876 inOptions = false;
00877 continue;
00878 }
00879 }
00880 if (option == "help")
00881 {
00882 KCmdLineArgs::usage();
00883 }
00884 else if (option.startsWith("help-"))
00885 {
00886 KCmdLineArgs::usage(option.mid(5).toUtf8());
00887 }
00888 else if ((option == "version") || (option == "v"))
00889 {
00890 s->printQ( QString("Qt: %1\n").arg(qVersion()));
00891 s->printQ( QString("KDE: %1\n").arg(KDE_VERSION_STRING));
00892 s->printQ( QString("%1: %2\n"). arg(s->about->programName()).arg(s->about->version()));
00893 exit(0);
00894 } else if (option == "license")
00895 {
00896 KCmdLineArgs::enable_i18n();
00897 s->printQ( s->about->license() );
00898 s->printQ( "\n" );
00899 exit(0);
00900 } else if (option == "author") {
00901 KCmdLineArgs::enable_i18n();
00902 if ( s->about ) {
00903 const QList<KAboutPerson> authors = s->about->authors();
00904 if ( !authors.isEmpty() ) {
00905 QString authorlist;
00906 for (QList<KAboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it ) {
00907 QString email;
00908 if ( !(*it).emailAddress().isEmpty() )
00909 email = " <" + (*it).emailAddress() + ">";
00910 authorlist += QString(" ") + (*it).name() + email + '\n';
00911 }
00912 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 ) );
00913 }
00914 } else {
00915 s->printQ( i18n("This application was written by somebody who wants to remain anonymous.") );
00916 }
00917 if (s->about)
00918 {
00919 if (!s->about->customAuthorTextEnabled ())
00920 {
00921 if (s->about->bugAddress().isEmpty() || s->about->bugAddress() == "submit@bugs.kde.org" )
00922 s->printQ( i18n( "Please use http://bugs.kde.org to report bugs.\n" ) );
00923 else {
00924 s->printQ( i18n( "Please report bugs to %1.\n" , s->about->bugAddress()) );
00925 }
00926 }
00927 else
00928 {
00929 s->printQ(s->about->customAuthorPlainText());
00930 }
00931 }
00932 exit(0);
00933 } else {
00934 if (option.startsWith("no"))
00935 {
00936 option = option.mid(2);
00937 enabled = false;
00938 }
00939 s->findOption(orig, option, i, enabled, inOptions);
00940 }
00941 }
00942 else
00943 {
00944
00945 if (!allowArgs)
00946 {
00947 if (s->ignoreUnknown)
00948 continue;
00949 KCmdLineArgs::enable_i18n();
00950 KCmdLineArgs::usageError(i18n("Unexpected argument '%1'.", KuitSemantics::escape(s->decodeInput(s->argv[i]))));
00951 }
00952 else
00953 {
00954 appOptions->d->addArgument(s->decodeInput(s->argv[i]));
00955 if (everythingAfterArgIsArgs)
00956 inOptions = false;
00957 }
00958 }
00959 }
00960 s->parsed = true;
00961 }
00962
00963 int & KCmdLineArgs::qtArgc()
00964 {
00965 if (!s->argsList)
00966 addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt);
00967
00968 static int qt_argc = -1;
00969 if( qt_argc != -1 )
00970 return qt_argc;
00971
00972 if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
00973 {
00974 qt_argc = 2;
00975 return qt_argc;
00976 }
00977
00978 KCmdLineArgs *args = parsedArgs("qt");
00979 Q_ASSERT(args);
00980 if (!s->argv)
00981 {
00982 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
00983 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
00984
00985 assert( 0 );
00986 exit(255);
00987 }
00988
00989 Q_ASSERT(s->argc >= (args->count()+1));
00990 qt_argc = args->count() +1;
00991 return qt_argc;
00992 }
00993
00994 static char** s_qt_argv;
00995
00996 char **
00997 KCmdLineArgs::qtArgv()
00998 {
00999 if (!s->argsList)
01000 addStdCmdLineOptions(CmdLineArgKDE|CmdLineArgQt);
01001
01002 if( s_qt_argv != NULL )
01003 return s_qt_argv;
01004
01005 if (!(s->mStdargs & KCmdLineArgs::CmdLineArgQt))
01006 {
01007 s_qt_argv = new char*[2];
01008 s_qt_argv[0] = qstrdup(s->encodeOutput(appName()));
01009 s_qt_argv[1] = 0;
01010
01011 return s_qt_argv;
01012 }
01013
01014 KCmdLineArgs *args = parsedArgs("qt");
01015 Q_ASSERT(args);
01016 if (!s->argv)
01017 {
01018 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01019 fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
01020
01021 assert( 0 );
01022 exit(255);
01023 }
01024
01025 s_qt_argv = new char*[ args->count() + 2 ];
01026 s_qt_argv[0] = qstrdup(s->encodeOutput(appName()));
01027 int i = 0;
01028 for(; i < args->count(); i++)
01029 {
01030 s_qt_argv[i+1] = qstrdup(s->encodeOutput(args->arg(i)));
01031 }
01032 s_qt_argv[i+1] = 0;
01033
01034 return s_qt_argv;
01035 }
01036
01037 const KAboutData *
01038 KCmdLineArgs::aboutData()
01039 {
01040 return s->about;
01041 }
01042
01043 void
01044 KCmdLineArgs::enable_i18n()
01045 {
01046
01047 if (KGlobal::hasLocale())
01048 return;
01049
01050 if (!KGlobal::hasMainComponent()) {
01051 KComponentData mainComponentData(s->about);
01052 mainComponentData.config();
01053
01054 }
01055 }
01056
01057 void
01058 KCmdLineArgs::usageError(const QString &error)
01059 {
01060 Q_ASSERT(KGlobal::hasLocale());
01061 QByteArray localError = s->encodeOutput(error);
01062 if (localError.endsWith('\n'))
01063 localError.chop(1);
01064 fprintf(stderr, "%s: %s\n", s->argv[0], localError.data());
01065
01066 QString tmp = i18n("Use --help to get a list of available command line options.");
01067 localError = s->encodeOutput(tmp);
01068 fprintf(stderr, "%s: %s\n", s->argv[0], localError.data());
01069 exit(254);
01070 }
01071
01072 void
01073 KCmdLineArgs::usage(const QByteArray &id)
01074 {
01075 enable_i18n();
01076 Q_ASSERT(s->argsList != 0);
01077
01078
01079 QString optionFormatString = " %1 %2\n";
01080 QString optionFormatStringDef = " %1 %2 [%3]\n";
01081 QString tmp;
01082 QString usage;
01083
01084 KCmdLineArgsList::Iterator args = --(s->argsList->end());
01085
01086 if ((*args)->d->id.isEmpty() && ((*args)->d->options.d->names.size() > 0) &&
01087 !(*args)->d->options.d->names[0].startsWith('+'))
01088 {
01089 usage = i18n("[options] ")+usage;
01090 }
01091
01092 while(true)
01093 {
01094 if (!(*args)->d->name.isEmpty())
01095 {
01096 usage = i18n("[%1-options]", (*args)->d->name.toString())+' '+usage;
01097 }
01098 if (args == s->argsList->begin())
01099 break;
01100 --args;
01101 }
01102
01103 KCmdLineArgs *appOptions = s->argsList->last();
01104 if (appOptions->d->id.isEmpty())
01105 {
01106 const KCmdLineOptions &option = appOptions->d->options;
01107 for (int i = 0; i < option.d->names.size(); i++)
01108 {
01109 QString opt_name = option.d->names[i];
01110 if (opt_name.startsWith('+'))
01111 usage = usage + (opt_name.mid(1)) + ' ';
01112 else if ( opt_name.startsWith("!+") )
01113 usage = usage + (opt_name.mid(2)) + ' ';
01114 }
01115 }
01116
01117 s->printQ(i18n("Usage: %1 %2\n", s->argv[0], KuitSemantics::escape(usage)));
01118 s->printQ('\n'+s->about->shortDescription()+'\n');
01119
01120 s->printQ(i18n("\nGeneric options:\n"));
01121 s->printQ(optionFormatString.arg("--help", -25).arg(i18n("Show help about options")));
01122
01123 args = s->argsList->begin();
01124 while(args != s->argsList->end())
01125 {
01126 if (!(*args)->d->name.isEmpty() && !(*args)->d->id.isEmpty())
01127 {
01128 QString option = QString("--help-%1").arg((*args)->d->id);
01129 QString desc = i18n("Show %1 specific options", (*args)->d->name.toString());
01130
01131 s->printQ(optionFormatString.arg(option, -25).arg(desc));
01132 }
01133 ++args;
01134 }
01135
01136 s->printQ(optionFormatString.arg("--help-all",-25).arg(i18n("Show all options")));
01137 s->printQ(optionFormatString.arg("--author",-25).arg(i18n("Show author information")));
01138 s->printQ(optionFormatString.arg("-v, --version",-25).arg(i18n("Show version information")));
01139 s->printQ(optionFormatString.arg("--license",-25).arg(i18n("Show license information")));
01140 s->printQ(optionFormatString.arg("--", -25).arg(i18n("End of options")));
01141
01142 args = s->argsList->begin();
01143
01144 bool showAll = (id == "all");
01145
01146 if (!showAll)
01147 {
01148 while(args != s->argsList->end())
01149 {
01150 if (id == (*args)->d->id) break;
01151 ++args;
01152 }
01153 }
01154
01155 while(args != s->argsList->end())
01156 {
01157 bool hasArgs = false;
01158 bool hasOptions = false;
01159 QString optionsHeader;
01160 if (!(*args)->d->name.isEmpty())
01161 optionsHeader = i18n("\n%1 options:\n", (*args)->d->name.toString());
01162 else
01163 optionsHeader = i18n("\nOptions:\n");
01164
01165 while (args != s->argsList->end())
01166 {
01167 const KCmdLineOptions &option = (*args)->d->options;
01168 QString opt;
01169
01170 for (int i = 0; i < option.d->names.size(); i++)
01171 {
01172 QString description;
01173 QStringList dl;
01174
01175 QString descriptionFull;
01176 if (!option.d->descriptions[i].isEmpty()) {
01177 descriptionFull = option.d->descriptions[i].toString();
01178 }
01179
01180
01181 if (option.d->names[i].startsWith(':'))
01182 {
01183 if (!descriptionFull.isEmpty())
01184 {
01185 optionsHeader = '\n'+descriptionFull;
01186 if (!optionsHeader.endsWith('\n'))
01187 optionsHeader.append('\n');
01188 hasOptions = false;
01189 }
01190 continue;
01191 }
01192
01193
01194 if (option.d->names[i].isEmpty())
01195 {
01196 if (!descriptionFull.isEmpty())
01197 {
01198 tmp = '\n'+descriptionFull;
01199 if (!tmp.endsWith('\n'))
01200 tmp.append('\n');
01201 s->printQ(tmp);
01202 }
01203 continue;
01204 }
01205
01206
01207 if (!descriptionFull.isEmpty())
01208 {
01209 dl = descriptionFull.split( "\n", QString::KeepEmptyParts);
01210 description = dl.first();
01211 dl.erase( dl.begin() );
01212 }
01213 QString name = option.d->names[i];
01214 if (name.startsWith('!'))
01215 name = name.mid(1);
01216
01217 if (name.startsWith('+'))
01218 {
01219 if (!hasArgs)
01220 {
01221 s->printQ(i18n("\nArguments:\n"));
01222 hasArgs = true;
01223 }
01224
01225 name = name.mid(1);
01226 if (name.startsWith('[') && name.endsWith(']'))
01227 name = name.mid(1, name.length()-2);
01228 s->printQ(optionFormatString.arg(name, -25).arg(description));
01229 }
01230 else
01231 {
01232 if (!hasOptions)
01233 {
01234 s->printQ(optionsHeader);
01235 hasOptions = true;
01236 }
01237
01238 if ((name.length() == 1) || (name[1] == ' '))
01239 name = '-'+name;
01240 else
01241 name = "--"+name;
01242 if (descriptionFull.isEmpty())
01243 {
01244 opt = name + ", ";
01245 }
01246 else
01247 {
01248 opt = opt + name;
01249 if (option.d->defaults[i].isEmpty())
01250 {
01251 s->printQ(optionFormatString.arg(QString( opt ), -25).arg(description));
01252 }
01253 else
01254 {
01255 s->printQ(optionFormatStringDef.arg(QString( opt ), -25)
01256 .arg(description, option.d->defaults[i]));
01257 }
01258 opt = "";
01259 }
01260 }
01261 for(QStringList::Iterator it = dl.begin();
01262 it != dl.end();
01263 ++it)
01264 {
01265 s->printQ(optionFormatString.arg("", -25).arg(*it));
01266 }
01267 }
01268
01269 ++args;
01270 if (args == s->argsList->end() || !(*args)->d->name.isEmpty() || (*args)->d->id.isEmpty())
01271 break;
01272 }
01273 if (!showAll) break;
01274 }
01275
01276 exit(0);
01277 }
01278
01279
01280
01281
01282
01288 KCmdLineArgs::KCmdLineArgs( const KCmdLineOptions &_options,
01289 const KLocalizedString &_name,
01290 const QByteArray &_id)
01291 : d(new KCmdLineArgsPrivate(_options, _name, _id))
01292 {
01293 }
01294
01298 KCmdLineArgs::~KCmdLineArgs()
01299 {
01300 if (!s.isDestroyed() && s->argsList)
01301 s->argsList->removeAll(this);
01302 delete d;
01303 }
01304
01305 void
01306 KCmdLineArgs::setCwd( const QByteArray &cwd )
01307 {
01308 s->mCwd = QString::fromUtf8(cwd);
01309 }
01310
01311 void
01312 KCmdLineArgs::clear()
01313 {
01314 delete d->parsedArgList;
01315 d->parsedArgList = 0;
01316 delete d->parsedOptionList;
01317 d->parsedOptionList = 0;
01318 }
01319
01320 void
01321 KCmdLineArgs::reset()
01322 {
01323 if ( s->argsList ) {
01324 delete s->argsList;
01325 s->argsList = 0;
01326 }
01327 s->parsed = false;
01328 }
01329
01330 void
01331 KCmdLineArgsPrivate::save( QDataStream &ds) const
01332 {
01333 if (parsedOptionList)
01334 ds << (*(parsedOptionList));
01335 else
01336 ds << quint32(0);
01337
01338 if (parsedArgList)
01339 ds << (*(parsedArgList));
01340 else
01341 ds << quint32(0);
01342 }
01343
01344 void
01345 KCmdLineArgsPrivate::load( QDataStream &ds)
01346 {
01347 if (!parsedOptionList) parsedOptionList = new KCmdLineParsedOptions;
01348 if (!parsedArgList) parsedArgList = new KCmdLineParsedArgs;
01349
01350 ds >> (*(parsedOptionList));
01351 ds >> (*(parsedArgList));
01352
01353 if (parsedOptionList->count() == 0)
01354 {
01355 delete parsedOptionList;
01356 parsedOptionList = 0;
01357 }
01358 if (parsedArgList->count() == 0)
01359 {
01360 delete parsedArgList;
01361 parsedArgList = 0;
01362 }
01363 }
01364
01365 void
01366 KCmdLineArgsPrivate::setOption(const QString &opt, bool enabled)
01367 {
01368 if (isQt)
01369 {
01370
01371 QString argString = "-";
01372 if( !enabled )
01373 argString += "no";
01374 argString += opt;
01375 addArgument(argString);
01376 }
01377 if (!parsedOptionList) {
01378 parsedOptionList = new KCmdLineParsedOptions;
01379 }
01380
01381 if (enabled)
01382 parsedOptionList->insert( opt, QString::fromUtf8("t") );
01383 else
01384 parsedOptionList->insert( opt, QString::fromUtf8("f") );
01385 }
01386
01387 void
01388 KCmdLineArgsPrivate::setOption(const QString &opt, const QString &value)
01389 {
01390 if (isQt)
01391 {
01392
01393 QString argString = "-";
01394 argString += opt;
01395 addArgument(argString);
01396 addArgument(value);
01397
01398 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01399
01400 if (argString == "-display")
01401 {
01402 setenv(DISPLAY, s->encodeOutput(value).data(), true);
01403 }
01404 #endif
01405 }
01406 if (!parsedOptionList) {
01407 parsedOptionList = new KCmdLineParsedOptions;
01408 }
01409
01410 parsedOptionList->insertMulti( opt, value );
01411 }
01412
01413 QString
01414 KCmdLineArgs::getOption(const QByteArray &_opt) const
01415 {
01416 QString opt = QString::fromUtf8(_opt);
01417 QString value;
01418 if (d->parsedOptionList)
01419 {
01420 value = d->parsedOptionList->value(opt);
01421 }
01422 if (!value.isEmpty())
01423 return value;
01424
01425
01426 QString opt_name;
01427 QString def;
01428 bool dummy = true;
01429 int result = s->findOption( d->options, opt, opt_name, def, dummy) & ~4;
01430
01431 if (result != 3)
01432 {
01433 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01434 fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
01435 s->encodeOutput(opt).data(), s->encodeOutput(opt).data());
01436 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01437
01438 Q_ASSERT( 0 );
01439 exit(255);
01440 }
01441 return def;
01442 }
01443
01444 QStringList
01445 KCmdLineArgs::getOptionList(const QByteArray &_opt) const
01446 {
01447 QString opt = QString::fromUtf8(_opt);
01448
01449 QStringList result;
01450 if (!d->parsedOptionList)
01451 return result;
01452
01453 while(true)
01454 {
01455 QString value = d->parsedOptionList->take(opt);
01456 if (value.isEmpty())
01457 break;
01458 result.prepend(value);
01459 }
01460
01461
01462
01463
01464
01465
01466 for(QStringList::ConstIterator it=result.begin();
01467 it != result.end();
01468 ++it)
01469 {
01470 d->parsedOptionList->insertMulti(opt, *it);
01471 }
01472 return result;
01473 }
01474
01475 bool
01476 KCmdLineArgs::isSet(const QByteArray &_opt) const
01477 {
01478
01479 QString opt = QString::fromUtf8(_opt);
01480 QString opt_name;
01481 QString def;
01482 int result = 0;
01483 KCmdLineArgsList::Iterator args = s->argsList->begin();
01484 while (args != s->argsList->end())
01485 {
01486 bool dummy = true;
01487 result = s->findOption((*args)->d->options, opt, opt_name, def, dummy) & ~4;
01488 if (result) break;
01489 ++args;
01490 }
01491
01492 if (result == 0)
01493 {
01494 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
01495 fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
01496 s->encodeOutput(opt).data(), s->encodeOutput(opt).data());
01497 fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
01498
01499 Q_ASSERT( 0 );
01500 exit(255);
01501 }
01502
01503 QString value;
01504 if (d->parsedOptionList)
01505 {
01506 value = d->parsedOptionList->value(opt);
01507 }
01508
01509 if (!value.isEmpty())
01510 {
01511 if (result == 3)
01512 return true;
01513 else
01514 return (value[0] == 't');
01515 }
01516
01517 if (result == 3)
01518 return false;
01519
01520
01521
01522 return (result == 2);
01523 }
01524
01525 int
01526 KCmdLineArgs::count() const
01527 {
01528 if (!d->parsedArgList)
01529 return 0;
01530 return d->parsedArgList->count();
01531 }
01532
01533 QString
01534 KCmdLineArgs::arg(int n) const
01535 {
01536 if (!d->parsedArgList || (n >= (int) d->parsedArgList->count()))
01537 {
01538 fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
01539 fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
01540 n);
01541
01542 Q_ASSERT( 0 );
01543 exit(255);
01544 }
01545
01546 return d->parsedArgList->at(n);
01547 }
01548
01549 KUrl
01550 KCmdLineArgs::url(int n) const
01551 {
01552 return makeURL( arg(n).toUtf8() );
01553 }
01554
01555 KUrl KCmdLineArgs::makeURL(const QByteArray &_urlArg)
01556 {
01557 const QString urlArg = QString::fromUtf8(_urlArg);
01558 QFileInfo fileInfo(urlArg);
01559 if (!fileInfo.isRelative()) {
01560 KUrl result;
01561 result.setPath(urlArg);
01562 return result;
01563 }
01564
01565 if ( KUrl::isRelativeUrl(urlArg) || fileInfo.exists() ) {
01566 KUrl result;
01567 result.setPath( cwd()+'/'+urlArg );
01568 result.cleanPath();
01569 return result;
01570 }
01571
01572 return KUrl(urlArg);
01573 }
01574
01575 void
01576 KCmdLineArgsPrivate::addArgument(const QString &argument)
01577 {
01578 if (!parsedArgList)
01579 parsedArgList = new KCmdLineParsedArgs;
01580
01581 parsedArgList->append(argument);
01582 }
01583
01584 void
01585 KCmdLineArgs::addTempFileOption()
01586 {
01587 KCmdLineOptions tmpopt;
01588 tmpopt.add( "tempfile", ki18n("The files/URLs opened by the application will be deleted after use") );
01589 KCmdLineArgs::addCmdLineOptions( tmpopt, ki18n("KDE-tempfile"), "kde-tempfile" );
01590 }
01591
01592 bool KCmdLineArgs::isTempFileSet()
01593 {
01594 KCmdLineArgs* args = KCmdLineArgs::parsedArgs( "kde-tempfile" );
01595 if ( args )
01596 return args->isSet( "tempfile" );
01597 return false;
01598 }