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